网络编程之Elementary TCP Sockets(二)

1. fork and exec Functions

笔者在APUE中比较详细的记录过fork函数,这里相关细节不在赘述,只看看和网络编程相关的概念:

  • The parent calls accept and then calls fork. The connected socket is then shared between the parent and child. Normally, the child then reads and writes the connected socket and the parent closes the connected socket.
  • A process makes a copy of itself so that one copy can handle one operation
    while the other copy does another task. This is typical for network servers.

2. getsockname and getpeername Functions

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
Both return: 0 if OK,1 on error

具体这两个函数的作用,简单来说就是为了找到由系统决定bind函数中绑定的地址和端口:

  • After connect successfully returns in a TCP client that does not call bind, getsockname returns the local IP address and local port number assigned to the connection by the kernel.
  • After calling bind with a port number of 0 (telling the kernel to choose the local
    port number), getsockname returns the local port number that was assigned.
  • getsockname can be called to obtain the address family of a socket
  • In a TCP server that binds the wildcard IP address, once a connection is established with a client (accept returns successfully), the server can call getsockname to obtain the local IP address assigned to the connection. The socket descriptor argument in this call must be that of the connected socket, and not the listening socket.
  • When a server is execed by the process that calls accept, the only way the server can obtain the identity of the client is to call getpeername. This is what happens whenever inetd forks and execs a TCP server. inetd calls accept (top left box) and two values are returned: the connected socket descriptor, connfd, is the return value of the function, and the small box we label ‘‘peer ’s address’’ (an Internet socket address structure) contains the IP address and port number of the client. fork is called and a child of inetd is created. Since the child starts with a copy of the parent’s memory image, the socket address structure is available to the child, as is the connected socket descriptor (since the descriptors are shared between the parent and child). But when the child execs the real server (say the Telnet server that we show), the memory image of the child is replaced with the new program file for the Telnet server (i.e., the socket address structure containing the peer’s address is lost), and the connected socket descriptor remains open across the exec. One of the first function calls performed by the Telnet server is getpeername to obtain the IP address and port number of the client.

第三点配上下图就比较清楚,也就是fork-exec会用新的程序替代老程序从而丢失了原本accept返回的地址信息,但是因为文件描述符依然被新进程继承,所以可以通过getpeername找回client的相关地址信息。
这里写图片描述

3. Concurrent Servers

一句话概括:The simplest way to write a concurrent server under Unix is to fork a child process to handle each client.其代码模板如下:

pid_t pid;
int listenfd, connfd;
listenfd = Socket( ... );
/* fill in sockaddr_in{} with server’s well-known port */
Bind(listenfd, ... );
Listen(listenfd, LISTENQ);
for ( ; ; ) {
		connfd = Accept(listenfd, ... ); /* probably blocks */
		if ( (pid = Fork()) == 0) {
		Close(listenfd); /* child closes listening socket */
		doit(connfd); /* process the request */
		Close(connfd); /* done with this client */
		exit(0); /* child terminates */
}
Close(connfd); /* parent closes connected socket */
}

其实上面程序最好玩的地方就是close在父进程调用,这点也是上一篇强调的地方,因为一个socketfd,经过fork以后其引用数就变为2,父进程必须调用close关闭它,否则会造成socketfd在子进程调用close无法真正关闭的现象。以上程序执行的过程,看下图会有比较直观的感受:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值