tcp套接字,select告诉可写,但write()阻塞

问题描述 投票:0回答:2

我编写了一个小的 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

我的问题是:即使 select 告诉可写,为什么 write() 操作也会阻塞? select() 的手册说:

如果可以的话,文件描述符被认为准备就绪 执行相应的 I/O 操作(例如,read(2)),无需 阻塞。

python c sockets tcp posix-select
2个回答
1
投票

Select() 不知道您要尝试写入多少字节,它只知道套接字的传出数据缓冲区未满。

如果您希望 write() 不阻塞,请将套接字设置为非阻塞模式。


0
投票

接收方的 TCP 缓冲区最终将被发送方发送的数据填满,以便它通告一个零大小的窗口来通知发送方“我没有剩余空间来保存您的数据,现在停止”。

© www.soinside.com 2019 - 2024. All rights reserved.