'select monitor two socket and return 1 instead of 2
server send "hello" after accept two client.
client recv "hello" and send something infintely.
Then, server uses select() waiting for data from two socket_fd.
I support that select() could detect if socket_fd had data in its buffer and result would be 2.
Acturally, it return 1 after some 2.
In wireshark, it caused a zero-window.
How can I fix it?
My simplfied code:
// server.cpp
#include <cstdio>
#include <cstring>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
struct sockaddr_in ser_addr, cli_addr[2];
int lisn_fd, conn_fd[2];
fd_set fs;
socklen_t len;
char buff[4096];
int main() {
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(9876);
lisn_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(lisn_fd, (struct sockaddr*) &ser_addr, sizeof(ser_addr));
listen(lisn_fd, 10);
FD_ZERO(&fs);
for (int i = 0; i < 2; i++) {
conn_fd[i] = accept(lisn_fd, (struct sockaddr*) &cli_addr[i], &len);
FD_SET(conn_fd[i], &fs);
}
int maxfd = conn_fd[0] > conn_fd[1]? conn_fd[0] : conn_fd[1];
while (1) {
write(conn_fd[0], "hello", 5);
write(conn_fd[1], "hello", 5);
int nready = select(maxfd+1, &fs, NULL, NULL, NULL);
printf("nread = %d\n", nready);
for (int i = 0; i < 2; i++) {
if ( FD_ISSET(conn_fd[i], &fs) ) {
printf("recv from client %d\n", i+1);
ssize_t nread = read(conn_fd[i], buff, 4096);
buff[nread] = 0;
// puts(buff);
}
}
}
return 0;
}
// client.cpp
#include <arpa/inet.h>
#include <cstdio>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
struct sockaddr_in ser_addr;
int conn_fd;
int main(){
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(9876);
inet_pton(AF_INET, "127.0.0.1", &ser_addr.sin_addr);
conn_fd = socket(AF_INET, SOCK_STREAM, 0);
connect(conn_fd, (struct sockaddr*) &ser_addr, sizeof(ser_addr));
char buff[4096];
buff[read(conn_fd, buff, 4096)] = 0;
printf("recv: %s\n", buff);
sprintf(buff, "hello from %d", getpid());
while (1) {
sleep(1);
write(conn_fd, buff, strlen(buff));
}
return 0;
}
$ ./server
recv from client 1
recv from client 2
nread = 2
recv from client 1
recv from client 2
nread = 2
recv from client 1
recv from client 2
nread = 2
recv from client 1
recv from client 2
nread = 1
recv from client 1
nread = 1
recv from client 1
nread = 1
recv from client 1
nread = 1
recv from client 1
nread = 1
recv from client 1
^C
$ ./client
recv: hello
$ netstat -anp | rg server
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
tcp 0 0 0.0.0.0:9876 0.0.0.0:* LISTEN 13805/./server
tcp 2160 0 127.0.0.1:9876 127.0.0.1:54694 ESTABLISHED 13805/./server
tcp 0 0 127.0.0.1:9876 127.0.0.1:54696 ESTABLISHED 13805/./server
=================UPDATE===================
I don't expect sockets are alyways ready and the result is always 2.
The problem is if turn into 1, it will be 1 forever.
And I found a solution, but it is confusing.
// server.cpp
// ommit others
while (1) {
// clear & reset fd_set before using select
FD_ZERO(&fs);
FD_SET(conn_fd[0], &fs);
FD_SET(conn_fd[1], &fs);
I reset the fd_set, and the 1 and 2 will staggered appear.
Is select() will change somthing?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
