Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 是select()+;在阻塞管道或套接字上是否可以使用非阻塞写入()?_Sockets_Unix_Pipe_Posix_Blocking - Fatal编程技术网

Sockets 是select()+;在阻塞管道或套接字上是否可以使用非阻塞写入()?

Sockets 是select()+;在阻塞管道或套接字上是否可以使用非阻塞写入()?,sockets,unix,pipe,posix,blocking,Sockets,Unix,Pipe,Posix,Blocking,情况是,我有一个阻塞管道或套接字fd,我想在不阻塞的情况下写入它,所以我首先执行一个select(),但这仍然不能保证write()不会阻塞 这是我收集的数据。即使select()指示 写入是可能的,写入超过PIPE\u BUF字节可能会阻塞。 但是,最多写入PIPE\u BUF字节似乎不会阻塞 实践,但这不是政府的强制要求 它只指定原子行为。声明: 通过select()、poll()或类似方式报告为可供写入的文件 此模块中的接口保证不会在写入时阻塞 到PIPE\u BUF字节。POSIX保证该

情况是,我有一个阻塞管道或套接字fd,我想在不阻塞的情况下写入它,所以我首先执行一个
select()
,但这仍然不能保证
write()
不会阻塞

这是我收集的数据。即使
select()
指示 写入是可能的,写入超过
PIPE\u BUF
字节可能会阻塞。 但是,最多写入
PIPE\u BUF
字节似乎不会阻塞 实践,但这不是政府的强制要求

它只指定原子行为。声明:

通过
select()
poll()
或类似方式报告为可供写入的文件 此模块中的接口保证不会在写入时阻塞 到
PIPE\u BUF
字节。POSIX保证该值至少为
512

在下面的测试程序中,将
BUF_字节
设置为
100000
以块入 成功选择后,在Linux、FreeBSD或Solaris上写入()。我 假设命名管道具有与匿名管道类似的行为

不幸的是,阻塞套接字也会发生同样的情况。呼叫
test\u socket()
main()
中,使用较大的
BUF\u字节
100000
很好 这里也是)。目前还不清楚是否有像这样的安全缓冲区大小 用于插座的管道

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义基本字节管道
字符buf[buf_字节];
int
使用_select探测_(int-nfds、fd _set*readfds、fd _set*writefds、,
fd_集*不包括FDS)
{
struct timeval timeout={0,0};
int n_found=select(nfds、readfds、writefds、exceptfds和timeout);
如果(n_found==-1){
佩罗(“选择”);
}
返回n_发现;
}
无效的
检查是否可读(int fd)
{
fd_集fdset;
FD_零点(&fdset);
FD_集(FD和FD集);
printf(“在fd%d上读取时选择()返回%d\n”,
fd,使用_选择探测_(fd+1和fdset,0,0));
}
无效的
检查是否可写(int fd)
{
fd_集fdset;
FD_零点(&fdset);
FD_集(FD和FD集);
int n_found=使用_select(fd+1,0和fdset,0)进行探测;
printf(“在fd%d上写入的select()返回%d\n”,fd,n\u找到);
/*如果(n_found==0){*/
/*printf(“睡眠”)*/
/*睡眠(2)*/
/*int n_found=使用_select(fd+1,0和fdset,0)进行探测*/
/*printf(“在fd%d上写入的重试选择()返回%d\n”*/
/*fd,n_*/
/* } */
}
无效的
测试管道(空隙)
{
int pipe_fds[2];
书写的大小;
int i;
if(管道(管道){
perror(“管道故障”);
_出口(1);
}
printf(“读取侧管道fd:%d\n”,管道fds[0]);
printf(“写入侧管道fd:%d\n”,管道fds[1]);
对于(i=0;i++){
printf(“i=%d\n”,i);
检查是否可读(管道fds[0]);
检查是否可写(管道fds[1]);
写入=写入(管道fds[1],buf,buf_字节);
如果(写入==-1){
佩罗(“书面”);
_出口(-1);
}
printf(“已写入%d字节\n”,已写入);
}
}
无效的
发球
{
int listenfd=0,connfd=0;
服务地址中的结构sockaddr\u;
listenfd=套接字(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);
绑定(listenfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
听(listenfd,10);
connfd=accept(listenfd,(struct sockaddr*)NULL,NULL);
睡眠(10);
}
int
将_连接到_服务器()
{
int sockfd=0,n=0;
服务地址中的结构sockaddr\u;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
佩罗(“插座”);
出口(-1);
}
memset(&serv_addr,'0',sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(5000);

如果(inet_pton(AF_inet,“127.0.0.1”,&serv_addr.sin_addr)您引用的Posix部分明确说明:

[对于管道]如果O_NONBLOCK标志清除,写入请求可能会导致线程阻塞,但在正常完成时,它将返回nbyte

[对于可能包括流套接字的流]如果O_NONBLOCK清除,并且流无法接受数据(由于内部流控制条件,流写入队列已满),则write()将阻塞,直到可以接受数据


因此,您引用的Python文档只能应用于非阻塞模式。但由于您没有使用Python,因此它与任何情况都没有关系。

除非您希望在选择()时一次发送一个字节表示fd已准备好写入,实际上无法知道您将能够发送多少,即使在理论上,select也有可能(至少在文档中,如果不是在现实世界中)说它已准备好写入,然后在select()和write()之间的时间内更改条件


非阻塞发送是这里的解决方案,如果从使用write()改为send(),则无需将文件描述符更改为非阻塞模式即可以非阻塞形式发送一条消息。唯一需要更改的是将MSG_DONTWAIT标志添加到send调用中,这将使发送无阻塞,而不会更改套接字的属性。在这种情况下,您甚至不需要使用select(),因为send()呼叫将在返回码中为您提供所需的所有信息-如果您得到的返回码为-1,并且错误号为EAGAIN或EWOULDBLOCK,则您知道您不能再发送了。

ckolivas的回答是正确的,但是,读了这篇文章后,我认为出于兴趣,我可以添加一些测试数据

我很快编写了一个慢读tcp服务器(两次读取之间睡眠100毫秒),每个周期读取4KB的数据