Tips on Network Programming Understand IPv4 Addressing Special address Host ID = 0: network address Network ID = 0, host ID = 0 127.x.y.z : “looped back” Host ID = all 1s : broadcasting NAT address 10/8 172.16/12 192.168/12 Broadcast address 255.255.255.255 IPv4 address는 host의 address 가 아니라 interface의 address이다. i.e 0.0.0.0 means this network 190.50.255.255 Limited broadcast router 밖에는 나가지 못함 Network-directed broadcast 그 네트워크까지 가서 네트워크 내에 broadcast 190.50.1.255/24 Subnet-directed broadcast 190.50.1.0/24 subnet 내에 broadcast Develop and Use Application “Skeletons” TCP Client, Server 프로그램의 skeleton은 비슷하다. UDP Client, Server 프로그램의 skeleton도 비슷하다. 다만, 서비스에 따라 내부 로직이 다를 뿐이니 skeleton에서 출발하자. Build Your Own Library and Use It ! UNP library를 이용하자. ETCP library도 써먹자. 필요하다면 porting해서 쓰자. 여러분 개인의 library를 만들어 나가자. Remember that TCP is a Stream Protocol No message boundary, just a byte stream TCP application에서 하나의 message를 send()했다고 해서 recevier application에서 그 message를 한 덩어리로 recv()되는 것이 아니다. Message를 send()했어도 TCP segment에 언제, 어떻게 실릴지 모른다. (buffering 되기 때문) Recv()하면 몇 byte 읽힐지 모른다. If you want to read exactly n bytes ?? If you want to make a record ??? Use end-of-record mark. e.g) new line Handle variable records (using fixed header) 메시지를 읽을 user buffer의 크기 즉, 최대로 읽을 수 있는 크기 #include <sys/socket.h> /* UNIX */ #include <winsock2.h> /* Windows */ int recv (SOCKET s, void *buf, size_t bufsize, int flags); int read (SOCKET s, void *buf, size_t bufsize); /* UNIX */ Returns: # of bytes read (>0), 0 if received FIN and no more data, -1 on failure int send (SOCKET s, const void *buf, size_t len, int flags); int write (SOCKET s, const void *buf, size_t len); /* UNIX */ Returns: # of bytes transferred on success, -1 on failure Socket send buffer에 저장할 메시지 길이 Don’t Underestimate the TCP Performance TCP는 충분히 Optimize 되어 있다. 통상적인 TCP segment 수신 루틴: 30 instructions (excluding checksum) ACK도 piggy-back 섯불리 UDP를 사용하지 말라. But, a single request-response로 끝나는 transaction에서는 TCP는 Connection set-up: RTT 소요 Connection release: 적어도 RTT 소요 Avoid Reinventing TCP Any reasonably robust UDP application must provide Error recovery: reTx a request if not received a response within RTO Sequencing: ensure that replies are matched correctly to requests Flow control: if server’s reply can consist of multiple datagrams, prohibit overflow of client’s recv buffer Cause to rewrite TCP TCP는 kernel에서 처리되기 때문에 application에서 reliable protocol을 구현하는 것보다 실제 빠르다. UDP를 사용이 권고되는 경우 must be used for broadcast or multicast applications can be used for simple request-reply applications desired level of error control must be added error detection must be needed Application level에서 real-time control이 필요한 경우 (예: multimedia streaming) should not be used for bulk data transfer TCP is a Reliable Protocol, Not Infallible Protocol 2 peer간에 connection이 유지되는 한 TCP는 ordered and uncorrupted delivery를 보장한다. Application은 통신이 불가능함을 모르고 데이터를 보낼 수 있고, 따라서 목적지에 delivery 되지 못하는 경우가 발생한다. TCP는 data를 보내봐야 실제 peer TCP와 통신 가능한지 확인 가능 (ACK를 받아 봐야) 또는, 2시간 이상 데이터 교환이 없을 경우에나 통신 불가능을 확인 할 수 있음 교환할 데이터가 없어도 주기적으로 교환해야 heart beat mechanism 구현 필요 Application은 send()/recv()가 error return 되었을 때야, 통신 불가능함을 알게 된다. failure 처리 통신 불가능한 경우 (실제 connection이 유지되지 않는 경우) Network outage (due to router or link failure) Peer app crashes Peer host crashes 1) Network Outage Inside TCP Segment 보낸 후 ACK 가 없으면, 12번 ReTx한다 (약 9분 걸림) 여전히 ACK를 받지 못하면, set socket pending error (ETIMEOUT) Inside IP/ICMP IP datagram을 forwarding할 수 없으면(router나 link 장애로 인해), ICMP host unreachable/network unreachable message를 source로 보낸다. 이 메시지를 Source IP가 받으면, set socket pending error (ENETUNREACH/EHOSTUNREACH) Socket Pending Error Send() returns on failure send buffer에 쓰는 것이 실패를 의미 실제 보낸 데이터가 peer에게 전달할 수 없음은 한참 뒤에나 알 수 있다. Kernel은 이와 같은 error가 발생하면, 해당되는 socket에 pending 시켜 놓는다 Socket API call이 이루어질 때, error return하면서 errno에 설정한다. 2) Peer App Crashes Peer app crashes(killed) 1. 2. When peer app crashes, Local app is 3. In recv(): return 0 FIN Call exit(), implicitly Call close() in exit() TCP: send FIN 통상적인 절차로 종료 In send(): normal return But, sent data is lost. Local connection을 강제 close. Error is pending. Send()/recv(): error return (ECONNRESET) Send()/recv(): rrror return (EPIPE) data RESET No connection ! Not delivered to peer app 3) Peer Host Crashes Local app Connection set-up Peer host crash Send(): normal return But sent data is lost Error is pending (ETIMEOUT) after retransmitting 12 times(9 min) or error is pending (EHOSTUNREACH or ENETUNREACH) by ICMP data No TCP there, so no TCP response No TCP/IP Protocol ! No Notification when Connectivity is lost 데이터를 보내 보지 않고서는 peer와 통신 가능 여부를 알 수 없다 통신 불가능함에도 불구하고 데이터를 보내면 lost됨 (송금했는데 못 받았으면 ???) 데이터 교환과 별도로 상대가 살아 있는지 주기적으로 check해 봐야 함 hearbeat mechanism 필요 C/S가 여러가지 msg type을 교환하는 경우 Heartbeat msg에 새로운 type을 할당 C/S가 byte stream으로 교환하는 경우 Hearbeat 과 data를 구분할 수 없음 Hearbeat에 대해 별도 TCP connection 설정하여 구분 Or, Hearbeat에 대해 OOB msg로 교환 (send/recv() 에서 flag를 OOB로 설정) Be Prepared for Rude Behavior from a Peer Check for client termination Check for valid input UNIX utility program 중 6 ~ 43 % 가 인위적으로 생성한 random input으로 시험했을 때 죽었음 Consider Letting inetd Launch Your Application dup2(sockfd, 0); dup2(sockfd, 1); dup2(sockfd, 2); close(sockfd); Exec후에 Peer를 알 수 있는 방법은? Open descriptor들은 fork시 copy되고 Exec 후에도 유지된다. Consider Using Two TCP Connections One-connection architecture Xout에서 send할 때 pending error는 xin에서 recv해야 알 수 있다 Xin mp xout 으로 알려 줘야 함 Two connection architecture 별도의 connection에 대해 socket pending error가 있는지 testing 가능 Using select() readability