소켓

컴퓨터들 간의 통신을 가능하게 하는 엔드포인트
• 소켓을 사용하여 서버와 클라이언트 간에 데이터를 전송
• 스트림 소켓 (Stream Socket):
• 전송 제어 프로토콜(TCP)을 기반으로 하는 소켓
• 연결 지향적이며 신뢰성 있는 데이터 전송
• 웹 브라우징, 이메일 전송 등의 애플리케이션에서 주로 사용
• 데이터그램 소켓 (Datagram Socket):
• 사용자 데이터그램 프로토콜(UDP)을 기반으로 하는 소켓
• 비연결 지향적이며 신뢰성이 떨어지지만 속도가 빠름
• 데이터 전송 순서를 보장하지 음
• 음성 및 동영상 스트리밍, 온라인 게임 등의 애플리케이션에서 주로 사용

Sample Program – TCP Server server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
 struct sockaddr_in server, remote; // 구현하려는게 TCP 서버. remote : 상대방, 클라이언트한테 요청시, 클라이언트의 ip주소와 포트번호를 담을 구조체로 remote 변수 선언
 int request_sock, new_sock;// request_sock : 소켓을 생성하고 연결요청 기다림, 연결이 새로들어올 때마다 소켓을 새로 사용 new sock: 새로운 소켓에 대한 정보를 저장
 int bytesread, addrlen;
 int i;
 char buf[BUFSIZ];
 if (argc != 2) {
 (void) fprintf(stderr,"usage: %s port\n", argv[0]); // 포트넘버를 arg로 준다
 exit(1);
 }
 if ((request_sock = socket(AF_INET, SOCK_STREAM, // 소켓 디스크립터 for TCP
 IPPROTO_TCP)) < 0) { // requset : 3번의 값을 가짐, 음수가 리턴되면 에러
 perror("socket");
 exit(1);
 }
memset((void *) &server, 0, sizeof (server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons((u_short)atoi(argv[1])); // htons : 호스트 to 네트워크 숄트, 호스트에서의 16비트를 네트워크에서 사용하는 short타입으로 바꿔주겠다.
if (bind(request_sock, (struct sockaddr *)&server, sizeof (server)) < 0) {
 perror("bind"); // bind : Bind 소켓 and 주소 // 소켓에 대한 디스크립터 지정, 이 소켓과 어떤 어드레스를 연결시켜주겠다 
 exit(1);
 }
if (listen(request_sock, SOMAXCONN) < 0) {
 perror("listen");
 exit(1);
}
for (;;) {
 addrlen = sizeof(remote);
 new_sock = accept(request_sock, // 이 소켓에서 뭔가 오면 요청을 받아들이겠다. new sock으로 return. 하나의 연결요청이 들어오면 새로운 소켓을 만듦, 그리고 remote에 있는 주소의 정보가 넘겨짐,+길이
 (struct sockaddr *)&remote, &addrlen);
 if (new_sock < 0) {// 음수시 에러
 perror("accept");
 exit(1);
 }
 printf("connection from host %s, port %d, socket %d\n",
 inet_ntoa(remote.sin_addr), // 인터넷 주소를 네트워크 to a sinaddr에있는걸 스트링으로 바꿔서 저장
 ntohs(remote.sin_port), new_sock); // 포트넘버 : 네트워크 타입, host 16비트 int로 바꿔줌. 
클라이언트가 스트링을 보내주면 그걸 대문자로 바꿔서 return
for (;;) {
 bytesread = read(new_sock, buf, sizeof (buf) - 1) ; // read : 시스템콜, 연결된 소켓에서 read를 한다. 리드한 내용을 버퍼 에 담는다. 
 if (bytesread<=0) { // 다 읽으면 나가.
 close(new_sock);
 break;
 }
 buf[bytesread] = '\0';
 printf("%s: %d bytes from %d: %s\n", argv[0], bytesread, new_sock, buf); // 소켓으로부터 읽은 내용을 %s에 출력
 for(i = 0; i < bytesread; i++)
 buf[i] = toupper(buf[i]); //대문자
 if (write(new_sock, buf, bytesread) != bytesread) // 바꾼 내용을 write. return이 되는것이랑 내가 읽은것이랑 다르면 에러가 발생.
 perror("echo");
 }
 }
}

•gcc -o srv server.c
•클라이언트는 nc나 telnet 사용

소켓 관련 구조체

struct sockaddr
 {
 __SOCKADDR_COMMON (sa_); /* Common data: address family // COMMOM ==> u_short sa_family;
and length. */
 char sa_data[14]; /* Address data. */
 };
#include <netinet/in.h>
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};

소켓 관련 함수

•socket - create an endpoint for communication
 #include <sys/types.h> /* See NOTES */
 #include <sys/socket.h>
 int socket(int domain, int type, int protocol);
bind - bind a name to a socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
•listen - listen for connections on a socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
• accept, accept4 - accept a connection on a socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
- 어드레스 처리
•inet_aton, inet_addr, inet_network, inet_ntoa, inet_makeaddr,
inet_lnaof, inet_netof - Internet address manipulation routines
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
•inet_pton - convert IPv4 and IPv6 addresses from text to binary form
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
• htonl, htons, ntohl, ntohs - convert values between host and network byte order
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

TCP 클라이언트

헤더파일

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>


int main(int argc, char argv[])
{
struct hostent
hostp;
struct sockaddr_in server; // 서버의 주소를 담을 스트럭쳐
int sock; // 소켓 파일디스크립터 저장
char buf[BUFSIZ]; // 데이터를 보낼 버퍼
int bytesread; // 보내고자하는 데이터
if(argc != 3) {
(void) fprintf(stderr,"usage: %s host port\n", argv[0]);
exit(1);
}
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { // 소켓 만들기,
perror("socket");
exit(1);
}


if ((hostp = gethostbyname(argv[1])) == 0) { // Get Host IP Addr
fprintf(stderr,"%s: unknown host\n",argv[2]);
exit(1);
}
memset((void *) &server, 0, sizeof (server)); // 주소의 모든 바이트를 0으로 sizeof만큼 
server.sin_family = AF_INET;
memcpy((void *) &server.sin_addr, hostp->h_addr, hostp->h_length); // length만큼 복사
server.sin_port = htons((u_short)atoi(argv[2]));
if (connect(sock, (struct sockaddr *)&server, sizeof (server)) < 0) { // Connect to Server
(void) close(sock);
fprintf(stderr, "connect");
exit(1);
}
 for (;;) {
 /* data from keyboard */
 if (!fgets(buf, sizeof buf, stdin)) { // Input from Keyboard
 exit(0);
 }
 if (write(sock, buf, strlen(buf)) < 0) { // Write to SD.
Send the bytestream
to the server
 perror("write");
 exit(1);
 }
 bytesread = read(sock, buf, sizeof buf); // Read byte stream
from the server
 buf[bytesread] = '\0';
 printf("%s: got %d bytes: %s\n", argv[0], bytesread, buf);
 }
}

Client 테스트

•nc –l 10000
• 서버 대용
• Waiting for tcp port 10000
•gcc -o cli client.c

0개의 댓글