TCP/IP 소켓 프로그래밍 - C 버전 중에서 Chapter 2 소켓 기본 최병선 네트워크 실험실
목차 Part I : 생성(Creating)과 해지(Destroying) Part II : 주소 지정 Part III : TCP 클라이언트 Part IV : TCP 서버
생성(Creating)과 해지(Destroying) Part I : 생성(Creating)과 해지(Destroying)
int socket(int protocolFamily, int type, int protocol) 첫번째 파라미터는 소켓의 프로토콜 패밀리를 결정 PF_INET은 인터넷 프로토콜 패밀리의 프로토콜을 사용하는 소켓을 명시 두번째 파라미터는 소켓의 형태를 지정 상수 SOCK_STREAM은 신뢰성 있는 데이터 스트림 전송을 위한 소켓을 나타냄 상수 SOCK_DGRAM은 단순 데이터 전송에 목적을 두는 소켓을 나타냄 세번째 파라미터는 소켓이 데이터전송을 위해 사용하는 프로토콜을 명시 TCP – 스트림 소켓을 위해, IPPROTO_TCP로 표시 UDP – 데이터그램 소켓을 위해, IPPROTO_UDP로 표시 socket()의 리턴값 socket()의 반환값은 하나의 정수 음이 아닌 값이면 성공, –1이면 실패를 의미 실패가 아닌 경우, 반환 값은 소켓 식별자(socket descriptor)라 부르는 핸들로서 다른 API 함수들에 전달되어 연산이 수행될 소켓을 지정하는 역할
close() 함수 어플리케이션이 소켓을 종료할때 close()를 호출 더 이상 사용하지 않을 소켓 식별자를 반환하는 역할 int close(int socket) 어플리케이션이 소켓을 종료할때 close()를 호출 더 이상 사용하지 않을 소켓 식별자를 반환하는 역할 성공시에 0을, 실패시에 -1을 반환한다.
Part II : 주소 지정
주소 구조체 소켓을 사용하는 어플리케이션들은 커널에 인터넷주소와 포트를 지정할 수 있는 방법이 필요 소켓 API는 소켓과 관련된 주소를 지정하기 위해 총괄적인 데이터 형태인 소켓 구조체(socket structure)를 정의 인터넷 주소 패밀리를 나타내는 상수 AF_INET을 사용 struct sockaddr { u_short sa_family; /* 주소 패밀리 (e.g AF_INET)*/ char sa_data[14]; /* 주소 */ }; 모양이 주소 패밀리에 따라 정해지는 비트들의 조합 이기종 방식을 다루기 위한 전형적인 기법 소켓주소는 32비트의 인터넷 주소와 16비트의 포트 번호로 나뉨
주소 구조체 구조체 socketaddr_in은 주소 패밀리에 추가하여 포트 번호와 인터넷 주소를 위한 필드를 가지고 있음 socketaddr_in은 socketaddr 구조체의 데이터를 인터넷 프로토콜에서 사용하기에 적합하도록 수정한 것임 구조체 socketaddr_in의 필드를 채운 후, socketaddr에 캐스트(cast)시켜 결과적으로 소켓 함수에 전달 소켓 함수는 sa_family 필드를 조사하여 주소의 나머지 부분이 어떻게 구성되었는지 알게됨 struct in_addr { u_long s_addr; /* 32비트의 IP 주소를 저장할 구조체 */ }; struct sockaddr_in { short sin_family; /* 주소 체계 */ u_short sin_port; /* 16비트 포트번호 */ struct in_addr sin_addr; /* 32비트 IP 주소 */ char sin_zero[8]; /* 16바이트 크기를 맞추기 위한 dummy */
주소 구조체 sa_family sa_data Family Blob(14 bytes) sockaddr 2bytes 2bytes Port Internet Address Unused sockaddr_in sin_family sin_port sin_addr sin_zero <그림 2-1> 주소 구조체, p. 28
Part III : TCP 클라이언트
<참고> TCP/IP 프로토콜, 미래컴, p. 775 send() recv() <참고> TCP/IP 프로토콜, 미래컴, p. 775
TCP 소켓 프로그래밍 절차 Client Server Socket() bind() connect() Listen() accept() send() recv() close() 데이터 송수신 종료 연결요청
TCP 클라이언트의 통신단계 socket()을 사용하여 TCP 소켓 생성한다. connect()을 사용하여 서버와 연결(connection)을 설정한다. send()와 recv()를 사용하여 통신한다. close()로 연결을 닫는다.
int send(int socket,const void *msg,unsigned int msgLength,int flags) TCP 클라이언트의 주요 소켓 함수들 TCP소켓은 이 소켓을 통해 데이터를 보내기 전에 반드시 다른 소켓과 연결되어 있어야 함 socket은 socket()에 의해 생성된 식별자이다. struct sockaddr * foreignAddress는 서버의 인터넷 주소 및 포트 번호를 포함하는 sockaddr_in을 가리키는 포인터 adderssLength는 주소구조체의 길이를 나타내며 고정적으로 sizeof(sockaddr_in)으로 주어진다. 메시지 전송함수들 send()와 recv()는 보내거나 받은 데이터의 바이트 수 또는 실패를 나타내는 -1을 반환 int connect(int socket , struct sockaddr * foreignAddress, unsigned int addressLength) int send(int socket,const void *msg,unsigned int msgLength,int flags) int recv(int socket,void *revbuffer,unsigned int bufferLength,int flags)
Part IV : TCP 서버
TCP 서버의 통신 단계 socket()을 사용하여 TCP socket을 생성한다. bind()로 소켓에 한 포트 번호를 부여한다. 시스템에 listen()을 이용 그 포트로 연결 요구를 허락하도록 알린다. 다음 과정을 반복한다 각 클라이언트 연결에 대해 새로운 소켓을 얻기 위해 accept()를 호출한다. send()와 recv()를 사용 새로운 소켓을 통해 클라이언트와 통신한다. close()을 사용하여 해당 클라이언트와의 연결을 닫는다.
TCP 서버의 주요 소켓 함수들 클라이언트가 서버에 접속 하기 위해서 서버의 소켓은 지정된 내부주소 및 포트를 가지고 있어야 하는데 이일을 하는 함수가 bind()이다. 첫번째 파라미터는 이전의 socket()호출에서 반환된 식별자 값이다. connect()에서와 마찬가지로 sockaddr 구조체가 선언된다. addressLength는 주소구조체의 길이로 sizeof(struct sockaddr_in)이 전달된다. 성공시 0, 실패시 –1을 반환 성공인 경우, 결과 식별자가 나타내는 소켓은 유일하게 주어진 인터넷 주소와 포트에 결합한다. int bind(int socket , struct sockaddr * localAddress , unsigned int addressLength)
TCP 서버의 주요 소켓 함수들 listen()은 주어진 소켓에 대해 내부 상태의 변경을 유발하여 들어오는 TCP 연결 요구들이 처리될수 있도록 큐에 저장하는 것을 가능하게 한다. accept()는 socket을 위한 큐에서 다음 연결을 하나 꺼낸다. 만약 큐가 비어 있다면 accept()는 연결요구가 도착할때 까지 블록 된다. 성공적인경우, accept는 해당 클라이언트와 연결된 새로운 소켓식별자를 반환한다. int listen(int socket,int queueLimit); int accept(int socket,struct sockaddr *clientAddress,unsigned int * addressLength)
TCPEchoServer.c의 처리 과정 listening 소켓을 설정하고 클라이언틀부터 들어오는 연결요구를 기다린다. 요구가 도착했을 때 바이트들을 수신하고 받은것 을 다시 보내는 작업을 클라이언트가 종료할때 까지 반복한다. 클라이언트 연결을 닫는다.
DieWithError.c와 HandleTCPClient.c 이 책의 모든 예제 어플리케이션과 같이 컴파일 및 링크 되어야 함 HandleTCPClient.c HandleTCPClient()는 주어진 소켓으로 데이터를 수신하고 같은 소켓으로 그 데이터를 되돌려 보냄 recv()가 양수를 반환하는 한 반복 recv()는 데이터를 수신하거나 또는 클라이언트가 연결을 닫을 때까지 블록된다. 클라이언트가 연결을 정상적으로 닫은 경우, recv()는 0을 반환
TCP Client/Server 통신 (1) server는 client의 연결을 받기 위한 준비를 한다. Server Create a TCP socket Assign a port to socket Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (2) /* 들어오는 연결을 위한 소켓을 생성 */ if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (3) echoServAddr.sin_family = AF_INET; /* 인터넷 주소 패밀리 */ echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);/* Any incoming interface */ echoServAddr.sin_port = htons(echoServPort); /* Local port */ if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("bind() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (4) /* Mark the socket so it will listen for incoming connections */ if (listen(servSock, MAXPENDING) < 0) DieWithError("listen() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (5) for (;;) /* Run forever */ { clntLen = sizeof(echoClntAddr); if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0) DieWithError("accept() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (6) 서버는 클라이언트로부터 연결을 기다리기 위해 블록되어 진다. Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (7) 클라이언트가 서버에 연결을 시도하려 한다. Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (8) /* Create a reliable, stream socket using TCP */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (9) echoServAddr.sin_family = AF_INET; /* Internet address family */ echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */ echoServAddr.sin_port = htons(echoServPort); /* Server port */ if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("connect() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book A new socket is created on the server that is connected to the client socket
TCP Client/Server 통신 (10) echoStringLen = strlen(echoString); /* Determine input length */ /* Send the string to the server */ if (send(sock, echoString, echoStringLen, 0) != echoStringLen) DieWithError("send() sent a different number of bytes than expected"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (11) /* Receive message from client */ if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed"); Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book
TCP Client/Server 통신 (12) close(sock); close(clntSocket) Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection Client Create a TCP socket Establish connection Communicate Close the connection Students should follow along with source code in the book Note that server closes connection socket, not listening socket
실행 결과 화면 Server Client
참고문헌 UNIX Network Programming, 교보문고 Linux Socket Programming by Example, Warren W. Gay, QUE '00 http://kldp.org/Translations/html/Socket_Programming-KLDP/Socket_Programming -KLDP.html
Q & A