views:

89

answers:

5

I am writing a chat program for my networking class and I have all the networking setup perfectly.

My problem is if a client is currently writing a message and he receives a message from a different client then his current input gets displayed with the received message.

For example if a client is writing a message "Hi there how are you?" and receives a message "Good day to you!" while in the middle of writing their message it gets displayed as:

Hi there hoGood day to you!

->w are you?

Where -> is the area for the user to type in the message. What I would like to happen is to just display the message received and have the area -> retain all the previous text that was written before the message was received.

Please make note that what the client is typing in is still in fact "there" when he receives a message. If he completes his message his full message will be sent.

Also note that my client uses pthreads. One thread to read messages from the server and display them to the users screen and one thread to read from stdin and send the messages to the server. I do believe that my problem is arising because I am using pthreads and the threads share the same stdin, stdout, stderr. Maybe this is a misconception and wrong?

I hope I have been clear on my problem. If not, sorry. Please let me know what I can clarify for you.

I started doing some research and came upon these links:

I was thinking about trying to go up lines and move the cursors around and stuff, but don't know if that is the most effective way to do so. Firstly because I don't know how to capture the information that is in the terminal waiting to "entered"/sent to stdin. Maybe I just haven't found out how to do that.

Also I was wondering if there was a way to work/manipulate file descriptors to solve the problem? Maybe that wouldn't even solve it?

Thanks for reading and your time. I appreciate all your help.

+4  A: 

Using a library such as curses to manage text 'windows' will be easier than trying to manipulate the screen by hand.

Trent
This is the best way. You want to keep a variable representing the position of the end of the received text, which will tell you where to insert new messages. The sequence should be something like:1) stop responding to user keypresses2) grab existing user input3) clear the user input4) insert the new message5) record where the end of that message is6) re-insert user input7) act on any buffered input recived while inserting the message
Justin Smith
+1  A: 

I am not an expert in unix network programming, but I am pretty much convinced that the problem is with multithreading itself rather than some stdin/stdout quirks.

What I see here is multiple threads accessing the same resource (terminal session) without any synchronization. This inevitably leads to race conditions between them.

I would recommend you to read this free e-book on sychronization problems, which is especially helpful for those who are only slightly familliar with sychronization:

http://www.greenteapress.com/semaphores/

catbert
A: 

Designate a thread as the IO thread and sent the messages to be displayed to that thread through a blocking queue (or circular buffer). Does C have those? (I use Java currently).

Seun Osewa
A: 

The problem involves threading. Your solutions are to either use one display and block the incoming message until the user finishes with the current input or use two "windows". Many conversation programs have two windows: one for incoming data (or the current conversation) and another to build the next message.

The standard C language does not have facilities for threading, windowing or cursor positioning. You'll just have to use platform specific features. Since you didn't specify your platform, you will have to look these up yourself.

Thomas Matthews
A: 

By default user input is handled by the terminal itself, so a mutex alone wouldn't cut it if you want real-time updates. If you wanted a line-input mode solution you could log incoming messages and commit them every time a message is sent and before the next one is read.

Else, your best bet would be using curses as suggested. A scrollok(3x) enabled window can be used like a terminal easily using waddstr(3x) and wgetnstr(3x), no need to micromanage that if you use an IRC-like UI.

Note that using curses doesn't mean you don't have to use a mutex around your curses functions. Else, when you less expect it the screen will become full of garbage.

jbcreix