Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C udp Sockets
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 irresponsive, 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 funtion 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);
                         }
                  }
 
                }
Posted 14-Apr-13 21:05pm
Comments
Sergey Alexandrovich Kryukov at 15-Apr-13 2:16am
   
Why? I hoped non-blocking sockets will go as threading becomes a commonplace. Better use threads with blocking calls. It makes code more linear, straightforward, more universal.
—SA
parths at 15-Apr-13 2:53am
   
If we used threading, wouldn't it depend on how many concurrent connections we want to support? For instance, if we have more than about 10-15K connections the context switching between the threads could become a bottleneck, right? Also anything about 32K connections (meaning 32K threads) would probably be unfeasible.
Sergey Alexandrovich Kryukov at 15-Apr-13 3:05am
   
No. The same thread is used for many connections. One example: TCP socket on client side. Two threads are minimally required: one accepts new connections, another one sends/receives data to/from remote sockets. Similar approached for different scenarios.
 
There are many people arguing against threads, but all arguments are reduced to one: they show the case if idiotic misuse of threads and then say: "look how bad!".
 
—SA
parths at 15-Apr-13 3:13am
   
But if we use the same thread for multiple connections, wouldn't each connection in any one thread have to be asynchronous / non-blocking? Otherwise the thread would block on the first blocking call and wouldn't be able to process any other connections that it has. Am I missing something?
Sergey Alexandrovich Kryukov at 15-Apr-13 3:30am
   
Look at this in this way: all your async APIs are implemented as threads anyway, but hidden from your...
No, there is no the limitation you mentioned. Why having async at all?
—SA
parths at 15-Apr-13 4:19am
   
Ref: http://www.xml.com/ldd/chapter/book/ch05.html
FIONBIO sets the O_NONBLOCK flag in filp->f_flags. This results in the read call returning immediately if there's no data present, as opposed to blocking the calling process/thread. This would be necessary if we want to handle multiple connections (or generally io operations) in a single thread without blocking, right?
Sergey Alexandrovich Kryukov at 15-Apr-13 4:22am
   
I don't agree, I already tried to explain why. However, thanks for the reference.
—SA
parths at 15-Apr-13 6:32am
   
Just to clarify, I am not against using threads, I had already modified my answer (below) to add that note before continuing our discussion. It'd be informative for me to try and understand any comparisons between the 2 methods. I'm checking google, but if you have any references, please share. Thanks
Sergey Alexandrovich Kryukov at 15-Apr-13 11:08am
   
"Network programming is very tricky because there are no written rules, there are a lot of options to play around with."
 
That's right. You cannot find a final recipe and comparison, just because posting them may not make sense. You can compare different approaches for concrete settings analytically and experimentally.
 
—SA
pasztorpisti at 15-Apr-13 4:18am
   
In 99.99% of the time my networking applications had less then 50 very active parallel clients. In this case we can safely go with a very simple model where 1 thread serves 1 connection. This makes code linear and less buggy as Sergey said. Don't prepare your code for thousands of clients if it will never have to serve thousands of clients. Async servers might be able to serve more clients but often they are less responsive and have lower performance/client when its about transmitting high volume of data (e.g. HTTP server).
 
Most of the time I create 1 thread/client with an async socket. This is necessary when the protocol is not deterministic like the classic request-response style of HTTP but some events can come unpredictably but in case of request-response style protocol you could safely use blocking sockets. For example if the server sends the client a very big file but the client is allowed to send a cancel message to the server at any point then the server must be able to handle both the sending of the data and the receiving of the occasional cancel message. In this case you HAVE TO use an async socket on the server side even if you have 1 thread/client. The number of threads and asnyc/blocking mode are 2 different options.
 
Network programming is very tricky because there are no written rules, there are a lot of options to play around with.
 
If you want to write a server with very high load then you have to go another route anyway because select() and its friends can handle at most 64 connections on windows, and the number of handles a select can handle is limited on linux too. High performance servers usually use a thread pool that handle sockets with iocp or epoll.
parths at 15-Apr-13 8:31am
   
Thanks for the info. I didn't mean to say anything against using threads with blocking socket io.
Also, thanks for mentioning epoll, didn't know about that. I had checked out IO completion ports on windows for high performance servers, didn't know about epoll, thanks for pointing it out.
Aayman Khalid at 15-Apr-13 2:23am
   
So you mean that threading is the better way to implement non-blocking sockets and I should quit on select()?
Sergey Alexandrovich Kryukov at 15-Apr-13 3:01am
   
Yes, I'm sure, much better. (I don't know what do you mean by "quite").
You see, you isolate the problem into almost independent threads, each one is pretty simple.
Yes, they need to communicate, but you use the same very thread synchronization primitives again and again for very different problems, while async APIs are specific to different API. Threads, threads, and again threads...
—SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

I couldn't see any calls setting the socket to work in non-blocking mode. Did you take a look at ioctl[^] (optionally ioctlsocket[^] for win32) with the FIOASYNC and/or FIOBNIO[^] options?
 
Here's the first tut link[^] I got from google. You might find better ones.
 
I hope this helps
 
[Modification] Also, depending on you requirement and other load expectations, as Sergey pointed out above, using threads with blocking calls should be considered [/Modification]
  Permalink  
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

You have to turn the socket into nonblocking mode even if you are using select() and its friends. On some versions of windows select() is able to wake up spuriously because the network stack receives some data but when you actually start reading the socket it can find out that the crc of the received data isn't OK leaving your reading in a blocking state if the socket isn't turned into non-blocking. This may happen also on non-windows OS-es. Another problem with your code is that you should handle the wait for read/write operations with a single select call.
int rv = select(n, &readfds, &writefds, NULL, NULL);
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 304
1 Maciej Los 285
2 Sergey Alexandrovich Kryukov 230
3 Shweta N Mishra 186
4 Aajmot Sk 153
0 OriginalGriff 7,660
1 Sergey Alexandrovich Kryukov 7,072
2 DamithSL 5,604
3 Manas Bhardwaj 4,986
4 Maciej Los 4,760


Advertise | Privacy | Mobile
Web02 | 2.8.1411023.1 | Last Updated 15 Apr 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100