0
votes

I wrote a little tcp socket server program, using select() to check if a client socket is writable. If the client is writable, I will write data to it.

The client is written in Python, for testing only, it connect to the server, and never read from the connect.

The result is, server write() finally blocks.

Server(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;
}

Client(Python):

import socket
s = socket.socket()
s.connect(('127.0.0.1', 7000))

Output:

$ 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

My qustion is: why would write() operation blocks even if select tells writable? The manual of select() says:

A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2)) without blocking.

2

2 Answers

1
votes

Select() doesnt know how many bytes you are going to try to write, it only knows that the socket's outgoing-data buffer isn't full.

If you want write() not to block, set the socket to non-blocking mode.

0
votes

The receiver's TCP buffer will finally be filled with data sent by the sender so that it advertises a zero-sized window to notify the sender that "I have no space left to hold your data, stop now".