Currently I am working on a single server,single client udp chat application. Initially I used blocking sockets which is the default condition. Now I want to convert the socket into non-blocking so that communication between client and server could be done without the obstacle of turns...
I've implemented the select function on the server side for now,but the when it starts the client gets to send a message once which is displayed on the server side,afterwards both client and server get unresponsive, so now I am showing how have I implemented the select() function on the server side:
//Declaring a non-blocking structure
fd_set readfds,writefds;
// clear the set ahead of time
FD_ZERO(&readfds);
FD_ZERO(&writefds);
// add our descriptor to the set
FD_SET(sd, &readfds);
FD_SET(sd, &writefds);
/value of sd+1
int n=sd+1;
Since I want to both receive and send data,I've implemented the select function in the loop:
int client_length = (int)sizeof(struct sockaddr_in);
int rv = select(n, &readfds, NULL, NULL, NULL);
if(rv==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
else if(rv==0)
{
printf("Timeout occurred\n");
}
else
if (FD_ISSET(sd, &readfds))
{
int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
}
further for sending data:
fgets(buffer,SIZE,stdin);
int rv1 = select(n, &writefds, NULL, NULL, NULL);
if(rv1==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
else if(rv1==0)
{
printf("Timeout occurred\n");
}
else
if(FD_ISSET(sd,&writefds))
{
if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0)
{
printf("Error sending the file! \n");
exit(1);
}
}
}
So I would really appreciate if somoone let me know whether I've done this right or not,if this is ok then will the same implelementation on the client side resolve my issue?
This is incorrect:
select(n, &writefds, NULL, NULL, NULL);
The second argument is used to check for readability only. To check for writability, use the third argument:
select(n, NULL, &writefds, NULL, NULL);
Related
I want to implement at the client side non-blocking socket with select function. But it doesn't work as expected. In the code below it never runs into else , rv is always 1 and when nothing is on the socket application stops for a while and continue when another messages is on the socket. I don't want that behavior , I want that client sends back message to the server when there is nothing on the socket to recvfrom.
fd_set readfds;
fcntl(sd, F_SETFL, O_NONBLOCK);
while (1) {
FD_ZERO(&readfds);
FD_SET(sd, &readfds);
rv = select(sd + 1, &readfds, NULL, NULL, NULL);
if(rv == 1){
nbytes = recvfrom(sd, buf, RW_SIZE, 0, (struct sockaddr *) &srv_addr, &addrlen);
} else {
printf("I'm never here so I can't send message back to the server!\n");
}
}
with struct timeval:
fd_set readfds;
fcntl(sd, F_SETFL, O_NONBLOCK);
struct timeval tv;
while (1) {
FD_ZERO(&readfds);
FD_SET(sd, &readfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
rv = select(sd + 1, &readfds, NULL, NULL, &tv);
if(rv == 1){
nbytes = recvfrom(sd, buf, RW_SIZE, 0, (struct sockaddr *) &srv_addr, &addrlen);
} else {
printf("I'm always here like now ! \n");
}
}
You set the timeout (last parameter of select) to NULL, which means it will only return once data are available on the socket (or interrupt). You need to set a timeout it should wait. The timeout might be 0 if you don't want to wait, but 0 means to use a struct timeval* with tv_sec=0 and tv_usec=0 and not use a struct timeval* of NULL like you did.
int CreateSocket()
{
socklen_t len;
// Socket creation for UDP
acceptSocket=socket(AF_INET,SOCK_DGRAM,0);
if(acceptSocket==-1)
{
printf("Failure: socket creation is failed, failure code\n");
return 1;
}
else
{
printf("Socket started!\n");
}
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
rc=bind(acceptSocket,(struct sockaddr*)&addr,sizeof(addr));
if(rc== -1)
{
printf("Oh dear, something went wrong with bind()! %s\n", strerror(errno));
return 1;
}
else
{
printf("Socket an port %d \n",port);
}
while(rc!=-1)
{
fd_set master;
fd_set read_fds;
int retval;
FD_ZERO(&master);
FD_ZERO(&read_fds);
FD_SET(acceptSocket, &master);
FD_SET(acceptSocket, &read_fds);
retval =select(2, &master, NULL, NULL, NULL);
len = sizeof(client);
if(retval == -1)
{
printf("error\n");
}
else if(FD_ISSET (acceptSocket, &master))
{
rc=recvfrom(acceptSocket,buf, 256, 0, (struct sockaddr*) &client, &len);
if(rc==0)
{
printf("Server has no connection..\n");
break;
}
if(rc==-1)
{
printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
break;
}
XcpIp_RxCallback( (uint16) rc, (uint8*) buf, (uint16) port );
}
else
{
makeTimer("First Timer", &firstTimerID, 2, 2); //2ms
makeTimer("Second Timer", &secondTimerID, 10, 10); //10ms
makeTimer("Third Timer", &thirdTimerID, 100, 100); //100ms
}
}
close(acceptSocket);
return 0;
}
The above is a server code for udp layer to recieve data from the client via the ip address and port number. I am using select api to check if there is data via the port then recieving the data else call the timer fucntion. I want to achieve of recieving the data from the client and after recieving I have to call the timer. But the above code is not calling the timer task. What is the mistake in the above code ?? is it efficient to use select api ??
The first parameter to select() is 1 + highest-numbered-FD-in-the-three-sets, so should be acceptSocket + 1.
(I'm assuming that your real problem is more complicated than the above code, because you could just make a blocking recvfrom() call and not bother with select(). You need select() if you want to handle multiple sockets in a single thread, and/or to wake up the blocking call after a timeout - although there are other ways of doing the latter.)
The way you are calling select() with timeout == NULL it will block until there is data to be read for one of the file descripors in master. In your case, with master only containing acceptSocket, the else where you call makeTimer() will never be reached.
Do
struct timeval timeout;
timeout.tv_sec = 0l;
timeout.tv_usec = 0l;
retval = select( acceptSocket+1, master, NULL, NULL, &timeout );
to just check without blocking
Note that select() returns 0 if it returns because of timeout and the number of file descriptors contained in the returned descriptor set otherwise. So you also have to change your condition:
else if(FD_ISSET (acceptSocket, &master))
to
else if(retval > 0 && FD_ISSET (acceptSocket, &master))
because otherwise you would call recvfrom() after a timout as well and in that case it would block
I am trying to make an asynchronous UDP chat application, currently having only one client and server.
When I run my server, a lot of redundant data is displayed. Afterward, when some text is typed,
Error sending the file!
is displayed.
Could someone please look at the code and let me know where I am going wrong?
Server:
u_long iMode=1;
ioctlsocket(sd,FIONBIO,&iMode);
int n=sd+1;
fd_set readfds,writefds;
while(1)
{
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(sd,&readfds);
FD_SET(sd,&writefds);
int rv = select(n, &readfds, &writefds, NULL, NULL);
if(rv==-1)
{
printf("Error in Select!!!\n");
exit(0);
}
if(rv==0)
{
printf("Timeout occurred\n");
}
if (FD_ISSET(sd, &readfds))
{
FD_CLR(sd,&readfds);
int client_length = (int)sizeof(struct sockaddr_in);
memset(&buffer,0,sizeof(buffer));
int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
fprintf(stderr, "Could not receive datagram.\n");
closesocket(sd);
WSACleanup();
exit(0);
}
}
printf("\nClient says: %s",buffer);
printf("\nWrite :");
fgets(buffer,SIZE,stdin);
if(FD_ISSET(sd,&writefds))
{
FD_CLR(sd,&writefds);
int client_length = (int)sizeof(struct sockaddr_in);
if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0)
{
printf("Error sending the file! \n");
exit(1);
}
}
}
closesocket(sd);
WSACleanup();
return 0;
}
I see a problem. This line:
int rv = select(n, &readfds, &writefds, NULL, NULL);
Will nearly always return immediately with the readfds empty. But writefds will almost ALWAYS be set with the "sd" socket indicating that it is ready for writing/sending.
Hence, your code correctly skips the attempt to call recvfrom(), but nothing stops it from falling through to the sending code path. All of the variables such client, client_length, and buffer as are likely uninitialized at that point. Or worse, buffer and client are exactly what they were from the last successful call in the loop. That likely explains the redundant data.
My advice would be to not have a "writefds" set in the select call at all. Then only "send" when you actually read. The sendto call won't block for any significant amount of time anyway.
The following code is a test program wriiten to understand the behaviour of select() call in a TCP client program.
What I observe is that the select is not blocking, instead the program is blocking on recv().
The output is as follows:
Wait on select.
Wait on recv.
...
My question is why the select() returns a success? Ideally it should be blocking on the select() instead of recv().
The TCP server is sending a character string of 15 bytes once in 3 seconds.
int clientfd = -1;
int dummyfd = -1;
int maxfd = -1;
struct sockaddr_in server_addr;
char recv_buf[100] = {0};
int msg_len = 0;
int bytes_recv = 0;
fd_set readfd;
int retval = 0;
/* Open the socket and a dummy socket */.
clientfd = socket(AF_INET, SOCK_STREAM, 0);
dummyfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == clientfd || -1 == dummyfd)
{
perror("socket error: ");
exit(1);
}
printf("Socket opened : %d\n", clientfd);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
//server_addr.sin_addr.s_addr = INADDR_ANY;
inet_aton("127.0.0.1", &(server_addr.sin_addr));
memset(&(server_addr.sin_zero), 0, 8);
/* Connect to server */
if(connect(clientfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)))
{
perror("connect error: ");
exit(1);
}
printf("Connect Success\n");
maxfd = (clientfd > dummyfd) ? (clientfd + 1) : (dummyfd + 1);
while(1)
{
FD_ZERO(&readfd);
FD_SET(clientfd, &readfd);
FD_SET(dummyfd, &readfd);
printf("Wait on select\n");
retval = select(maxfd , &readfd, NULL, NULL, NULL);
if(retval <= 0)
{
printf("select failed\n");
}
else
{
printf("Wait on recv\n");
/* ... The process waits here ... */
bytes_recv = recv(clientfd, recv_buf, 100, 0);
printf("%d: Bytes recv = %d\t%s\n", retval, bytes_recv, recv_buf);
memset(recv_buf, 0 ,100);
}
}
close(clientfd);
return 0;
}
Edit: Without dummyfd, the program works as intended.
A follow up question:
When the server is closed abruptly, how to detect this using select()?
Can the program be modified so that is blocks on select() when the server side, say, crashes?
Use the following to be sure it's the clientfd that's returning from the select:
else if (FD_ISSET(clientfd, &readfd)) {
Don't have time to test, but I suspect the dummyfd is returning as an EOF from the select, not the clientfd.
After select() returns, you will want to conditionally receive from clientfd. My guess is that there may be data on dummyfd that is triggering the select to complete, but the receive is on the clientfd.
retval = select(maxfd , &readfd, NULL, NULL, NULL);
if(retval <= 0)
{
printf("select failed\n");
}
else
{
if (FD_ISSET(clientfd, &readfd))
{
bytes_recv = recv(clientfd, recv_buf, 100, 0);
...
}
if (FD_ISSET(dummyfd, &readfd))
{
/* "dummyfd" processing */
}
I'm trying to figure out what is blocking my program. I'm running a server that uses POSIX threads. I have to for my computer programming lab. The main function listens for new connections. Once it accepts a connection, it creates a new thread by passing the FD to the thread. I'm able to successfully connect to the server using multiple telnet/client connections. I can send data to the server successfully once, but if I try sending again the server won't do anything.
Part of the main function
int active_thread = 0;
//The Running loop
while(running)
{
if(active_thread > NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up");
running = false;
}
else
{
if(FD_ISSET(sockfd, &readfds))
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
//close(bindfd[active_thread]);
//pthread_join( threads[active_thread], NULL);
active_thread++;
//running = false;
}
}
}
close(sockfd);
return 0;
}
Part of the POSIX THREAD CODE
void *server_handler( void *sockfd)
{
int bindfd = *( (int *) sockfd);
char buffer[MESSAGELENGTH];
bool running = true;
printf("Thread was created successfully\n");
char intro[] = "Successfully Connected to server!\n";
struct pollfd pfd;
pfd.fd = bindfd;
pfd.events = POLLIN;
if ( (send(bindfd, intro, strlen(intro), 0)) < 0)
{
perror("Unable to send");
}
while(running){
char msg[] = "\nYou have the following options!\n1) Insert an integer: insert <integer>\n2) Remove An Integer: remove <integer>\n3) Get number of integers in list: get_count\n4) Get first integer: get_first\n5) Get last integer: get_last\n6) Quit program: quit\n ";
if ( (send(bindfd, msg, strlen(msg), 0)) < 0)
{
perror("Unable to send");
}
memset(&buffer, 0, MESSAGELENGTH);
if (recv(bindfd, buffer, MESSAGELENGTH, 0) > 0)
{
//SOme other code
}
}
I think its blocking at either the accept or recv. I've heard of select() and various other methods, but I'm having difficulty trying to implement them. Thanks!
The root cause of your issue appears to be that you are unconditionally executing close(sockfd); return 0; at the bottom of your while (running) loop, which means that the loop only ever executes once.
Additionally, you should not be using FD_ISSET() unless you are also using select(). Your main loop should look something more like:
int active_thread = 0;
while (active_thread < NUMBTHREADS)
{
if((bindfd[active_thread] = accept(sockfd, (struct sockaddr *) &client_addr, &client_sock_size)) == -1)
{
fprintf(stderr, "Unable to accept client \n");
perror("What");
break;
}
activethreads[active_thread] = pthread_create( &threads[active_thread], NULL, server_handler, (void*) &bindfd[active_thread]);
active_thread++;
}
if (active_thread >= NUMBTHREADS)
{
printf("Unable to accept client connection! Threads are all used up.\n");
}
running = false;
close(sockfd);
return 0;
By default network sockets are blocking. You need to set the O_NONBLOCK flag on the socket.
if(fcntl(fd, F_GETFL, &flags) < 0 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
perror("Failed to set socket as non-blocking");
Now, instead of blocking when there is no input (or buffer space to store output), the error EAGAIN (or EWOUDLBLOCK) is returned. Lastly, you will need to use select() or poll() when you have nothing else to do but wait on I/O. These calls will only wake the process when either there is input, room for output, or possibly a time-out period passes.
int maxFd;
fdset fds;
FD_ZERO(&fds);
FD_SET(listenFd, &fds);
FD_SET(sockFd1, &fds);
FD_SET(sockFd2, &fds);
maxFd = listenFd+1;
maxFd = sockFd1 > maxFd ? sockFd1+1 : maxFd;
maxFd = sockFd2 > maxFd ? sockFd2+1 : maxFd;
if(select(maxFd, &fds, &fds, &fds, NULL) < 0) {
perror("Failed on select()");
exit(1);
}
if(FD_ISSET(listenFd, &fds))
...
This example is not complete or neccessarily 100% correct, but should be a good start. Also, I tend to reserve using send*() and recv*() when dealing with SOCK_DGRAM sockets and just use read(), write() on SOCK_STREAM sockets.