Click to See Complete Forum and Search --> : Sockets in C


TaeShadow
06-03-2002, 01:52 PM
I am writing a network client that allows the user to send commands to a server. Additionally, the program needs to listen for messages from the server, which can occur at random times, not just in response to what the user sends. How can I have my program monitor and respond to these messages at the same time as it is presenting the user with a prompt?

Strogian
06-03-2002, 03:49 PM
One way to do it would (and I'm speaking broadly here, since I don't remember exactly how sockets work in C) be to have the prompt actually be a continuous loop that checks the socket for input, then checks stdin for input. Whichever one happens first is then acted upon. In fact, I think that you could use the select() or poll() functions to do this.

Energon
06-03-2002, 06:14 PM
One way is to use select on a non-blocking socket, and you only read when there's data to be read, or you can use threads. The problem is that the input is not going to break until something is entered without some hacking around, so your best bet is to thread it/put it in a new process with fork().

The times I've done it, I make a thread that does input in a loop and a thread that works on a non-blocking socket with select() and just loops around. When input comes in, it's pushed onto a queue and when the queue's not empty, the socket thread dequeues a packet and sends it off.

TaeShadow
06-04-2002, 10:49 AM
At the moment, the only thing I need to do with incoming messages is display them to the user. In the future, this will change, so I may need to do something more sophisticated. When the program starts, let's say I start a thread that monitors the socket for incoming messages. When it recieves one, it enqueues it and continues to monitor. When the users finishes entering an input string, the program processes the user's command, and then proceeds to dequeue messages until the queue is empty. Then, it asks for input again, and the thread continues to monitor the socket.

Is there anything wrong with this? I was reading about select() and I don't understand how it would help me here. It seems that it is designed for cases where you would like to monitor multiple sockets at once.

Thanks.

Aaron_Adams
06-04-2002, 11:22 AM
select() is actually for monitoring multiple descriptors at once, so that would include sockets and files.

It's good for situations where you're client program may need to be blocked into a read from STDIN, but you also want to keep track of signals generated from the server, in which case you block into select() instead.

Energon
06-04-2002, 01:18 PM
The only problem with waiting for input then dequeing all the messages is that if the user doesn't input anything, they don't get any messages... always assume the user won't cooperate...

Stuka
06-04-2002, 01:50 PM
<WARNING: This could be wrong...>
But, as select() does monitor file descriptors, you can use it to test if the console is reading, and not write until its done. You can use the same process to test your socket for any incoming messages. So, basically:
1. Use select() to decide what's busy.
2. Read any incoming messages.
3. Respond correctly to the console.
4. Print out messages.

Now, this sorta depends on these being in different threads I think, as any interaction with the console would be delayed otherwise...but maybe not -- maybe you could just do it in a loop like I described, since that would eliminate polling the socket, and still interact relatively quickly with the user....

Energon
06-04-2002, 03:16 PM
Will select() report somethings ready on stdin only if there's a newline? Or will it say it's ready every time a key is pressed? You could probably get that all to work in one thread that way if it works like I'm thinking it would. It may also allow you to output new things without disrupting where the user is inputting since you can just write back what they've already typed.

Strogian
06-04-2002, 04:04 PM
Originally posted by Energon:
<STRONG>Will select() report somethings ready on stdin only if there's a newline? Or will it say it's ready every time a key is pressed? You could probably get that all to work in one thread that way if it works like I'm thinking it would. It may also allow you to output new things without disrupting where the user is inputting since you can just write back what they've already typed.</STRONG>

select() will only say there is input if the user presses Enter, normally. The reason for this is that, on Linux, there actually IS no input until the user presses Enter. What you type is held in the console buffer, then it sends it to the program after you press the Enter key. You may be able to modify the console settings if you want, and then select() would (I assume) say there is input every time a key is pressed.

TaeShadow
06-05-2002, 10:12 PM
Thanks for the input, everyone. I'm going to play with it for a while, and post again if I still can't figure out anything.

Riley
06-09-2002, 09:06 PM
I've never done C sockets in Linux or actually at all, but from C++ socket experience all you have to do is make a listening socket on one thread for the prompt and a listening socket on another thread for the random data. It might be necessary to use different ports though.

Energon
06-09-2002, 11:34 PM
errr... C++ doesn't define any kind of socket interface... only wrappers to C functions...

Stuka
06-10-2002, 11:01 AM
Hey, just started my class on "Concurrent Programming in Unix", and there's a fairly simple solution for this: message queues. Basically, each portion (the client "handler", the client console interface, and the client socket interface) is a separate thread or process. You create a message queue that all 3 use. You can identify messages by type, so that you can prioritize how your "handler" handles the messages, and so each portion can pull only its messages, and pull the critical ones first. This would seem to handle the issues you need handled...