1.多进程TCP服务器的代码框架
主要的步骤如下,需要注意的点:
(1)父进程仅仅用于监听,对应pid>0,需要关闭连接套接字conn_fd;
(2)子进程仅仅用于连接后的数据传输,对应pid=0,需要关闭监听套接字listen_fd;
(3)如果没有连接请求时,客户端accept函数一直处于阻塞状态,直到内核完成3次握手并返回连接结果。
//1.创建监听套接字listen_fd
listen_fd=socket();
//2.将监听套接字与服务器IP绑定
bind();
//3.设置同时监听客户端的数量
listen();
while(1){
//4.阻塞等待3次握手,建立TCP连接套接字connfd
conn_fd=accept();
//5.创建子进程,服务多个客户端
pid=fork();
if(pid<0){perror("fork");}
if(pid==0){close(listen_fd);process();}
if(pid>0){close(conn_fd);}
}
close(listen_fd);
2.accept与fork函数功能验证
验证方法如下:
(1)通过在accept函数上下添加printf调试打印,确认accept的阻塞状态;
(2)通过打印pid,确认当前处于父进程还子进程。
while (1)
{
pid_t pid = -1;
printf("accept() in\n");//accept调试打印
if ((newfd = accept (fd, (struct sockaddr *) &cin, &addrlen)) < 0) {
perror ("accept");
break;
}
printf("accept() out\n");//accept调试打印
/*创建一个子进程用于处理已建立连接的客户的交互数据*/
if ((pid = fork()) < 0) {
perror("fork");
break;
}
printf("pid=%d\n",getpid());//打印进程号
if (0 == pid) { //子进程中
close(fd);
char ipv4_addr[16];
if (!inet_ntop (AF_INET, (void *) &cin.sin_addr, ipv4_addr, sizeof (cin))) {
perror ("inet_ntop");
exit (1);
}
printf ("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(cin.sin_port));
cli_data_handle(&newfd);
return 0;
} else { //实际上此处 pid >0, 父进程中
close(newfd);
}
}
3.运行结果
下方2850是父进程,2852和2854均为子进程
(1)在无连接建立时,2850一直阻塞在accept那里,打印accept in;
(2)当有TCP连接建立后,里面打印accept out,此时还在父进程中,父进程在关闭conn_fd后,有回到accept那里阻塞;
(3)后面的pid=2852和后两行,是第一个子进程中的打印,负责TCP数据处理。
(1)启动服务程序
root@wang-virtual-machine:/home/wang/03-linux-net-work/0411-multi-tcp# ./Service
Server starting....OK!
accept() in
(2)使用nc 192.168.31.59 5001命令启动第一个客户端
accept() out
pid=2850
accept() in
pid=2852
Clinet(192.168.31.59:55802) is connected!
Child handling process: newfd =4
(3)使用nc 192.168.31.59 5001命令启动第二个客户端
accept() out
pid=2850
accept() in
pid=2854
Clinet(192.168.31.59:55804) is connected!
Child handling process: newfd =4
4.参考链接:
1.TCP网络编程中connect()、listen()和accept()三者之间的关系
3.Linux网络编程基础-04_TCP/IP网络编程-并发服务器