943,616 Members | Top Members by Rank

Ad:
  • C Discussion Thread
  • Marked Solved
  • Views: 2617
  • C RSS
Apr 20th, 2009
0

Chatty Kathy (Chat program in C)

Expand Post »
Good afternoon, all!

I'm in the process of writing a chat program. The server is completed, and if I simply telnet into the server with 2 different windows, 2 people can chat in fluid fashion.

However, when I connect 2 clients, the chat appears in lock-step fashion. (ie. Client 1 types a msg to Client 2, but Client 2 doesn't see the msg until Client2 types a message first.)

Here is a snippet of the code. Any pointers would be great!

And thank you in advance for any assistance!

- Jim

  1. // Open an unbound TCP socket
  2.  
  3. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  4. pdie("Opening stream socket");
  5.  
  6.  
  7. // Prepare for connection to server
  8.  
  9. bzero((char *) &server, sizeof(server));
  10. server.sin_family = AF_INET;
  11. if ((hp = gethostbyname(argv[1])) == NULL)
  12.  
  13. {
  14. sprintf(buf, "%s: unknown host\n", argv[1]);
  15. die(buf);
  16. }//end preparation
  17.  
  18. bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
  19. server.sin_port = htons((u_short) SERVER_PORT);
  20.  
  21. // Establish connection to server
  22.  
  23. if (connect(sock, (struct sockaddr *) &server, sizeof(server)) <
  24. 0)
  25. pdie("Connecting stream socket");
  26.  
  27. // What socket number am I talking on?
  28.  
  29. clientLen = sizeof(client);
  30. if (getsockname(sock, (struct sockaddr *) &client, &clientLen))
  31. pdie("Getting socket name");
  32.  
  33. if (clientLen != sizeof(client))
  34. die("getsockname() overwrote name structure");
  35.  
  36. printf("Client socket has port %hu\n", ntohs(client.sin_port));
  37.  
  38.  
  39. int name = ntohs(client.sin_port);
  40. printf("Now the client name is %d\n\n", name);
  41. gets (msg);
  42.  
  43. while (msg != "q")
  44. {
  45. /* Write out message. */
  46. if (write(sock, msg, sizeof(msg)) < 0)
  47. pdie("Writing on stream socket");
  48.  
  49. /* Prepare buffer and read from it. */
  50. bzero(buf, sizeof(buf));
  51. if (read(sock, buf, BUFFER_SIZE) < 0)
  52. pdie("Reading stream message");
  53.  
  54. printf("User %d says: %s\n", name, buf);
  55.  
  56. gets(msg);
  57. }
  58. close(sock);
  59.  
  60.  
  61. exit(0);
  62.  
  63. }
Reputation Points: 10
Solved Threads: 0
Light Poster
JimD C++ Newb is offline Offline
46 posts
since Oct 2008
Apr 21st, 2009
0

Re: Chatty Kathy (Chat program in C)

Not surprisingly, but your program is doing what you told it to:

  1. // Wait here for the user to enter a message
  2. gets (msg);
  3.  
  4. while (msg != "q")
  5. {
  6. /* Write out message. */
  7. if (write(sock, msg, sizeof(msg)) < 0)
  8. pdie("Writing on stream socket");
  9.  
  10. /* Prepare buffer and read from it. */
  11. bzero(buf, sizeof(buf));
  12. if (read(sock, buf, BUFFER_SIZE) < 0)
  13. pdie("Reading stream message");
  14.  
  15. printf("User %d says: %s\n", name, buf);
  16.  
  17. // Wait here for the user to enter a message
  18. gets(msg);
  19. }

If you're wanting the client to be both waiting for user input and watching for messages from the server (other client) you will need to implement some form of multi-threading.

One implementation might have a thread that supports the socket and the main display of the chat. (It would add lines to the window as they were received or sent.) Another thread would support the user input, it would wait for the user to enter some data (without blocking the other thread) and then send the message the user entered to the other thread for sending to the server and adding to the chat window.

As an alternative to 'actual' multi-threading, you might be able to do something with a 'main loop' that would check for user input and check for socket data repeatedly. Something like the following:
  1. loop forever
  2. if there is user input data available:
  3. if the user input is an 'enter':
  4. if the input buffer contains 'q':
  5. break the loop
  6. send the input buffer
  7. else if the user input is a 'backspace':
  8. if the input buffer is not empty:
  9. remove the last character from the input buffer
  10. else if the user input is a printable character:
  11. add the character to the input buffer
  12. if the socket is closed:
  13. break the loop
  14. if the socket has data:
  15. read the data from the socket
  16. display the data to the user
Reputation Points: 344
Solved Threads: 116
Practically a Master Poster
Murtan is offline Offline
670 posts
since May 2008
Apr 21st, 2009
0

Re: Chatty Kathy (Chat program in C)

You do not need multi-threading for this task.

Your program proceeds in lockstep because your I/O calls are of the "blocking" type and you are calling them without knowing that they are "ready". If they are not ready, they'll wait until something is ready to return. This includes fgets, which waits until the Enter key is pressed to return (line-buffered input).

You have 4 I/O statements in the loop, a simplified version of which appears below (error handling removed):
  1. for ( ; ; ) {
  2.  
  3. gets ( msg ); /* IO_1 */
  4. if ( strcmp ( msg, "q" ) == 0 ) break;
  5.  
  6. write ( ... ); /* IO_2 */
  7.  
  8. read ( ... ); /* IO_3 */
  9. printf ( ... ); /* IO_4 */
  10. }
Instantly, the gets() blocks reading from the terminal, waiting for an Enter keypress. If the other client had sent us a message, we won't see it until we send our message. To fix that you must read the keyboard in a non-blocking manner and yet avoid active polling.

You avoid active polling with the select() function, which will block until one of a given set of file descriptors are "ready". Blocking is good because it means you're not looping and testing (active polling), which is worse than wasteful in a multitasking environment! select() allows you to block on a set of file descriptors, waiting until any one of them is ready. (I don't know how standardized select() is, but it should perform the same basic function on different systems.)

For keyboard input, just read a character at a time using getchar() and respond to the newline character by calling write. The STDIN_FILENO file descriptor would be part of the set passed to select(), so you will know that a character is there to read.
Reputation Points: 163
Solved Threads: 91
Posting Pro in Training
nucleon is offline Offline
476 posts
since Oct 2008
Apr 21st, 2009
0

Re: Chatty Kathy (Chat program in C)

I was forgetting that you've already written the server, so you must know about select (?). In the client, you can try using select the same way, adding STDIN_FILENO to the fds, but it is system dependent whether that will work. If it doesn't, there may be some other system dependent way to do it (like setting it up so a signal is sent every keystroke, interrupting the select).

Alternatively, the threaded solution is actually very clean. The "keyboard" thread reads keys, sending its buffer to the "main" thread (either when enter is pressed or even char by char) which communicates with the server.
Reputation Points: 163
Solved Threads: 91
Posting Pro in Training
nucleon is offline Offline
476 posts
since Oct 2008
Apr 21st, 2009
0

Re: Chatty Kathy (Chat program in C)

I've can't seem to get the select() in the Client to work. I was looking at multithreading in C, but it seems a bit fuzzy to me.

http://softpixel.com/~cwright/progra.../threads.c.php

was one of the places I looked. Maybe I'm making it out to be more difficult than it needs to be?

- Jim
Reputation Points: 10
Solved Threads: 0
Light Poster
JimD C++ Newb is offline Offline
46 posts
since Oct 2008
Apr 21st, 2009
1

Re: Chatty Kathy (Chat program in C)

Basically you just say "start a new thread of execution here". It shares the same address space as your main (or original) line of execution, which can be handy. How about something like this:
  1.  
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/time.h>
  6. #include <pthread.h>
  7.  
  8.  
  9. void*
  10. KeyboardThread (void *unused)
  11. {
  12. printf ("In keyboard thread\nPress Enter...");
  13. getchar();
  14. printf ("Exiting keyboard thread\n:);
  15. return NULL; /* Or pthread_exit(NULL) */
  16. }
  17.  
  18.  
  19. pthread_t
  20. StartKeyboardThread (void)
  21. {
  22. pthread_t thread;
  23. if (pthread_create (&thread, /* Thread id */
  24. NULL, /* Default attributes */
  25. KeyboardThread, /* Thread start routine */
  26. NULL) /* Arg to start routine */
  27. != 0)
  28. {
  29. perror ("StartKeyboardThread");
  30. exit (-1);
  31. }
  32. return thread;
  33. }
  34.  
  35.  
  36. int
  37. main (void)
  38. {
  39. /* To start it */
  40. pthread_t thread = StartKeyboardThread();
  41.  
  42. /* And when you want to kill it */
  43. pthread_cancel (thread);
  44.  
  45. return 0;
  46. }
  47.  
Reputation Points: 163
Solved Threads: 91
Posting Pro in Training
nucleon is offline Offline
476 posts
since Oct 2008
Apr 22nd, 2009
0

Re: Chatty Kathy (Chat program in C)

I finally got the select() syntax right! Thank you all for the wonderful pointers!

After the project is complete, I'd like to go back and try to redo it with the multi-thread idea. That sounds like a lot of fun to learn.

- Jim
Reputation Points: 10
Solved Threads: 0
Light Poster
JimD C++ Newb is offline Offline
46 posts
since Oct 2008

This thread is solved

Either the thread starter or a moderator has marked this thread as solved. You can most likely trust the responses and answers given. There is most likely no reason for any further responses to be posted here. If you have a related question, please start a new thread in this forum instead.

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C Forum Timeline: Hey Im a newbie to C could I get some help with this Program!!
Next Thread in C Forum Timeline: execv() redirection problem





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC