linux epoll系列2 利用epoll_wait查看是否可以送信
write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变成了阻塞了,这个进程或者线程就堵住了,不能被响应了。
epoll_wait函数可以判断出,缓存区是否可写,可写后再调用write函数,这样就避免了write函数被阻塞。
例子1,是接收端。
例子2, 是会发生阻塞的发送端。
例子3,利用了epoll_wait,所以是不会发生阻塞的。
例子1,接收端
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
int main(){
int sock0;
sockaddr_in addr;
sockaddr_in client;
socklen_t len;
int sock;
int n;
char buf[65536];
int i;
sock0 = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sock0, (sockaddr*)&addr, sizeof(addr));
listen(sock0, 5);
len = sizeof(client);
sock = accept(sock0, (sockaddr*)&client, &len);
printf("after accept
");
for(i = 0; i < 10; ++i){
sleep(2);
n = read(sock, buf, sizeof(buf));
printf("recv data size:[%d] bytes
", n);
}
printf("close socket and finish
");
close(sock);
return 0;
}
例子2, 是会发生阻塞的发送端。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
int main(){
sockaddr_in server;
int sock;
char buf[65536];
int n;
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr);
n = connect(sock, (sockaddr*)&server, sizeof(server));
if(n != 0){
perror("connect");
return 1;
}
int cnt = 0;
while(1){
++cnt;
printf("[%d]write %ld bytes
", cnt, sizeof(buf));
n = write(sock, buf, sizeof(buf));
if(n <= 0){
printf("write error:%d
", n);
break;
}
}
close(sock);
return 0;
}
例子3,利用了epoll_wait,所以是不会发生阻塞的。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#define EVENTS 12
int main(){
sockaddr_in server;
epoll_event ev, ev_ret[EVENTS];
int sock, epfd;
char buf[65536];
int nfds;
int n;
sock = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr);
n = connect(sock, (sockaddr*)&server, sizeof(server));
if(n != 0){
perror("connect");
return 1;
}
epfd = epoll_create(2);
if(epfd < 0){
perror("epfd");
return 1;
}
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLOUT;//可写
ev.data.fd = sock;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev) != 0){
perror("epoll_clt");
return 1;
}
int cnt = 0;
while(1){
cnt++;
printf("before epoll wait
");
nfds = epoll_wait(epfd, ev_ret, EVENTS, -1);
if(nfds < 0){
perror("epoll_wait");
return 1;
}
printf("after epoll_wait
");
if(ev_ret[0].data.fd == sock){
printf("[%d]write %ld types
", cnt, sizeof(buf));
n = write(sock, buf, sizeof(buf));
if(n <= 0){
printf("write error:%d
", n);
break;
}
}
}
close(sock);
return 0;
}
运行方法:先运行接收端,再运行阻塞发送端。
从运行结果可以看出:阻塞的发送端,缓存区溢出后,write函数变成阻塞的了。
运行方法:先运行接收端,再运行非阻塞发送端。