linux c 使用epoll模型进行管道通信,子linux进程间通信 管道在break之后,父linux进程间通信 管道epoll_wait没有阻塞,仍在循环,为什么呀

标签:至少1个,最多5个
Linux 下进程通信
在网络课程中,有讲到Socket编程,对于tcp讲解的环节,为了加深理解,自己写了Linux下进程Socket通信,在学习的过程中,又接触到了其它的几种方式。记录一下。
共享内存通信方式
共享内存的通信方式,系统根据我的偏好设置在内存中开辟一块空间,并对其进行相应的指定,然后我们的另一个进程可以按照同样的指定,也就是其标记,对其进行访问。创建共享内存,得到共享内存后,想内存中写入数据,然后另个进程得到内存,然后从中读出数据。先贴出代码,写入方
#include &stdlib.h&
#include &sys/shm.h&
#include &sys/ipc.h&
#include &unistd.h&
#include &string.h&
#define PATH ""
#define SIZE 512
#define ID 0
int main()
char * shmA
char * dataAddr = "Hello";
int key = ftok(PATH,ID);
int shmID = shmget(key,SIZE,IPC_CREAT);
shmAddr = shmat(shmID,NULL,0);
strcpy(shmAddr,dataAddr);
shmdt(shmAddr);
#include &stdlib.h&
#include &stdio.h&
#include &unistd.h&
#include &string.h&
#include &sys/shm.h&
#include &sys/ipc.h&
#define PATH ""
#define SIZE 0
#define ID 0
int main()
char * shmA
char * dataAddr = "Hello";
int key = ftok(PATH,ID);
int shmID = shmget(key,SIZE,0);
shmAddr = shmat(shmID,NULL,0);
printf("%s\n",shmAddr);
shmdt(shmAddr);
shmctl(shmID, IPC_RMID, NULL);
代码比较简单,不难看出,通过函数shmget(),我们得到了对一块共享内存的标记,然后通过shmdt(),然后和我们的进程绑定得到这块共享内存的地址,然后即可输出该块内存区域中的数据。主要涉及几个参数,ftok(),shmget(),shmat()。
ftok():接受两个参数一个是文件目录,一个是我们的projectid,对于第二个id,我们这里可以随便制定,此处指定0,该函数可以为当前IPC生成一个唯一的键值。shemget():第一个参数是我们进程的键值,第二个参数是我们指定内存区域的大小,如果制定为0则代表我们只是打开,而不是去创建,第三个参数是制定我们对该内存区域的操作模式权限。shmat:该参数的作用是将我们的共享内存映射到我们的当前进程的内存空间。得到了其地址。第一个参数是我们要映射的共享内存的标示符。第二个参数是制定将共享内存的映射到我们进程空间的起始地址,如果制定为null,则会由系统自动分配一个。第三个参数是指定我们的操作模式,是读还是写,此处指定为0,表示既可以对其读又可以对其写。shmdt:这个函数是用来断开当前进程和该共享内存区域的连接,shmctl:该函数通过对于一些参数的指定来对共享内存区域进行一系列的控制,对于共享内存区域,设有一个计时器,当到达一定时间之后,如果没有进程和其绑定,该内存将会被回收。也可以不用手动对其回收。
下面运行下这两个程序当我们再次运行client2后因为我们的连个进程都已经和该共享内存区域解绑,而且也执行了移除,如果我们不对其移除。则会
管道通信(匿名,有名)
管道通信,在一个进程之中,只能单一的对其写或者是读,而不可以及执行写操作又执行读操作。这一点,我们可以将其想象成我们的水管,分别连着不同的两端,在有水流的时候,一端只能进行输入,另一端只能进行输出,而不可以同时输入和输出。
管道又分为有名管道和匿名管道,两者的区别在于对于匿名管道,其只能在具有亲缘关系的父子进程之间进行消息通信。管道的通信是借助于在我们的磁盘上生成一个文件,然后对文件的读写来实现我们的通信,而且数据被读之后,在文件中将会被删除掉。
匿名管道的实现较为简单,实现代码:
#include &stdio.h&
#include &stdlib.h&
#include &unistd.h&
#define BUFFER_SIZE 9
int main()
int fd[2];
char buf[BUFFER_SIZE];
if(pipe(fd)==-1)
printf("error in create pipe\n");
if((pid=fork())&0)
printf("error in fork a sub process\n");
close(fd[0]);
write(fd[1],"Welcome!",10);
close(fd[1]);
read(fd[0],buf,9);
printf("%s,son\n",buf);
1.创建管道2.通过fork函数分叉出子进程3.写数据4.读数据5.关闭管道读端和写端。这里也除了管道函数,还要特别说一下的是fork函数。
fork函数返回的数据在父进程中是子进程pid,而对子进程返回的是0,这并不是说,子进程的pid就是零,还有一个函数是getpid(),执行这个函数后,在子进程和父进程中得到的都是该进程pid,而不是fork函数的返回值。fork函数执行的时候,是将父进程中全部的数据置入自己进程之中,和父进程中的数据不是同步的了。
通过pipe函数我们创建了一个管道,管道接收的参数是一个长度为2的一维数组,此时,此时在0位返回的是读端口,1位返回的是写端口,当我们要对数据进行写入的时候,我们需要关闭其读端口,如果对其进行读操作,我们要关闭写端口。类似于读文件的操作,制定数据和大小,然后通过read和write函数对其进行读写。
后来又发现的一些问题是对于读写端口的问题,当我们在写的时候,读端口开着对其并没有影响,其目的是以防万一,写入数据被自身读取走了。还有此处实现方式是通过建立一个管道文件,然后采用了常规的文件读写方式进行的读写,还会出现的一些是,当我们read完一次之后,如果下面接着再read,将会出现一个问题,我们还能够从中读出数据来,原因是管道文件本身具有一个自身管理的,来负责对于管道文件的擦除,而其擦除速度较慢于我们从中读出的速度,所以导致了这个问题。
通过对于匿名管道的分析,再到有名管道,为什么有名管道可以被非亲缘进程找到利用?因为它有名呀,对的,如果在家中,父亲要和儿子谈话,只需说出来就好了,因为信道上的接听者只有父亲和儿子,所以即使不指儿子的名字和儿子说,儿子也是知道是在和他讲,但是如果要和别人讲话,而且由很多人同时在侦听信道的时候,如果我们不指定名字,他们就不会知道我们是在跟谁讲话。所以对于有名管道,我们首先要对其指定一个名字,然后指定作为写端或者是读端,然后对其进行操作。
#include &unistd.h&
#include &stdlib.h&
#include &fcntl.h&
#include &limits.h&
#include &sys/types.h&
#include &sys/stat.h&
#include &stdio.h&
#include &string.h&
#define FIFO_NAME "/oswork/pipe/myfifo"
int main()
char buffer[] = "Hello world";
if(access(FIFO_NAME,F_OK)==-1)
res = mkfifo(FIFO_NAME,O_WRONLY);
if(res!=0)
printf("Error in creating fifo.\n");
pipe_id = open(FIFO_NAME,O_WRONLY);
if(pipe_id!= -1)
if(write(pipe_id,buffer,PIPE_BUF)&0){
close(pipe_id);
printf("Error in writing.\n");
printf("Error in opening.\n");
因为管道是通过本地磁盘上的文件进行信息的交换,因此我们需要给予其本地磁盘上的一个文件目录,然后根据该目录通过access()函数来获取该管道,如果获取失败,那么我们就按照给定的目录创建一个,创建管道的时候,我们需要制定是对其进行读还是写,创建好之后,通过指定模式打开我们的管道,此时会得到一个管道号,然后根据获得管道标志号,作为参数,进行read和write操作。下面是读端的执行代码。
#include &unistd.h&
#include &stdlib.h&
#include &fcntl.h&
#include &limits.h&
#include &sys/types.h&
#include &sys/stat.h&
#include &stdio.h&
#include &string.h&
#define FIFONAME "/oswork/pipe/myfifo"
int main()
char buffer[PIPE_BUF+1];
pipe_id = open(FIFONAME,O_RDONLY);
if(pipe_id != -1)
read(pipe_id,buffer,PIPE_BUF);
printf("%s",buffer);
printf("error in reading\n");
执行结果,在这里的读和写都是设置为堵塞执行方式,就是如果没读端,这个时候,写端就是处于堵塞状态这个时候再执行读端写端堵塞解除
Socket通信
Socket通信,不仅仅是一台主机上的两个进程可以进行通信,还可以让处在因特网中的两个进程进行通信。在两个进程进行通信的时候,首先本地的进程在运行的时候会绑定一个端口,然后我们本地为该进程生成一个缓冲区,返回一个值,即为socket作为对其进行标记,每当本地进程和远程一个进程建立连接的时候,就会根据远程进程的信息和本地进程的信息生成一个socket,然后双方借助于socket就可以进行通信,运输层得到的数据写入socket标志的缓冲区,然后在里面进行相应的操作之后将其提交给网络层。相比其它的几种处理方式,该中方式比较麻烦。多于服务端,通过listen阻塞监听,监听到有连接请求,通过accept函数得到一个本地与之对应的缓冲区,然后创建一个进程用来和该连接进行交互,然后通过receive来接收信息,由于c语言大一学过去之后,基本没怎么再看过,所以写来的时候还是遇到了几个小坑。这里实现的是当连接建立后,服务端给本地端发送一个连接建立提示,然后客户端可以向服务端发送消息,服务端给予一个I don't know的回复。
服务端代码
#include &sys/type.h&
#include &sys/socket.h&
#include &stdio.h&
#include &netinet/in.h&
#include &arpa/inet.h&
#include &unistd.h&
#include &string.h&
#include &stdlib.h&
#include &fcntl.h&
#include &sys/shm.h&
#define PORT 9000
#define KEY 123
#define SIZE 1024
int main()
char buf[100];
memset(buf,0,100);
int server_sockfd,client_
socklen_t server_len,client_
sockaddr_in server_sockaddr,client_
/*create a socket.type is AF_INET,sock_stream*/
server_sockfd = socket(AF_INET,SOCK_STREAM,0);
/*the address of the sockt which is a struct include sinfamily,sin_port and sin_addr(struct)
htons is a convert function,*/
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*the length of the sever_sockt address*/
server_len = sizeof(server_sockaddr);
first option is socket we create,the second option is level the left is
the paraments'length and value
setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
/*bind a socket or rename a sockt*/
if(bind(server_sockfd,(struct sockaddr*)&server_sockaddr,server_len)==-1){
printf("bind error");
/*listen the socket,the second option is 5 which is the limit number of kernal handle*/
if(listen(server_sockfd,5)==-1){
printf("listen error");
client_len = sizeof(client_sockaddr);
/*define a pid number*/
pid_t ppid,
if(client_sockfd=accept(server_sockfd,(struct sockaddr*)&client_sockaddr,&client_len)==-1){
printf("connect error");
//send and receiv all include a socket , content and the len.
send(client_sockfd,"You have conected the server",strlen("You have connected the server"),0);
ppid = fork();
if(ppid == -1) {
printf("fork 1 failed:");
/*the subthread is used to receiver the message from client Create a process again when
we create father process success*/
else if(ppid == 0){
pid = fork();
if(pid == -1){
printf("fork 2 failed:");
else if(pid == 0) {
//set the 100 byte of the buf to 0
bzero(buf,100);
if((recvbytes = recv(client_sockfd,buf,100,0))==-1) {
perror("read client_sockfd failed:");
//if the subProcess receive the message successfully
else if(recvbytes != 0){
buf[recvbytes] = '\0';
usleep(1000);
printf("%s:%d said:%s\n",inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port), buf);
//send same message to the client.
if(send(client_sockfd,buf,recvbytes,0)==-1){
perror("send error");
//when send the msg successfuly end up the method
else if(pid&0) {
} else if(ppid&0){ //总父进程中关闭client_sockfd(因为有另一个副本在子进程中运行了)返回等待接收消息
close(client_sockfd);
其中涉及到创建进程与结束进程等还是比较复杂的。下面通过一个流程图说明其工作原理对于其中的一些函数,有自己的英文注释,想锻炼下英文表达能力,但是表达在语法和意思上还是有些错误的。客户端工作代码
#include &stdio.h&
#include &stdlib.h&
#include &errno.h&
#include &string.h&
#include &sys/types.h&
#include &netinet/in.h&
#include &sys/socket.h&
#include &sys/wait.h&
#include &unistd.h&
#include &arpa/inet.h&
#define SERVER_PORT 9000
/* the port of the sever which will connected*/
#define MAXDATASIZE 100 /* the maxmum bytes every send*/
#define SERVER_IP "114.215.100.147"
/* the ip address of the server*/
/*First we need to create a socket and then initialize the socket,then we invoke the connect,it will build a connection between client
and server we designate*/
int main() {
int sockfd,
char buf[MAXDATASIZE];
struct sockaddr_in server_
printf("\n======================client initialization======================\n");
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero));
if (connect(sockfd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1){
perror("connect error");
//waitting for receive msg from the server,the receiver method is a block method,when the server break up
//the connection ,is will close the socket.
while(1) {
bzero(buf,MAXDATASIZE);
printf("\nBegin receive...\n");
if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1){
perror("recv");
else if (numbytes & 0){
int len, bytes_
buf[numbytes] = '\0';
printf("Received: %s\n",buf);
printf("Send:");
char msgb[100];
scanf("%s",msg);
len = strlen(msg);
//sent to the server
if(send(sockfd,msg,len,0) == -1){
perror("send error");
printf("soket end!\n");
close(sockfd);
相比于服务器端,客户端的代码比较简单了,发起连接请求--&连接成功进入轮询--&接受消息————&发送消息。执行结果
消息队列通信
消息队列和有名管道有些类似的地方,最大相同点在于它可以用于在不同的进程之间进行通信,但是管道有一个劣势是,对于接收端其对与管道内的数据只能是接受,而不可以对其进行过滤选择,同时在写和读的时候还会出现堵塞.对于消息队列其在接收的时候也是会发生堵塞的,解除阻塞,只有当其接收到合适的消息或者该队列被删除了,这个阻塞才会解除。对于消息队列的通信流程是创建消息-》获得队列--》向队列中发送消息--》从队列中取出消息。
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
#include &errno.h&
#include &unistd.h&
#include &sys/types.h&
#include &sys/ipc.h&
#include &sys/stat.h&
#include &sys/msg.h&
#define MSG_FILE "/oswork/message/sender.c"
#define BUFFER 255
#define PERM S_IRUSR|S_IWUSR
//message struct
struct msgbuf
char mtext[BUFFER+1];
int main()
char *myask="I'm receiver, 3 messages received from you.";
//create a key for
if((key=ftok(MSG_FILE,66))==-1)
fprintf(stderr,"Creat Key Error:%s \n",strerror(errno));
exit(EXIT_FAILURE);
//get a message queue
if((msgid=msgget(key,PERM|IPC_CREAT))==-1)
fprintf(stderr,"Creat MessageQueue Error:%s \n",strerror(errno));
exit(EXIT_FAILURE);
//get a message from the queue everytime
for(i=0; i&3; i++)
msgrcv(msgid,&msg,sizeof(struct msgbuf),1,0);
printf("Receiver receive: %s\n",msg.mtext);
msg.mtype=2;
//send the message that I have received the message.
strncpy(msg.mtext,myask,BUFFER);
msgsnd(msgid,&msg,sizeof(struct msgbuf),0);
the code of sender
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
#include &sys/types.h&
#include &sys/ipc.h&
#include &sys/msg.h&
#include &sys.stat.h&
#define MSG_FILE "/oswork/message/sender.c"
#define BUFFER_SIZE 255
#define PERM S_IRUSR|S_IWUSR
struct msgbuf
char mtext[BUFFER_SIZE+1];
//create three messages
char *message[3]={"I'm sender,there are some message for you.","Message1",
"Message2"};
int main()
if((key=ftok(MSG_FILE,66))==-1)
printf("error in creating key\n");
if((msgid=msgget(key,PERM|IPC_CREAT))==-1)
printf("error in creating get message\n");
//set the type of the message
msg.mtype=1;
//send the message
for(i=0; i&3; i++)
strncpy(msg.mtext,message[i],BUFFER_SIZE);
msgsnd(msgid,&msg,sizeof(struct msgbuf),2,0);
memset(&msg,'\0',sizeof(struct msgbuf));
/*receive the message,the third arguments show the type of message will be received
msgrcv(msgid,&msg,sizeof(struct msgbuf),2,0);
printf("%s\n",msg.mtext);
//delete the message queue.
if(msgctl(msgid,IPC_RMID,0)==-1)
printf("error in deleting msg queue\n");
对于消息通信,其中的几个函数,这里在说明一下,msgrcv和msgsnd两个函数,对于其中的参数,第一个指定的是我们的消息队列的标示符,然后第二个是消息区域,然后是我们的消息长度,然后是消息类型,最后一个是用来指定是否堵塞。消息队列中的消息只要是被读出的,就会自动的被从队列中剔除掉。
上述为Linux下进程间通信的四种方式,实际开发中,我们传输数据类型和进程间的关系选择合适的方式。
前段时间在牛客网上将《剑指offer》书中算法题用Java实现了一遍,放在了Github上,欢迎一起交流,提升。
7 收藏&&|&&82
你可能感兴趣的文章
30 收藏,1.7k
3 收藏,612
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
百度脑图 哈哈
感觉还是蛮好用的,看书的时候喜欢通过脑图梳理下思路,列个框架
socket代码一堆错误呀,怎么就贴上来了。
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
我要该,理由是:高并发服务器中如何高效使用epoll?_突袭网-提供留学,移民,理财,培训,美容,整形,高考,外汇,印刷,健康,建材等信息
高并发服务器中如何高效使用epoll?
来源:互联网 时间: 15:12:20
&&为了解决用户可能碰到关于"高并发服务器中如何高效使用epoll?"相关的问题,突袭网经过收集整理为用户提供相关的解决办法,请注意,解决办法仅供参考,不代表本网同意其意见,如有任何问题请与本网联系。"高并发服务器中如何高效使用epoll?"相关的详细问题如下:
&&RT。小弟最近研究epoll模型,网上例子都是很简单的那种,服务器中没啥用处。我想了一种方案,但是有很多疑问。
&&创建监听socket后,开启一个专门的accept线程处理client的连接。创建一个线程调用epoll_wait等待事件通知,对于新建立的连接,向epoll加入ET和EPOLLIN,wait接收到IN通知后,创建一个对应的事件,加入队列中,作为生产者,创建N个线程作为队列的消费者,消费者线程完成数据的recv,并提交给逻辑层处理。
&&&&1.如何发送数据?我想的是直接send,如果失败且错误代码EAGIN,则向epoll加入EPOLLOUT事件,之后交由消费线程处理。如果send很频繁,怎么保证消费线程按照正确顺序发送数据?向epoll加入OUT事件,如果有空间发送,wait函数是否总是一直返回该事件?还是只返回一次?
===突袭网收集的解决方案如下===用户提供的回答1:
既然是专门accept的线程,就不必用epoll来accept了,循环里阻塞着accept就对了。
保证什么顺序?每个tcp连接你都可以搞个自己的buffer,只往buffer里写就不会乱了。
返回一次还是多次,看你注册的是ET还是LT,ET是一次,LT是多次。
用户提供的回答2:
引用&1&楼&pcboyxhy&的回复:既然是专门accept的线程,就不必用epoll来accept了,循环里阻塞着accept就对了。
保证什么顺序?每个tcp连接你都可以搞个自己的buffer,只往buffer里写就不会乱了。
返回一次还是多次,看你注册的是ET还是LT,ET是一次,LT是多次。
比如说wait到socketA的IN事件,把这个事件交给工作线程A,工作线程A调用recv接收数据,然后写入buffer,但与此同时wait又收到该socketA的IN事件,这时就会有另一个工作线程B调用recv然后写入buffer,怎么保证线程B和线程A的顺序呢?
用户提供的回答3:
引用&2&楼&zgxyz2010&的回复:Quote: 引用&1&楼&pcboyxhy&的回复:
既然是专门accept的线程,就不必用epoll来accept了,循环里阻塞着accept就对了。
保证什么顺序?每个tcp连接你都可以搞个自己的buffer,只往buffer里写就不会乱了。
返回一次还是多次,看你注册的是ET还是LT,ET是一次,LT是多次。
比如说wait到socketA的IN事件,把这个事件交给工作线程A,工作线程A调用recv接收数据,然后写入buffer,但与此同时wait又收到该socketA的IN事件,这时就会有另一个工作线程B调用recv然后写入buffer,怎么保证线程B和线程A的顺序呢?
这要看你的应用层协议是否允许顺序不一致,如果应用层在request-reply中含有请求ID的,顺序不一致也没关系。
如果应用层不允许这种乱序,此时有2种办法,1是client在收到上一个请求的完整应答之前不发送新的请求。
另一种办法是在服务端做控制,在每个client的连接中维护一个request序列的信息,和reply序列,发送reply的时候去做顺序的控制。有点儿类似http1.1的pipelining,但是http2取消了这种顺序要求,提高了性能。
用户提供的回答4:
引用&3&楼&pcboyxhy&的回复:Quote: 引用&2&楼&zgxyz2010&的回复:
Quote: 引用&1&楼&pcboyxhy&的回复:
既然是专门accept的线程,就不必用epoll来accept了,循环里阻塞着accept就对了。
保证什么顺序?每个tcp连接你都可以搞个自己的buffer,只往buffer里写就不会乱了。
返回一次还是多次,看你注册的是ET还是LT,ET是一次,LT是多次。
比如说wait到socketA的IN事件,把这个事件交给工作线程A,工作线程A调用recv接收数据,然后写入buffer,但与此同时wait又收到该socketA的IN事件,这时就会有另一个工作线程B调用recv然后写入buffer,怎么保证线程B和线程A的顺序呢?
这要看你的应用层协议是否允许顺序不一致,如果应用层在request-reply中含有请求ID的,顺序不一致也没关系。
如果应用层不允许这种乱序,此时有2种办法,1是client在收到上一个请求的完整应答之前不发送新的请求。
另一种办法是在服务端做控制,在每个client的连接中维护一个request序列的信息,和reply序列,发送reply的时候去做顺序的控制。有点儿类似http1.1的pipelining,但是http2取消了这种顺序要求,提高了性能。
大概明白了,可使用ONESHORT模式,保证同一socket同时只有一个recv事件,但是感觉效率有点低。
我还有一个地方不明白,我的程序设计如下:1个专门发送线程,不断取数据来send(假设一直有数据需要发送),如果发送缓冲区满,就注册一个OUT事件,那缓冲区空时,就可能会有2个线程在该socket上发送数据,1个是发送线程,2是wait响应OUT的线程。怎么解决这个冲突呢?
用户提供的回答5:
引用&4&楼&zgxyz2010&的回复:Quote: 引用&3&楼&pcboyxhy&的回复:
Quote: 引用&2&楼&zgxyz2010&的回复:
Quote: 引用&1&楼&pcboyxhy&的回复:
既然是专门accept的线程,就不必用epoll来accept了,循环里阻塞着accept就对了。
保证什么顺序?每个tcp连接你都可以搞个自己的buffer,只往buffer里写就不会乱了。
返回一次还是多次,看你注册的是ET还是LT,ET是一次,LT是多次。
比如说wait到socketA的IN事件,把这个事件交给工作线程A,工作线程A调用recv接收数据,然后写入buffer,但与此同时wait又收到该socketA的IN事件,这时就会有另一个工作线程B调用recv然后写入buffer,怎么保证线程B和线程A的顺序呢?
这要看你的应用层协议是否允许顺序不一致,如果应用层在request-reply中含有请求ID的,顺序不一致也没关系。
如果应用层不允许这种乱序,此时有2种办法,1是client在收到上一个请求的完整应答之前不发送新的请求。
另一种办法是在服务端做控制,在每个client的连接中维护一个request序列的信息,和reply序列,发送reply的时候去做顺序的控制。有点儿类似http1.1的pipelining,但是http2取消了这种顺序要求,提高了性能。
大概明白了,可使用ONESHORT模式,保证同一socket同时只有一个recv事件,但是感觉效率有点低。
我还有一个地方不明白,我的程序设计如下:1个专门发送线程,不断取数据来send(假设一直有数据需要发送),如果发送缓冲区满,就注册一个OUT事件,那缓冲区空时,就可能会有2个线程在该socket上发送数据,1个是发送线程,2是wait响应OUT的线程。怎么解决这个冲突呢?
应该避免两个线程发送同一个socket的数据,多个线程可以提交数据到发送队列,但是不能自己发送
答:使用起来很清晰,首先要调用epoll_create建立一个epoll对象。参数size是内核保证能够正确处理的最大句柄数,多于这个最大数时内核可不保证效果。epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll...答:udp还是tcp,如果是tcp需要你把服务器当成客户端主动连接客户端的指定端口,listen后才能send。要么你就手动使用raw socket直接从最上层到最底层直接构造tcp回应包发送,不用bind listen都可以。答:服务程序最为关键的设计是并发服务模型,当前有以下几种典型的模型: - 单进程服务,使用非阻塞IO 使用一个进程服务多个客户,通常与客户通信的套接字设置为非阻塞的,阻塞只发生在select()、poll()、epoll_wait()等系统调用上面。这是一种行之...答:基本的IO编程过程(包括网络IO和文件IO)是,打开文件描述符(windows是handler,Java是stream或channel),多路捕获(Multiplexe,即select和poll和epoll)IO可读写的状态,而后可以读写的文件描述符进行IO读写,由于IO设备速度和CPU内存比速度...答:并发量与其他配置也息息相关,况且4G的内存已经很低端了。建议你可以去服务器厂商(正睿)的网上直接咨询一下(最好当成购买用户,你懂的),几分钟就清楚了!答:多核服务器和多个epoll没什么关系,多核能力还是留给CPU计算型任务吧,至于网络IO,一个epoll实例轻松处理10K以上并发连接。只遇到过后续处理数据的瓶颈,没遇过epoll接入和收发数据的瓶颈。答:各有各的好处吧,今天来讲讲关于非阻塞的异步IO。说到异步IO,其实现在很难实现真正的异步,大部分情况下仍然需要阻塞在某个多路复用函数,比如select 或者 epoll 上,得到就绪描述符,然后调用注册在相应描述符上的回调函数。这种方式是现在的...答:当一个节点和多个节点建立连接时,如何高效的处理多个连接的数据,下面具体分析两者的区别。 1. select函数 函数原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 参数介绍:(1)...答:参考下面的 nginx 配置高并发 一、一般来说nginx 配置文件中对优化比较有作用的为以下几项: 1. worker_processes 8; nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。 2. worker_cpu_affinity 0001...答:#include #include /* basic system data types */#include /* basic socket definitions */#include /* sockaddr_in{} and other Internet defns */#include /* inet(3) functions */#include /* epoll function */#include /* nonblocking */#...
你可能还关注
淘宝折扣专区}

我要回帖

更多关于 子进程epoll wait 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信