套接字 – 在阻塞管道或套接字上是否可以使用select()非阻塞writ
情况是我有一个阻塞管道或套接字fd我想写()没有阻塞,所以我先做一个select(),但仍然不能保证write()不会阻塞.
这是我收集的数据.即使select()表示 这只是指定原子行为. Python(!) documentation指出:
在以下测试程序中,将BUF_BYTES设置为100000以阻止 不幸的是,阻塞套接字会发生同样的情况.呼叫 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <limits.h> #include <stdio.h> #include <sys/select.h> #include <unistd.h> #define BUF_BYTES PIPE_BUF char buf[BUF_BYTES]; int probe_with_select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds) { struct timeval timeout = {0,0}; int n_found = select(nfds,readfds,writefds,exceptfds,&timeout); if (n_found == -1) { perror("select"); } return n_found; } void check_if_readable(int fd) { fd_set fdset; FD_ZERO(&fdset); FD_SET(fd,&fdset); printf("select() for read on fd %d returned %dn",fd,probe_with_select(fd + 1,&fdset,0)); } void check_if_writable(int fd) { fd_set fdset; FD_ZERO(&fdset); FD_SET(fd,&fdset); int n_found = probe_with_select(fd + 1,0); printf("select() for write on fd %d returned %dn",n_found); /* if (n_found == 0) { */ /* printf("sleepingn"); */ /* sleep(2); */ /* int n_found = probe_with_select(fd + 1,0); */ /* printf("retried select() for write on fd %d returned %dn",*/ /* fd,n_found); */ /* } */ } void test_pipe(void) { int pipe_fds[2]; size_t written; int i; if (pipe(pipe_fds)) { perror("pipe failed"); _exit(1); } printf("read side pipe fd: %dn",pipe_fds[0]); printf("write side pipe fd: %dn",pipe_fds[1]); for (i = 0; ; i++) { printf("i = %dn",i); check_if_readable(pipe_fds[0]); check_if_writable(pipe_fds[1]); written = write(pipe_fds[1],buf,BUF_BYTES); if (written == -1) { perror("write"); _exit(-1); } printf("written %d bytesn",written); } } void serve() { int listenfd = 0,connfd = 0; struct sockaddr_in serv_addr; listenfd = socket(AF_INET,SOCK_STREAM,0); memset(&serv_addr,'0',sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(5000); bind(listenfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); listen(listenfd,10); connfd = accept(listenfd,(struct sockaddr*)NULL,NULL); sleep(10); } int connect_to_server() { int sockfd = 0,n = 0; struct sockaddr_in serv_addr; if((sockfd = socket(AF_INET,0)) < 0) { perror("socket"); exit(-1); } memset(&serv_addr,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(5000); if(inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr) <= 0) { perror("inet_pton"); exit(-1); } if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) { perror("connect"); exit(-1); } return sockfd; } void test_socket(void) { if (fork() == 0) { serve(); } else { int fd; int i; int written; sleep(1); fd = connect_to_server(); for (i = 0; ; i++) { printf("i = %dn",i); check_if_readable(fd); check_if_writable(fd); written = write(fd,BUF_BYTES); if (written == -1) { perror("write"); _exit(-1); } printf("written %d bytesn",written); } } } int main(void) { test_pipe(); /* test_socket(); */ } 解决方法
除非你希望每当select()表示fd已准备好写入时一次发送一个字节,否则实际上没有办法知道你能发送多少,即使理论上它也是可能的(至少在文档中),如果不是在现实世界中)选择说它已准备好写入,然后条件在select()和write()之间改变.
非阻塞发送是此处的解决方案,如果您从使用write()更改为send(),则无需将文件描述符更改为非阻塞模式即可以非阻塞形式发送一条消息.您需要更改的唯一方法是将MSG_DONTWAIT标志添加到发送调用,这将使发送非阻塞而不更改套接字的属性.在这种情况下,您甚至根本不需要使用select(),因为send()调用将在返回代码中为您提供所需的所有信息 – 如果返回的代码为-1且errno为EAGAIN或EWOULDBLOCK然后你知道你不能再发送了. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |