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.