Linux网络编程之socket使用fork并发处理多个client的请求和对等通信P2PWord下载.docx
- 文档编号:19356800
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:9
- 大小:78.85KB
Linux网络编程之socket使用fork并发处理多个client的请求和对等通信P2PWord下载.docx
《Linux网络编程之socket使用fork并发处理多个client的请求和对等通信P2PWord下载.docx》由会员分享,可在线阅读,更多相关《Linux网络编程之socket使用fork并发处理多个client的请求和对等通信P2PWord下载.docx(9页珍藏版)》请在冰豆网上搜索。
signal(SIGCHLD,SIG_IGN);
intlistenfd;
//被动套接字(文件描述符),即只可以accept,
监听套接字
if((listenfd=socket(PF_INET,SOCK_STREAM,
IPPROTO_TCP))<
0)
//listenfd=socket(AF_INET,SOCK_STREAM,0)
ERR_EXIT("
socketerror"
);
structsockaddr_inservaddr;
memset(&
servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(5188);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
/*servaddr.sin_addr.s_addr=inet_addr("
127.0.0.1"
*//*inet_aton("
&
servaddr.sin_addr);
*/inton=1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,
&
on,sizeof(on))<
setsockopterror"
if(bind(listenfd,(structsockaddr*)&
servaddr,
sizeof(servaddr))<
binderror"
if(listen(listenfd,SOMAXCONN)<
0)//listen应在socket
和bind之后,而在accept之前
listenerror"
structsockaddr_inpeeraddr;
//传出参数
socklen_tpeerlen=sizeof(peeraddr);
//传入传出参数,必
须有初始值
intconn;
//已连接套接字(变为主动套接字,即可以主动
connect)
pid_tpid;
while
(1)
if((conn=accept(listenfd,(structsockaddr
*)&
peeraddr,&
peerlen))<
0)//3次握手完成的序列
accepterror"
printf("
recvconnectip=%sport=%d\n"
inet_ntoa(peeraddr.sin_addr),
ntohs(peeraddr.sin_port));
pid=fork();
if(pid==-1)
forkerror"
if(pid==0)
//子进程
close(listenfd);
do_service(conn);
exit(EXIT_SUCCESS);
else
close(conn);
//父进程
return0;
voiddo_service(intconn)
charrecvbuf[1024];
memset(recvbuf,0,sizeof(recvbuf));
intret=read(conn,recvbuf,sizeof(recvbuf));
if(ret==0)//客户端关闭了
clientclose\n"
break;
elseif(ret==-1)
readerror"
fputs(recvbuf,stdout);
write(conn,recvbuf,ret);
}客户端程序:
#include#include#include#include#include#include#include#include
intsock;
if((sock=socket(PF_INET,SOCK_STREAM,
servaddr.sin_addr.s_addr=inet_addr("
/*inet_aton("
*/if(connect(sock,(structsockaddr*)&
connecterror"
charsendbuf[1024]={0};
charrecvbuf[1024]={0};
while(fgets(sendbuf,sizeof(sendbuf),stdin)!
=NULL)
write(sock,sendbuf,strlen(sendbuf));
read(sock,recvbuf,sizeof(recvbuf));
memset(sendbuf,0,sizeof(sendbuf));
close(sock);
述程序利用了一点,就是父子进程共享打开的文件描述符,因为在子进程已经用不到监听描述符,故将其关闭,而连接描述符对父进程也没价值,将其关闭。
当某个客户端关
闭,贝yread返回0,退出循环,子进程顺便exit,但如果没
有设置对SIGCHLD信号的忽略,则因为父进程还没退出,故子进程会变成僵尸进程。
现在先运行server,再打开另外两个终端,运行client,可以
看到server输出如下:
同时在另外一个终端PS一下:
发现共
由上面的分析可知对应服务的子进程也会退出,而因为我们设置了父进程对SIGCHLD信号进行忽略,故不会产生僵尸进程,输出如下:
如果把主函数的第一行去掉,上述的情景输出可能为:
如果不想忽略SIGCHLD信号,则必须在信号处理函数中调用wait处理,但这里需要注意的是wait只能等待第一个退出的子进程,所以这里需要使用
waitpid。
若当前只有一个子进程退出,则waitpid一次之后因为其他子进程状态尚未改变,故返回0退出循环;
若几个连接同时断开,信号因为不能排队
号,
而只接收到一个SIGCHLD信号,waitpid多次之后已经不存在子进程了,返回-1退出循环。
如下所示:
signal(SIGCHLD,handler);
voidhandler(intsig)
*/
/*wait(NULL);
//只能等待第一个退出的子进程
while(waitpid(-1,NULL,WNOHANG)>
}2.P2P通信
如果我们想实现对等通信,即P2P,可以在服务器程序用使
用两个进程,一个进程接收用户的输入并发送给客户端,另返回0时得知客户端已经关闭需要退出进程,此时尚有另个进程未退出,可以通过在退出前发送消息给它,在消息处理函数中退出。
当然客户端也必须使用双进程,原理与服务器程序相同。
服务端程序:
#include#include#include#include#include
#include#include#include#include
#includevoidhandler(intsig)
recvasig=%d\n"
sig);
//被动套接字(文件描述符),即只可以accept
if((listenfd=socket(AF_INET,SOCK_STREAM,0))<
inton=1;
if((conn=accept(listenfd,(structsockaddr*)&
peeraddr,
if(pid==0)//此子进程用于接收终端输入并且发送给客
户端
signal(SIGUSR1,handler);
=
NULL)
write(conn,sendbuf,strlen(sendbuf));
else//此进程用于接收客户端信息
if(ret==-1)
elseif(ret==0)
peerclose\n"
kill(pid,SIGUSR1);
//父进程退出时发送信号给子进exit(EXIT_SUCCESS);
}客户端:
#include#include#include#include#include#include#include#include#include
#defineERR_EXIT(m)do{perror(m);
exit(EXIT_FAILURE);
}while(0)intmain(void)
if((sock=socket(AF_INET,SOCK_STREAM,0))<
servaddr,0,sizeof(servaddr));
if(connect(sock,(structsockaddr*)&
servaddr,sizeof(servaddr))<
if(pid==-1)
if(pid==0)//此子进程用于发送数据
while(fgets(sendbuf,sizeof(sendbuf),stdin)!
write(sock,sendbuf,strlen(sendbuf));
memset(sendbuf,0,sizeof(sendbuf));
else//此进程用于接收数据
while
(1)
intret=read(sock,recvbuf,sizeof(recvbuf));
if(ret==-1)
fputs(recvbuf,stdout);
memset(recvbuf,0,sizeof(recvbuf));
}这里是使用父子进程来完成对等通信,即双方都可以发送
信息给对方,也可以接收对方的信息,
号给父进程,可以使用getppid函数得到父进程的id。
客户端接入服务器端:
服务器端与客户端进行双向通信:
客户端断开:
注意,ctrl+c
会将前台进程组中的两个进程都终止掉,即父子进程都打开了conn,只有两个进程都close(conn),将file的引用计数减
为0,才会真正关
打印peerclose,并发信号给另一个进程,在信号处理函数中退出。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 网络 编程 socket 使用 fork 并发 处理 client 请求 对等 通信 P2P
链接地址:https://www.bdocx.com/doc/19356800.html