Select() to read in sockets - c

I have a client server client connection where the server reads the message sent by the client every 1 second but I do not want the server to keep on waiting for a message for too long. I tried using the select() function but the server continues waiting for some message to read. Could anyone tell me what I am doing wrong please?
fd_set master;
fd_set read_fds;
FD_ZERO(&master);
FD_ZERO(&read_fds);
FD_SET(sock, &master);
while (1) {
bzero(message, 256);
sleep(1);
read_fds = master;
if(select(sock+2, &read_fds, NULL, NULL, NULL) < 0)
error("ERROR reading");
//if there is any data to read from the socket
else if(FD_ISSET(sock, &read_fds)){
n = read(sock, buffer, 256);
c = buffer[0];
printf("1st char is %c",c);
}//close else if statement
else printf("Nothing was read");
}//close while loop

A few comments that are too long to fit in the comments...
The first parameter to select really only needs to be sock+1.
By passing NULL for the timeout, select will block indefinitely (so you might as well have just called read).
When select does tell you that sock is ready for reading, there may only be one byte present, even if the other end wrote more then that. You will have to loop, reading the socket until you get the number of bytes you want. You will have to decide if you want the timeout only while waiting for the first byte, or if you want to timeout in the middle (I.e. is the select inside or outside the loop).
Normally, when using select, you only want to block in select, and not in read, so the socket should be put in non-blocking mode, and you should be prepared for the read to fail with EWOULDBLOCK.
If you do time out, do you want to close the connection? If you got half way through a message, you can't just throw away the half and keep going because you would now be expecting the next byte to be another start of message when it will now be a middle.

Related

Server TCP stuck on read()

I'm trying to get a server to receive messages from a client in TCP.
The problem is, I only receive the messages on the server side once I close the socket on the client side.
Here is the read function on the server side:
char *read_socket(int fd){
int bytesRcvd, aux;
char *buffer=(char*)malloc(BUFFSIZE*sizeof(char));
bytesRcvd=read(fd, buffer , BUFFSIZE);
aux=bytesRcvd;
while(bytesRcvd>0){
if((bytesRcvd = read(fd, &buffer[aux], BUFFSIZE))<0){
printf("read() failed!: %s\n", strerror(errno));
exit(1);
}
aux+=bytesRcvd;
}
return &buffer[0];
}
I know (by printfs) that it gets stuck on the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Any help will be greatly appreciated.
Your program is reading the data in the line:
bytesRcvd = read(fd, &buffer[aux], BUFFSIZE)
Your while loop receives the data that the client sends. If the client doesn't have data to send read will block until the connection is closed where read will return 0 and you will exit from while loop.
This is the reason that you think that the data are send in the end (when connection is closed). This is not right, if you print the data you read in the while loop you will see them immediately and not all of them in the end.
Though you can't return the data before the connection is closed due to read() blocking.
For one client your program may seems ok if you don't have the problem of getting data at the end (as I said you could just print them inside while loop) but imagine have two or more clients then you would firstly close connection with first client to go on and read data from second and so on.
One solution(to both problems) is to use select() system call, this will go on to read only if there are data.( Though select() is not safe when using fork()- doesn't guarantee that a parent of child process will not block in read() ).

How to recv until theres nothing more to recv without eof?

So i need to recv an html file from the server to the client, the file is bigger than the buffer so i make several sends. Thats why i have this loop when i recv
while (i = recv(s, buf, TAM_BUFFER, 0)) {
if (i == -1) {
perror(argv[0]);
fprintf(stderr, "%s: error reading result\n", argv[0]);
exit(1);
}
while (i < TAM_BUFFER) {
j = recv(s, &buf[i], TAM_BUFFER - i, 0);
if (j == -1) {
perror(argv[0]);
fprintf(stderr, "%s: error reading result\n", argv[0]);
exit(1);
}
i += j;
}
/* Print out the file line by line. */
printf("%s", buf);
}
the send looks something like this:
while (fgets(buf, sizeof(buf), fp)){
if (send(s, buf, TAM_BUFFER, 0) != TAM_BUFFER) errout(hostname);
}
The problem is the loop never ends, becase it doesnt recv the eof and i is never 0, its just remain blocked there.
I cant do the close to send the eof because after he recv the whole file, the client will ask for another file.
I tryed to send a SIGALRM if the loop stays blocked for longer than 5 seconds but it doesnt work as expected, because the loop wont stop, and it will throw an error.
Also how can i do to be able to recv less than TAM_BUFFER?(in the send, change the TAM_BUFFER -> strlen(buf)) I know i need to change the interior loop, but then ill have the same problem, j will not be 0 never, so i dont know how could i end it.(or maybe i dont need the second loop in this case).
EDIT: i cant send the lenght of the file beucause of the protocol im following
TCP is a protocol used to transport a single unstructured octet stream in each direction. Shutdown of the connection (i.e. EOF) is the only way in TCP to signal to the peer that no more data will be sent in this connection. If you need a different way because you need to distinguish between multiple messages inside the same TCP connection then you need to use an application level protocol which can specify such message boundaries. This is usually done by fixed message size, prefixing the message with a length or by special boundary markers.
If you can't embed payload size in your protocol, you have to identify EOF by closing socket or checking for timeout. You can use select function and set timeout for it, see here Using select and recv to obtain a file from a web server through a socket and https://stackoverflow.com/a/30395738/4490542

One socket descriptor always blocked on write. Select not working?

Hello I have a server program and a client program. The server program is working fine, as in I can telnet to the server and I can read and write in any order (like a chat room) without any issue. However I am now working on my client program and when I use 'select' and check if the socket descriptor is set to read or write, it always goes to write and then is blocked. As in messages do not get through until the client sends some data.
How can I fix this on my client end so I can read and write in any order?
while (quit != 1)
{
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_SET(client_fd, &read_fds);
FD_SET(client_fd, &write_fds);
if (select(client_fd+1, &read_fds, &write_fds, NULL, NULL) == -1)
{
perror("Error on Select");
exit(2);
}
if (FD_ISSET(client_fd, &read_fds))
{
char newBuffer[100] = {'\0'};
int bytesRead = read(client_fd, &newBuffer, sizeof(newBuffer));
printf("%s",newBuffer);
}
if(FD_ISSET(client_fd, &write_fds))
{
quit = transmit(handle, buffer, client_fd);
}
}
Here is code to transmit function
int transmit(char* handle, char* buffer, int client_fd)
{
int n;
printf("%s", handle);
fgets(buffer, 500, stdin);
if (!strchr(buffer, '\n'))
{
while (fgetc(stdin) != '\n');
}
if (strcmp (buffer, "\\quit\n") == 0)
{
close(client_fd);
return 1;
}
n = write(client_fd, buffer, strlen(buffer));
if (n < 0)
{
error("ERROR writing to socket");
}
memset(buffer, 0, 501);
}
I think you are misinterpreting the use of the writefds parameer of select(): only set the bit when you want to write data to the socket. In other words, if there is no data, do not set the bit.
Setting the bit will check if there is room for writing, and if yes, the bit will remain on. Assuming you are not pumping megabytes of data, there will always be room, so right now you will always call transmit() which waits for input from the command line with fgets(), thus blocking the rest of the program. You have to monitor both the client socket and stdin to keep the program running.
So, check for READ action on stdin (use STDIN_FILENO to get the file descriptor for that), READ on client_fd always and just write() your data to the client_fd if the amount of data is small (if you need to write larger data chunks consider non-blocking sockets).
BTW, you forget to return a proper value at the end of transmit().
Sockets are almost always writable, except when the socket send buffer is full, which indicates that you are sending faster than the receiver is receiving.
So your transmit() function will be entered every time around the loop, so it will read some data from stdin, which blocks until you type something, so nothing happens.
You should only select on writability when a prior send() has returned EWOULDBLOCK/EAGAIN. Otherwise you should just send, when you have something to send.
I would throw this code away and use two or three threads in blocking mode.
select is used to check whether a socket has become ready to read or write. If it is blocking for read then that indicates no data to read. If it is blocking in write, then that indicates the TCP buffer is likely full and the remote end has to read some data so that the socket will allow more data to be written. Since the select blocks until one of the socket descriptions is ready, you also need to use timeout in select to avoid waiting for a long time.
In your specific case, if your remote/receiving end keep reading data from the socket then the select will not block for the write on the other end. Otherwise the tcp buffer will become full on the sender side and select will block. Answers posted also indicate the importance of handling EAGAIN or EWOULDBLOCK.
Sample flow:
while(bytesleft > 0)
then
nbytes = write data
if(nbytes > 0)
bytesleft -= nbytes;
else
if write returns with EAGAIN or EWOULDBLOCK
call poll or select to wait for the socket to be come ready
endif
endif
if poll or select times out
then handle the timeout error(e.g. the remote end did not send the
data within expected time interval)
endif
end while
The code also should include handle error conditions and read/write returning with (For example, write/read returning with 0). Also note read/recv returning 0 indicates the remote end closed the socket.

timeout while on a read using Select

Here is my situation, I am using UDP, and have a server who is sending me data, but he could also possibly not send the data, due to a lost packet, and I'd like him to resend it, but my client might also not receive the data, so I'd like him re-read it. For now, I decided to go with a timeout on my client, who will wait a certain amount of time, and then re-read. My problem is that, is simply adding a goto which heads back to the select going to solve the issue, or will select be broken after the first timeout? Do I havet to make the socket non-blocking? I read that somewhere on the net. Essentially, my goal is that if read doesn't happen, try again, after a certain period of time, cause I know thes sender is trying to send. I want to know if my logic is correct since there is no way of me testing it.
fd_set set;
struct timeval timeout;
int rv;
char buff[100];
int len = 100;
FD_ZERO(&set); /* clear the set */
FD_SET(sockfd, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
retry:
write(sockfd,"hi",3);//sent to client now waiting for an ack
rv = select(sockfd + 1, &set, NULL, NULL, &timeout);
read(sockfd, buff, strlen(buff), 0);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
printf("timeout");
goto retry;
else
read( filedesc, buff, len ); /* there was data to read */
}
I would excpect that select modifies your fd_set so that it doesn't contain your sockfd anymore after read (because it wasn't ready to read). So just to be sure you should reinitialize the set before the retry. Or you could try if the fd is still there after a timeout, but I think the normal behaviour is to reinitialize all FDs before calling select.
If you use poll or epoll you don't have to do that.
Apart from that the code looks ok.
Whether you use blockin or nonblocking IO doesn't matter for the read in your case. If you use non-blocking your write could fail, therefore staying with blocking is easier.

c socket: recv and send data simultaneously

I'm having issues with my client side implementation of client server chat program where multiple clients connect. The issue is that i'm coming across is that how exactly should i be sending (chat message to another client) and receiving (chat message from another client) at the same time? What's happening is that i'm always sending data and never reading. Do i need to fork and have one read and the other send?
here is the relevant code
client side
while(1) {
fd_set rfds, wfds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(serverSocket, &rfds);
FD_SET(serverSocket, &wfds);
if(select(serverSocket+1, &rfds, &wfds, NULL, NULL) < 0) {
perror("select");
exit(-1);
}
if (FD_ISSET(serverSocket, &rfds)) {
// we got data, read it
}
if (FD_ISSET(serverSocket, &wfds)) {
printf(">");
// read keyboard
sendLen = 0;
while ((cmd[sendLen] = getchar()) != '\n')
sendLen++;
cmd[sendLen] = '\0';
// send the data
}
}
You should put the file descriptor 0 (standard input) in the select as well, then read chars and buffer them, and when the socket is available for writing, copy the entire buffer on it. In this way you just block reading on the standard input all the time.
add
FD_SET(0, &rfds);
so select will return when user types something as well.
you must also use fcntl to set stdin as non-blocking.
Then everytime select tells you there's data on stdin do something like that:
while(read(0,buffer+filled,1)>0) {}
Make sure to put another condition to exit the loop if the buffer is full.
then when you can write on the socket do a send, of the size of the amount of bytes you have in your buffer, check if all of it has been written, or move the leftovers bytes at the beginning of the buffer.
That while(getchar()) is blocking you preventing you from receving any messages.

Resources