Sign in to follow this  
Red Ant

[C++] Async sockets using the plain vanilla socket API??

Recommended Posts

Hello, I have a server application which creates one thread per client it talks to. Once a connection has been initiated, the client may wish to send stuff to the server at any time, so on the server side I must constantly be ready to receive the data and react to it. If this was the only thing I'd have to do in the thread, then I suppose using a blocking socket object would be just fine. I could just recv and not worry about the thread being blocked until the client actually sends me something. Unfortunately, besides being ready to receive data from the client at all times, I must also be ready to react to events sent to my thread from ANOTHER thread in server and react to those as well, which means the idea of using blocking sockets goes straight out the window. What I envision is something like the following: Each of my threads which talk to the clients owns ONE event object. When the thread has determined that there is nothing to do at this time, it suspends itself using this event object. As soon as the client sends stuff using the connection associated with that particular thread, the event object fires (kinda like with the overlapped I/O ReadFile() function from the Windows API) and my thread wakes up. Similarily, if that other thread in my server which I mentioned before, decides that it has work for my client thread, it simply signals its event object, also causing the thread to wake up. Of course I'd need a boolean/integer that the OTHER thread sets to true so my client thread knows whether it was woken up by that OTHER thread or because the client has sent it some new data. Anyway, is there a way to set up a socket object for asynchronous operation using nothing but the normal socket API ... socket, connect, recv, send, accept and all of that? I'm reluctant to use anything Windows specific because I'd like to keep my stuff portable if possible.

Share this post


Link to post
Share on other sites
Are you sure you need asynchronous operation? It sound like you only need non-blocking sockets. For that all you to do is call ioctlsocket() with FIONBIO.

Share this post


Link to post
Share on other sites
In the context of winsock, asynchronous usually means that you've used WSAAsyncSelect(), which sends windows messages when socket events occurs.

Share this post


Link to post
Share on other sites
Ah okay. Yes, in that case I really need non-blocking sockets. I actually want to avoid Windows messages or any of that. Like I said, I need my code to be as portable as possible, so I'm trying hard to steer clear of the Windows API. Anyway, I'll have a look at ioctlsocket(), so thanks a bunch!

Share this post


Link to post
Share on other sites
Hi again!

I've read up on ioctlsocket() and FIONBIO. This is what I found.

Quote:

FIONBIO
The *argp parameter is a pointer to an unsigned long value. Set *argp to a nonzero value if the nonblocking mode should be enabled, or zero if the nonblocking mode should be disabled. When a socket is created, it operates in blocking mode by default (nonblocking mode is disabled). This is consistent with BSD sockets.


Right, understood. However ...

Quote:

This ioctlsocket function performs only a subset of functions on a socket when compared to the ioctl function found in Berkeley sockets. The ioctlsocket function has no command parameter equivalent to the FIOASYNC of ioctl (emphasize mine), and SIOCATMARK is the only socket-level command that is supported by ioctlsocket.


I take that to mean even tho it is possible to set up sockets for non-blocking operation, there is no way I can have the socket send me some kind of notification when it has received something. I'd have to poll the socket to see if anything has arrived. Is that correct? If so, then I need to find another solution.

Share this post


Link to post
Share on other sites
I've looked at that as well, but I don't see how it would help me in the slightest. Have you read my problem description?

Oh, another thing ... assuming a blocking socket, can one thread successfully write data to the socket while another thread is doing a blocking read on the same socket? Or would that fail by definition?

Share this post


Link to post
Share on other sites
I think I've found an acceptable solution to my problem. I'm still using blocking sockets. I just rolled my own asynchronous recv function, which starts a new thread that then does a blocking read and notifies the caller via an event object passed to the function as soon as the blocking read has returned.

Share this post


Link to post
Share on other sites
Quote:
Original post by Red Ant
I've looked at that as well, but I don't see how it would help me in the slightest. Have you read my problem description?



You don't see how abstracting the entire threaded event notification system you've developed into a single loop is helpful?

*shrug* select() is the common, portable way these things are done.

Share this post


Link to post
Share on other sites
Okay, let me explain that again. My thread
A) Should be sleeping when there is nothing to do for it, so as to not waste CPU time.
B) Should wake up whenever the client is sending it something so it can read the data and react to it.
C) Should wake up when another thread in my server wants it to become active and do stuff.

The combination of A), B) and C) implies that my thread has to suspend itself using a SINGLE event object that can be set to the signaled state either by B) or by C).
If I were to use select() (and please feel free to correct me if I'm wrong), then I'd essentially have to kind of periodically POLL the socket ("Hello, have you got any data available for me to read?"), right? Whereas with my solution, my thread automatically wakes up when there is data available __OR__ when that other thread needs it to wake up. I'm not debating that there my be entirely different approaches that are more elegant than the way I'm doing it, tho right now I'm not seeing any.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster

Create a local socket connection from other thread to the client thread. You do all the work for this before spawning the client thread.

Then just include that local socket connection to the other thread in your select fd set (along with the connected client socket). This meets the C requirement

Call select then with a infinite time out. No polling is needed.

Share this post


Link to post
Share on other sites
Ah, a pair of local, connected sockets! Okay, now things are starting to make sense (sorry, I can be a bit dense at times lol). :D
Only annoying thing is that there is no Windows equivalent for the socketpair() function, but I guess I can always roll my own.

P.S. Shame you posted anonymously ... I'd have rated you up. ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this