UNIX Network Programming Volume 1, Third Edition [Electronic resources] : The Sockets Networking API نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

UNIX Network Programming Volume 1, Third Edition [Electronic resources] : The Sockets Networking API - نسخه متنی

Addison Wesley

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










Chapter 15


15.1

unlink removes the pathname from the filesystem, and when the client calls connect at a later time, the connect will fail. The server's listening socket is not affected, but no clients will be able to connect after the unlink.

15.2

The client cannot connect to the server even if the pathname still exists, because for the connect to succeed, a Unix domain socket must be currently open and bound to that pathname (Section 15.4).

15.3

When the server prints the client's protocol address by calling sock_ntop, the output is "datagram from (no pathname bound)" because no pathname is bound to the client's socket by default.

One solution is to specifically check for a Unix domain socket in udp_client and udp_connect and bind a temporary pathname to the socket. This puts the protocol dependency in the library function where it belongs, not in our application.

15.4

Even though we force 1-byte writes by the server for its 26-byte reply, putting the sleep in the client guarantees that all 26 segments are received before read is called, causing read to return the entire reply. This is just to confirm (again) that TCP is a byte stream with no inherent record markers.

To use the Unix domain protocols, we start the client and server with the two command-line arguments /local (or /unix) and /tmp/daytime (or any other temporary pathname you wish to use). Nothing changes: 26 bytes are returned by read each time the client runs.

Since the server specifies the MSG_EOR flag for each send, each byte is considered a logical record and read returns 1 byte each time it is called. What is happening here is that Berkeley-derived implementations support the MSG_EOR flag by default. This is undocumented, however, and should not be used in production code. We use it here as an example of the difference between a byte stream and a record-oriented protocol. From an implementation perspective, each output operation goes into a memory buffer (mbuf) and the MSG_EOR flag is retained by the kernel with the mbuf as the mbuf goes from the sending socket to the receiving socket's receive buffer. When read is called, the MSG_EOR flag is still attached to each mbuf, so the generic kernel read routine (which supports the MSG_EOR flag since some protocols use the flag) returns each byte by itself. Had we used recvmsg instead of read, the MSG_EOR flag would be returned in the msg_flags member each time recvmsg returned 1 byte. This does not work with TCP because the sending TCP never looks at the MSG_EOR flag in the mbuf that it is sending, and even if it did, there is no way to pass this flag to the receiving TCP in the TCP header. (Thanks to Matt Thomas for pointing out this undocumented "feature.")

15.5

15.5 Figure E.13 shows an implementation of this program.

Figure E.13 Determine actual number of queued connections for different

backlog values.


debug/backlog.c


1 #include "unp.h"
2 #define PORT 9999
3 #define ADDR "127.0.0.1"
4 #define MAXBACKLOG 100
5 /* globals */
6 struct sockaddr_in serv;
7 pid_t pid; /* of child */
8 int pipefd[2];
9 #define pfd pipefd[1] /* parent's end */
10 #define cfd pipefd[0] /* child's end */
11 /* function prototypes */
12 void do_parent(void);
13 void do_child(void);
14 int
15 main(int argc, char **argv)
16 {
17 if (argc != 1)
18 err_quit("usage: backlog");
19 Socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd);
20 bzero(&serv, sizeof(serv));
21 serv.sin_family = AF_INET;
22 serv.sin_port = htons(PORT);
23 Inet_pton(AF_INET, ADDR, &serv.sin_addr);
24 if ( (pid = Fork()) == 0)
25 do_child();
26 else
27 do_parent();
28 exit(0);
29 }
30 void
31 parent_alrm(int signo)
32 {
33 return; /* just interrupt blocked connect() */
34 }
35 void
36 do_parent(void)
37 {
38 int backlog, j, k, junk, fd[MAXBACKLOG + 1];
39 Close(cfd);
40 Signal(SIGALRM, parent_alrm);
41 for (backlog = 0; backlog <= 14; backlog++) {
42 printf("backlog = %d: ", backlog);
43 Write(pfd, &backlog, sizeof(int)); /* tell child value */
44 Read(pfd, &junk, sizeof(int)); /* wait for child */
45 for (j = 1; j <= MAXBACKLOG; j++) {
46 fd[j] = Socket(AF_INET, SOCK_STREAM, 0);
47 alarm(2);
48 if (connect(fd[j], (SA *) &serv, sizeof(serv)) < 0) {
49 if (errno != EINTR)
50 err_sys("connect error, j = %d", j);
51 printf("timeout, %d connections completed\n", j - 1);
52 for (k = 1; k <= j; k++)
53 Close(fd[k]);
54 break; /* next value of backlog */
55 }
56 alarm(0);
57 }
58 if (j > MAXBACKLOG)
59 printf("%d connections?\n", MAXBACKLOG);
60 }
61 backlog = -1; /* tell child we're all done */
62 Write(pfd, &backlog, sizeof(int));
63 }
64 void
65 do_child(void)
66 {
67 int listenfd, backlog, junk;
68 const int on = 1;
69 Close(pfd);
70 Read(cfd, &backlog, sizeof(int)); /* wait for parent */
71 while (backlog >= 0) {
72 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
73 Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
74 Bind(listenfd, (SA *) &serv, sizeof(serv));
75 Listen(listenfd, backlog); /* start the listen */
76 Write(cfd, &junk, sizeof(int)); /* tell parent */
77 Read(cfd, &backlog, sizeof(int)); /* just wait for parent */
78 Close(listenfd); /* closes all queued connections, too */
79 }
80 }


/ 450