360 likes | 569 Views
TCP/IP 소켓 프로그래밍 - C 버전 중에서. Chapter 2 소켓 기본. 최병선 네트워크 실험실. 목차. Part I : 생성 (Creating) 과 해지 (Destroying). Part II : 주소 지정. Part III : TCP 클라이언트. Part IV : TCP 서버. Part I :. 생성 (Creating) 과 해지 (Destroying). socket() 함수.
E N D
TCP/IP 소켓 프로그래밍 - C 버전 중에서 Chapter 2 소켓 기본 최병선 네트워크 실험실
목차 Part I : 생성(Creating)과 해지(Destroying) Part II : 주소 지정 Part III : TCP 클라이언트 Part IV : TCP 서버
Part I : 생성(Creating)과 해지(Destroying)
socket() 함수 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()를 호출 • 더 이상 사용하지 않을 소켓 식별자를 반환하는 역할 • 성공시에 0을, 실패시에 -1을 반환한다. int close(int socket)
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 4bytes 8bytes 2bytes Family Port Internet Address Unused sockaddr_in sin_family sin_port sin_addr sin_zero <그림 2-1> 주소 구조체, p. 28
Part III : TCP 클라이언트
TCP 소켓 프로그래밍 절차 send() recv() <참고> TCP/IP 프로토콜, 미래컴, p. 775
Socket() Client Socket() Server bind() 연결요청 connect() Listen() accept() recv() send() 데이터 송수신 send() recv() 종료 close() TCP 소켓 프로그래밍 절차
TCP 클라이언트의 통신단계 • socket()을 사용하여 TCP 소켓 생성한다. • connect()을 사용하여 서버와 연결(connection)을 설정한다. • send()와 recv()를 사용하여 통신한다. • close()로 연결을 닫는다.
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 • DieWithError.c • 어플리케이션들은 표준 에러 함수로 DieWithError()를 사용 • 이 책의 모든 예제 어플리케이션과 같이 컴파일 및 링크 되어야 함 • HandleTCPClient.c • HandleTCPClient()는 주어진 소켓으로 데이터를 수신하고 같은 소켓으로 그 데이터를 되돌려 보냄 • recv()가 양수를 반환하는 한 반복 • recv()는 데이터를 수신하거나 또는 클라이언트가 연결을 닫을 때까지 블록된다. • 클라이언트가 연결을 정상적으로 닫은 경우, recv()는 0을 반환
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Assign a port to socket Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (1) server는 client의 연결을 받기 위한 준비를 한다.
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (2) /* 들어오는 연결을 위한 소켓을 생성 */ if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection 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");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (4) /* Mark the socket so it will listen for incoming connections */ if (listen(servSock, MAXPENDING) < 0) DieWithError("listen() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (5) for (;;) /* Run forever */ { clntLen = sizeof(echoClntAddr); if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen)) < 0) DieWithError("accept() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (6) 서버는 클라이언트로부터 연결을 기다리기 위해 블록되어 진다.
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (7) 클라이언트가 서버에 연결을 시도하려 한다.
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (8) /* Create a reliable, stream socket using TCP */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection 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");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection 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");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (11) /* Receive message from client */ if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed");
Client Create a TCP socket Establish connection Communicate Close the connection Server Create a TCP socket Bind socket to a port Set socket to listen Repeatedly: Accept new connection Communicate Close the connection TCP Client/Server 통신 (12) close(sock); close(clntSocket)
실행 결과 화면 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