用多进程方式实现一个TCP并发服务器,每当一个新的客户端连接时fork一个子进程去和它通信。(各种主流的web服务器都不是纯粹的多进程方式运行,比如apache在每个进程中都用多路复用方式,直到连接数多到超过select可监听的最大描述符数时也会利用新的进程去处理。)
//server.c
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <unistd.h>
#include<sys/wait.h>
int startup(int _port,const char* _ip)
{
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0){
perror("socket");
exit(1);
}
int opt=1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
socklen_t len=sizeof(local);
if(bind(sock,(struct sockaddr*)&local,len)<0){
perror("bind");
exit(2);
}
if(listen(sock,5)<0){
perror("listen");
exit(3);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc!=3){
printf("usage: %s [local_ip] [local_port]\n",argv[0]);
return 3;
}
int listen_sock=startup(atoi(argv[2]),argv[1]);
struct sockaddr_in remote;
socklen_t len=sizeof(remote);
while(1){
int sock=accept(listen_sock,(struct sockaddr*)&remote,&len);
if(sock<0){
perror("accept");
continue;
}
printf("get a client,ip:%s,port:%d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
pid_t id = fork();
if(id<0){
perror("fork");
close(sock);
}else if(id==0){//child
close(listen_sock);
char buf[1024];
while(1){
ssize_t _s=read(sock,buf,sizeof(buf)-1);
if(_s>0){
buf[_s]=0;
printf("client#:%s\n",buf);
}else{
printf("client is quit!\n");
break;
}
}
close(sock);
}else{//father
close(sock);
while(waitpid(-1,NULL,WNOHANG));
}
}
return 0;
}
client.c
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <unistd.h>
static void usage(const char* proc){
printf("usage: %s [ip] [port]\n",proc);
}
int main(int argc,char* argv[])
{
if(argc!=3){
usage(argv[0]);
return 3;
}
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0){
perror("socket");
return 1;
}
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[2]));
server.sin_addr.s_addr=inet_addr(argv[1]);
if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0){
perror("connect");
return 2;
}
char buf[1024];
while(1){
printf("send#");
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
buf[s-1]=0;
write(sock,buf,s);
}
close(sock);
return 0;
}
运行结果:
client1
client2
server服务
需要注意的一点是fork子进程以后需要对子进程关闭监听套接口,对父进程关闭连接套接口。
本文介绍了一个使用多进程实现的TCP并发服务器方案。当有新的客户端连接时,服务器通过fork子进程来处理通信,确保主线程继续监听新的连接请求。文章提供了完整的服务器端和服务端代码示例,并解释了为何在子进程中需要关闭监听套接字,在父进程中关闭连接套接字。
466

被折叠的 条评论
为什么被折叠?



