客户端代码还是之前的echo的代码,服务器现在更改为基于进程的支持并发的服务器代码。
1、首先服务器会运行很长时间,所以要包含一个SIGCHLD(当一个进程结束或终止时发送信号给父进程)处理程序,回收僵尸进程,这个信号处理程序必须准备回收多个僵尸子进程的资源。
2、七次父子进程必须关闭他们各自的connfd副本,这对父进程尤为重要,以避免内存泄漏。
3、因为套接字的文件表表项的引用计数,直到父子进程的connfd都关闭了,到客户端的连接才会终止。
客户端代码和之前一样,服务器代码如下:
#include "csapp.h"
void echo(int connfd);
//信号处理程序
void sigchld_handler(int sig)
{
while(waitpid(-1,0,WNOHANG)>0);
return ;
}
int main(int argc, char **argv)
{
int listenfd, connfd, port, clientlen;
struct sockaddr_in clientaddr;
struct hostent *hp;
char *haddrp;
if (argc != 2)
{
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(0);
}
port = atoi(argv[1]);
Signal(SIGCHLD,sigchld_handler);
listenfd = Open_listenfd(port);
while (1)
{
clientlen = sizeof(clientaddr);
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
/* determine the domain name and IP address of the client */
hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
haddrp = inet_ntoa(clientaddr.sin_addr);
printf("server connected to %s (%s)\n", hp->h_name, haddrp);
if(Fork()==0){
//子进程关闭监听描述符
Close(listenfd);
echo(connfd);
Close(connfd);
exit(0);
}
//父进程关闭已连接描述符
Close(connfd);
}
// exit(0);
}
4、运行结果
可以看到这时候的服务器可以支持多个客户端。