1 목포해양대해양컴퓨터공학과 2 장. TCP 소켓 네트워크프로그램설계
2 목포해양대해양컴퓨터공학과 목차 제 2장 TCP 소켓 1. IPv4 TCP 클라이언트 2. IPv4 TCP 서버 3. 소켓의생성과해지 4. 주소지정 5. 소켓에연결 6. 소켓을주소에바인딩하기 7. 클라이언트의연결요청처리 8. 데이터주고받기 9. IPv6의사용
3 목포해양대해양컴퓨터공학과 소켓통신과정 간략화한소켓통신과정 소켓생성 TCP or UDP 소켓에주소정보할당 IP address, Port number 소켓연결 클라이언트소켓과서버소켓연결 bind(), listen(), connect(), accept() 데이터전송 send(), recv()
4 목포해양대해양컴퓨터공학과 TCP/IP 소켓의생성 소켓생성 어떠한소켓을생성할것인가를명시 ( 프로토콜종류 ) int socket(int family, int type, int proto); TCP/IP 소켓의경우 Family Type Protocol TCP SOCK_STREAM IPPROTO_TCP PF_INET UDP SOCK_DGRAM IPPROTO_UDP Socket 식별자 UNIX 의파일식별자와동일 Windows 의경우, WinSock 에서사용하는소켓핸들 Windows 의경우, 파일핸들과같지않음 반환값 : 소켓식별자인양의정수, 에러의경우 -1
5 목포해양대해양컴퓨터공학과 TCP/IP 소켓식별자 유닉스 / 리눅스계열에서식별자공간 0 1 2 3 4 Descriptor Table Data structure for file 0 Data structure for file 1 Family: PF_INET Service: SOCK_STREAM Local IP: 111.22.3.4 Remote IP: 123.45.6.78 Local Port: 2249 Remote Port: 3726
6 목포해양대해양컴퓨터공학과 TCP/IP 소켓의주소지정 (1) struct sockaddr 사용 여러가지프로토콜을사용하기때문에 1) 프로토콜종류 2) 주소를지정해야함 TCP/IP 의경우는인터넷주소임을알리는 AF_INET, IP 주소, Port 번호가필요 IP : IPv4 주소형식과 IPv6 주소형식으로나뉨 Port : TCP/UDP 관계없이 0 ~ 65535 사이의값사용 well-known (port 0-1023) dynamic or private (port 1024-65535)
7 목포해양대해양컴퓨터공학과 TCP/IP 소켓의주소지정 (2) 범용 (Generic) 소켓주소구조체 struct sockaddr { unsigned short sa_family; /* Address family (e.g., AF_INET) */ char sa_data[14]; /* Protocol-specific address information */ }; IPv4 에사용되는소켓주소구조체 struct sockaddr_in { unsigned short sin_family; /* Internet protocol (AF_INET) */ unsigned short sin_port; /* Port (16-bits) */ struct in_addr sin_addr; /* Internet address (32-bits) */ char sin_zero[8]; /* Not used */ }; struct in_addr { unsigned long s_addr; /* Internet address (32-bits) */ };
8 목포해양대해양컴퓨터공학과 TCP/IP 소켓의주소지정 (3) IPv6 에사용되는소켓주소구조체 struct sockaddr_in6 { sa_family_t sin6_family; // Internet protocol(af_inet6) in_port_t sin6_port; // Address port(16bits) uint32_t sin6_flowinfo; // Flow information struct in6_addr sin6_addr; // IPv6 address(128bits) uint32_t sin6_scope_id; // Scope identifier }; struct in_addr{ uint32_t s_addr[16]; }; // Internet address(128bits) 모든종류의 sockaddr 을수용하기위한구조체 struct sockaddr_storage { sa_family_t };
9 목포해양대해양컴퓨터공학과 주소정보를소켓에할당 bind() 를사용하여주소정보를생성된소켓에할당 성공시 0, 실패시 -1 int bind( int sockfd, struct sockaddr *localaddr, int addrlen); int mysock,err; struct sockaddr_in myaddr; char* servip; /* ex)202.30.49.84 */ mysock = socket(pf_inet,sock_stream,0); myaddr.sin_family = AF_INET; myaddr.sin_port = htons( portnum ); myaddr.sin_addr.s_addr = inet_addr(servip); err=bind(mysock, (sockaddr *) &myaddr, sizeof(myaddr));
클라이언트 서버통신 클라이언트가먼저서버에게연결요청 서버의프로세스는미리소켓을열고대기하고있어야함 서버는특정포트를열고대기하여야하며클라이언트는이포트를알고있어야함 클라이언트는서버에연결 이때클라이언트는서버의 IP, Port 정보를응용프로그램에게명시하여접속가능 10
TCP 연결흐름도 연결요청 다음클라이언트로부터연결요청을기다림 11
서버의연결대기함수- listen() TCP와같은연결지향서버에사용 소켓의상태를대기상태로바꿈 int listen(int socket, int queuelimit); socket: 생성된소켓의식별자 queuelimit : 연결을수행중에다른연결이들어오면연결요청을 queue 에넣고보류, 이때사용하는 queue 의크기 12
서버의연결대기함수 - accept() int accept(int socket, struct sockaddr *clientaddress, int *addr_len); listen() 호출후, accept() 를수행하면 클라이언트의연결요청 (connect()) 에대해응답함 passive open 클라이언트와데이터송수신 (send/recv) 이가능한새로운소켓식별자를반환 13
클라이언트의연결함수 - Connect() int connect(int socket, struct sockaddr *foreignaddress, int addr_len); 클라이언트는 connect() 를호출하여연결의상태를 active open 으로만듬 foreignaddress 는서버의 IP, port 를담고있는주소구조체 14
Send(to), Recv(from) 연결이이루어진후에는 send/recv 를이용하여데이터의송수신이가능 int send(int socket, char *message, int msg_len, int flags); 주어진소켓을통하여 message 의송신이가능 int recv(int scoket, char *buffer, int buf_len, int flags); 주어진소켓을통해주어진 buffer 에데이터를수신 15
클라이언트와서버의통신 클라이언트 : 연결을초기화하는주체 Client: Bob Server: Jane Hi. I m Bob. Hi, Bob. I m Jane Nice to meet you, Jane. 서버 : 수동적으로연결을기다림 16
TCP 상의서버 / 클라이언트통신 (1) 서버는클라이언트의연결을받아들일준비를하고시작 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 17
TCP 상의서버 / 클라이언트통신 (2) /* Create socket for incoming connections */ if ((servsock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithSystemMessage("socket() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 18
TCP 상의서버 / 클라이언트통신 (3) echoservaddr.sin_family = AF_INET; /* Internet address family */ 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) DieWithSystemMessage("bind() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 19
TCP 상의서버 / 클라이언트통신 (4) /* Mark the socket so it will listen for incoming connections */ if (listen(servsock, MAXPENDING) < 0) DieWithSystemMessage("listen() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 20
TCP 상의서버 / 클라이언트통신 (5) for (;;) /* Run forever */ { clntlen = sizeof(echoclntaddr); if ((clntsock=accept(servsock, (struct sockaddr *)&echoclntaddr, &clntlen)) < 0) DieWithError("accept() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 21
TCP 상의서버 / 클라이언트통신 (6) 서버는이시점에서클라이언트의연결을처리하기위해서대기 클라이언트는서버에연결시도 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 22
TCP 상의서버 / 클라이언트통신 (7) /* Create a reliable, stream socket using TCP */ if ((sock = socket(pf_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithSystemMessage("socket() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 23
TCP 상의서버 / 클라이언트통신 (8) 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) DieWithSystemMessage ("connect() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 24
TCP 상의서버 / 클라이언트통신 (9) if ((clntsock=accept(servsock, (struct sockaddr *)&echoclntaddr, &clntlen)) < 0) DieWithError("accept() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 25
TCP 상의서버 / 클라이언트통신 (10) echostringlen = strlen(echostring); /* Determine input length */ /* Send the string to the server */ if (send(sock, echostring, echostringlen, 0)!= echostringlen) DieWithUserMessage ("send() sent a different number of bytes than expected"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 26
TCP 상의서버 / 클라이언트통신 (11) /* Receive message from client */ if ((recvmsgsize = recv(clntsocket, echobuffer, RCVBUFSIZE, 0)) < 0) DieWithSystemMessage("recv() failed"); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 27
TCP 상의서버 / 클라이언트통신 (12) close(sock); close(clntsocket); 서버 클라이언트 2. 연결설정 3. 데이터송수신 4. 연결종료 2. 소켓에포트할당 3. 소켓상태를대기 (listen) 로 변경 4. 다음을반복적으로수행 a. 새로운연결을받아들임 b. 데이터송수신 c. 연결을종료 28
TCP 데이터교환 클라이언트는사전에서버의주소정보 (IP, port) 를알아야함 서버는클라이언트가접속할포트만정하고있음 send() 와 recv() 간에는어떠한정해진룰이없음 Client send( Hello Bob ) Server recv() -> Hello recv() -> Bob recv() -> Hi Jane send( Hi ) send( Jane ) 29
연결종료 연결을종료하기위해서 close() 를사용 파일의 EOF 와유사 echo Client echo Server send(string) while (not received entire string) recv(buffer) print(buffer) recv(buffer) while(client has not closed connection) send(buffer) recv(buffer) close(socket) close(client socket) 30
Practical.h 31
TCPEchoClient4.c (1) 32
TCPEchoClient4.c (2) 33
TCPEchoClient4.c (3) 34
TCPEchoServer4.c (1) 35
TCPEchoServer4.c (2) 36
HandleTCPClient() in TCPServerUtility.c 37
Makefile 38
DieWithMessage.c 39
AddressUtility.c (1) 40
AddressUtility.c (2) 41
컴파일방법 리눅스환경 Native 리눅스 /VMware 리눅스 / Cygwin 환경 유닉스기반 (iris.mmu.ac.kr) $ gcc < 컴파일옵션 > -o < 실행파일 > < 소스파일들 > -lsocket lnsl 리눅스기반 (lily.mmu.ac.kr) $ gcc < 컴파일옵션 > -o < 실행파일 > < 소스파일들 > 주의 std=c99 로컴파일할때일부헤더파일 (netdb.h) 을제대로포함시키지못하는오류가확인되었습니다. -std=gnu99 로컴파일!!! 42