Reputation: 1314
In order to test the select system call, I wrote a program to receive data from client:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#define BACKLOG 5
int main(int argc, char *argv[])
{
if (argc <= 2)
{
printf("Usage: %s ip_address port_number\r\n", basename(argv[0]));
return 1;
}
const char *ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd != -1);
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, BACKLOG);
assert(ret != -1);
struct sockaddr_in client_address;
socklen_t client_addrlen = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_addrlen);
if (connfd < 0)
{
printf("accept failed! errno is %d\r\n", errno);
close(listenfd);
}
else
{
printf("accept success!\r\n");
}
char buf[1024];
fd_set read_fds;
fd_set exception_fds;
FD_ZERO(&read_fds);
FD_ZERO(&exception_fds);
while (1)
{
memset(buf, 0, sizeof(buf));
FD_ZERO(&read_fds);
FD_ZERO(&exception_fds);
FD_SET(connfd, &read_fds);
FD_SET(connfd, &exception_fds);
ret = select(connfd + 1, &read_fds, 0, &exception_fds, NULL);
if (ret < 0)
{
printf("selection failed!\r\n");
break;
}
if (FD_ISSET(connfd, &read_fds))
{
ret = recv(connfd, buf, sizeof(buf)-1, 0);
if (ret < 0)
{
break;
}
printf("received %d bytes of normal data: %s\r\n", strlen(buf), buf);
}
else if (FD_ISSET(connfd, &exception_fds))
{
ret = recv(connfd, buf, sizeof(buf)-1, MSG_OOB);
if (ret < 0)
{
break;
}
printf("received %d bytes of oob data: %s\r\n", strlen(buf), buf);
}
}
close(connfd);
close(listenfd);
return 0;
}
however, when I send data from the client program, the server program above prints as follows: accept success!
received 16 bytes of normal data: thisisnormaldata
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
received 0 bytes of normal data:
(endless "received o bytes of normal data")
why the select system call report the read fds are ready constantly?
Upvotes: 1
Views: 85
Reputation: 180201
select()
reports your FD constantly ready because it is constantly ready. It doesn't block (I presume).
Consider the implications of the message that keeps being printed, in light of this excerpt for the documentation for recv()
:
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0.
Since you are using a stream socket, it can indeed tell when the other end has performed an orderly shutdown. Your program is telling you that that is what happened. It is willing to tell you so as many times as you ask. A more typical response for your program to make than asking again, repeatedly, would be to close the local end of the connection and move on to other things (maybe such as handling other connections).
Possibly you want to select()
the listenfd
file descriptor instead in order to wait for subsequent connections, though I don't see what good that would do you, as you don't at that point have any other work to do so that just performing a blocking accept()
would be a problem.
Upvotes: 3