我写了一个小的tcp套接字服务器程序,使用select()来检查客户端套接字是否可写。如果客户端是可写的,我会将数据写入其中。
客户端是用Python编写的,仅用于测试,它连接到服务器,从不从连接中读取。
结果是,服务器write()最终阻塞。
服务器(C):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/select.h>
int main(int argc, char **argv){
int serv_sock;
struct sockaddr_in addr;
const char *ip = "0.0.0.0";
int opt = 1;
int port = 7000;
if(argc > 2){
port = atoi(argv[1]);
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((short)port);
inet_pton(AF_INET, ip, &addr.sin_addr);
serv_sock = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(serv_sock, (struct sockaddr *)&addr, sizeof(addr));
listen(serv_sock, 1024);
printf("server listen on port: %d\n", port);
int sock = accept(serv_sock, NULL, NULL);
printf("accepted\n");
while(1){
fd_set w_set;
FD_ZERO(&w_set);
int maxfd = sock;
FD_SET(sock, &w_set);
int ret = select(maxfd + 1, NULL, &w_set, NULL, NULL);
if(ret < 0){
if(errno == EINTR){
continue;
}else{
printf("select error! %s\n", strerror(errno));
exit(0);
}
}
char buf[128 * 1024];
if(FD_ISSET(sock, &w_set)){
printf("write begin\n");
int n = write(sock, buf, sizeof(buf));
printf("write %d\n", n);
}
}
return 0;
}
客户端(Python)的
import socket
s = socket.socket()
s.connect(('127.0.0.1', 7000))
输出:
$ gcc a.c; ./a.out
server listen on port: 7000
accepted
write begin
write 131072
write begin
write 131072
write begin
write 131072
write begin
write 131072
write begin
write 131072
write begin
我的qustion是:为什么写()操作块,即使select告诉可写? select()的手册说:
如果可以,则认为文件描述符已就绪 不执行相应的I / O操作(例如,读取(2)) 阻塞。
答案 0 :(得分:1)
Select()不知道你要尝试写多少字节,它只知道套接字的传出数据缓冲区未满。
如果您希望write()不阻止,请将套接字设置为非阻塞模式。
答案 1 :(得分:0)
接收方的TCP缓冲区最终将被发送方发送的数据填充,以便它通告零大小的窗口,通知发送方“我没有空间来保存您的数据,现在停止”。