4.6 accept Function
accept is called by a TCP server to return the next completed connection from the front of the completed connection queue (Figure 4.7). If the completed connection queue is empty, the process is put to sleep (assuming the default of a blocking socket).
#include <sys/socket.h> |
int accept (int sockfd , struct sockaddr *cliaddr , socklen_t *addrlen ); |
Returns: non-negative descriptor if OK, -1 on error |
Example: Value-Result Arguments
We will now show how to handle the value-result argument to accept by modifying the code from Figure 1.9 to print the IP address and port of the client. We show this in Figure 4.11.
Figure 4.11 Daytime server that prints client IP address and port
intro/daytimetcpsrv1.c
1 #include "unp.h" 2
2 #include <time.h>
3 int
4 main(int argc, char **argv)
5 {
6 int listenfd, connfd;
7 socklen_t len;
8 struct sockaddr_in servaddr, cliaddr;
9 char buff[MAXLINE];
10 time_t ticks;
11 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
12 bzero(&servaddr, sizeof(servaddr));
13 servaddr.sin_family = AF_INET;
14 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
15 servaddr.sin_port = htons(13); /* daytime server */
16 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
17 Listen(listenfd, LISTENQ);
18 for ( ; ; ) {
19 len = sizeof(cliaddr);
20 connfd = Accept(listenfd, (SA *) &cliaddr, &len);
21 printf("connection from %s, port %d\n",
22 Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)),
23 ntohs(cliaddr.sin_port));
24 ticks = time(NULL);
25 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
26 Write(connfd, buff, strlen(buff));
27 Close(connfd);
28 }
29 }
New declarations
78 We define two new variables: len, which will be a value-result variable, and cliaddr, which will contain the client's protocol address.
Accept connection and print client's address
1923 We initialize len to the size of the socket address structure and pass a pointer to the cliaddr structure and a pointer to len as the second and third arguments to accept. We call inet_ntop (Section 3.7) to convert the 32-bit IP address in the socket address structure to a dotted-decimal ASCII string and call ntohs (Section 3.4) to convert the 16-bit port number from network byte order to host byte order.
Calling sock_ntop instead of inet_ntop would make our server more protocol-independent, but this server is already dependent on IPv4. We will show a protocol-independent version of this server in Figure 11.13.
If we run our new server and then run our client on the same host, connecting to our server twice in a row, we have the following output from the client:
solaris % daytimetcpcli 127.0.0.1
Thu Sep 11 12:44:00 2003
solaris % daytimetcpcli 192.168.1.20
Thu Sep 11 12:44:09 2003
We first specify the server's IP address as the loopback address (127.0.0.1) and then as its own IP address (192.168.1.20). Here is the corresponding server output:
solaris # daytimetcpsrv1
connection from 127.0.0.1, port 43388
connection from 192.168.1.20, port 43389
Notice what happens with the client's IP address. Since our daytime client (Figure 1.5) does not call bind, we said in Section 4.4 that the kernel chooses the source IP address based on the outgoing interface that is used. In the first case, the kernel sets the source IP address to the loopback address; in the second case, it sets the address to the IP address of the Ethernet interface. We can also see in this example that the ephemeral port chosen by the Solaris kernel is 43388, and then 43389 (recall Figure 2.10).As a final point, our shell prompt for the server script changes to the pound sign (#), the commonly used prompt for the superuser. Our server must run with superuser privileges to bind the reserved port of 13. If we do not have superuser privileges, the call to bind will fail:
solaris % daytimetcpsrv1
bind error: Permission denied