linux的进程池通讯,进程池模型_tech记录的技术博客_51CTO博客

进程池模型需要通过system V IPC机制或管道、信号、文件锁等进行同步。以下是进程池的一般模型。

6b8eb1ff662bf7a907a74299f5938e5c.png

Linux惊群现象:

惊群:惊群是指多个进程/线程在等待同一资源时,每当资源可用,所有的进程/线程都来竞争资源的现象。

accept、select、epoll实现进程池模型时的惊群现象:

1).Linux多进程accept系统调用的惊群问题(注意,这里没有使用select、epoll等事件机制),在linux 2.6版本之前的版本存在,在之后的版本中解决掉了。

2).使用select epoll等事件机制,在linux早期的版本中,惊群问题依然存在(epoll_create在fork之前)。 原因与之前单纯使用accept导致惊群,原因类似。Epoll的惊群问题,同样在之后的某个版本部分解决了。

3).Epoll_create在fork之后调用,不能避免惊群问题,Nginx使用互斥锁,解决epoll惊群问题。

进程池中的进程调用accept如果阻塞在同一个listen队列中,有可能产生惊群现象(取决于Linux版本):当一connect到达时,所有accept都会唤醒,但只有一个accept会返回正确结果,其他的都会返回错误码。

accept多进程实现:让一个进程bind一个网络地址(可能是AF_INET,AF_UNIX或者其他任何你想要的),然后fork这个进程自己:

int s = socket(...)

bind(s, ...)

listen(s, ...)

fork()

Fork自己几次之后,每个进程阻塞在accept()函数这里

for(;;) {

int client = accept(...);  //子进程阻塞在这了

if (client < 0) continue;

...

}

99278d47f13bcb176b8b64d3553f1ce0.png

在较老的unix系统中,当有连接到来时,accept()在每个阻塞在这的进程里被唤醒。但是,只有这些进程中的一个能够真正的accept这个连接,其他的进程accept将返回EAGAIN惊群造成结果是系统对用户进程/线程频繁的做无效的调度、上下文切换,系统系能大打折扣。

实现代码:

服务器端代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define BUFLEN 1024

#define PIDNUM 3

/*******************并发服务器模型之一:预先分配好了进程的个数**********************/

static void handle_fork(int sockfd){

int newfd;

struct sockaddr_in c_addr;

char buf[BUFLEN];

socklen_t len;

time_t now;

while(1){

len = sizeof(struct sockaddr);

if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){

perror("accept");

exit(errno);

}else

printf("\n*****************通信开始***************\n");

printf("正在与您通信的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));

/******处理客户端请求*******/

bzero(buf,BUFLEN);

len = recv(newfd,buf,BUFLEN,0);

if(len >0 && !strncmp(buf,"TIME",4)){

bzero(buf,BUFLEN);

/*获取系统当前时间*/

now = time(NULL);

/*ctime将系统时间转换为字符串,sprintf使转化后的字符串保存在buf*/

sprintf(buf,"%24s\r\n",ctime(&now));

//******发送系统时间*******/

send(newfd,buf,strlen(buf),0);

}

/*关闭通讯的套接字*/

close(newfd);

}

}

int main(int argc, char **argv)

{

int sockfd;

struct sockaddr_in s_addr;

unsigned int port, listnum;

pid_t pid[PIDNUM];

/*建立socket*/

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket");

exit(errno);

}else

printf("socket create success!\n");

/*设置服务器端口*/

if(argv[2])

port = atoi(argv[2]);

else

port = 4567;

/*设置侦听队列长度*/

if(argv[3])

listnum = atoi(argv[3]);

else

listnum = 3;

/*设置服务器ip*/

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(port);

if(argv[1])

s_addr.sin_addr.s_addr = inet_addr(argv[1]);

else

s_addr.sin_addr.s_addr = INADDR_ANY;

/*把地址和端口帮定到套接字上*/

if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){

perror("bind");

exit(errno);

}else

printf("bind success!\n");

/*侦听本地端口*/

if(listen(sockfd,listnum) == -1){

perror("listen");

exit(errno);

}else

printf("the server is listening!\n");

/*处理客户端的连接*/

int i = 0;

for(i = 0; i < PIDNUM; i++){

pid[i] = fork();

if(pid[i] == 0)

handle_fork(sockfd);

}

/*关闭服务器的套接字*/

close(sockfd);

return 0;

}

客户端代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define BUFLEN 1024

int main(int argc, char **argv)

{

int sockfd;

struct sockaddr_in s_addr;

socklen_t len;

unsigned int port;

char buf[BUFLEN];

/*建立socket*/

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket");

exit(errno);

}else

printf("socket create success!\n");

/*设置服务器端口*/

if(argv[2])

port = atoi(argv[2]);

else

port = 4567;

/*设置服务器ip*/

bzero(&s_addr, sizeof(s_addr));

s_addr.sin_family = AF_INET;

s_addr.sin_port = htons(port);

if (inet_aton(argv[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0) {

perror(argv[1]);

exit(errno);

}

/*开始连接服务器*/

if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1){

perror("connect");

exit(errno);

}else

printf("conncet success!\n");

/******缓冲区清零*******/

bzero(buf,BUFLEN);

strcpy(buf,"TIME");

/******发送消息*******/

send(sockfd,buf,strlen(buf),0);

/******缓冲区清零*******/

bzero(buf,BUFLEN);

/******接收消息*******/

len = recv(sockfd,buf,BUFLEN,0);

if(len > 0)

printf("服务器的系统时间是:%s\n",buf);

close(sockfd); /*关闭连接*/

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值