Thread: Multithreaded Webchat-Server

  1. #1
    Registered User
    Join Date
    May 2002
    Posts
    41

    Smile Multithreaded Webchat-Server

    Hello!

    This is my first post here, I hope I don't do anything wrong.
    I'm currently working on a webchat for my website. In the past I tried a lot of different solutions but all either where using too much bandwith, too much CPU ressources or where simply too slow. Java applets are no alternative IMO. I knew that streaming chatservers would probably do the trick but I didn't have a lot of C knowledge (and I still don't). I tried creating a chatserver in Perl, but they either took almost as much ressources as CGI scripts (a forking server) or crashed all the time (a selective server). The answer seemed to be multithreading but no good thread support for Perl. :/ So I gave up, because I didn't have my own server anyway.

    Now I'm back with a dedicated webserver I have access to and started thinking about this idea again, because more than 70% of my visitors want a webchat.

    I had an idea. Instead of coding the whole chat in C (which would be a PITA for me especially because C probably isn't the most friendly language for string manipulation and dynamic webpages), I'm going for a mixed solution.
    The chatserver (in C) will do nothing but serve connected chatters with a chatstream. The input and everything else will be handled by PHP scripts. I searched google and found a freeware (GPL) multithreaded webserver. It wasn't difficult to manipulate this server to send persistant streams to connected clients. Only downside of this server is though, that it is a little bit more complex than I need. It's spawning a lot of worker threads to server requests as fast as possible. Of course this isn't usefull if every connection is persistant anyway. Also the problem is that it doesn't accept new connections when all worker threads are used. :/ I will try to change that later to a simple server that does spawn one thread per connection. It would be cool if someone could show me some example code for this. But for now I just spawn enough worker threads to handle a lot of chatters and this works for testing...
    I wanted to use MySQL for storing the chatdata but faced a problem of course. When all threads would poll the database constantly, the load would be unacceptable. So I had an idea. I just spawned another thread that is doing all the polls (once a second) and serves the result to connected clients. To make this possible, every client "registers" itself in a "chatter" structure array and the polling thread checks all elements of this array for connected chatters to send the messages to.
    To my big surprise, this even worked! I can already connect with serveral clients to this server, type something at one client and a second later it's on the screen of all clients. The load is almost non-existant and the delay is at most one second (because of the 1 second intervall of the polling thread). I'm really proud of this. I shared all those details because I thought other people might also be interested in doing something like this (although many serious hackers dislike the idea of webchats in favor of IRC, etc, those are extremely popular).

    I also hope that some of you can assist me a little bit.
    I have mainly two big problems to face yet.

    1) Convert this to "one-thred-per-connection" to allow unlimited numbers of connections without pre-spawning threads.
    I would be really really happy to find some tutorial or example script about this.

    2) Detect when a client is disconnected. Atm, every client who connects gets a new slot (there are 1000 of them so far) and then goes in an endless loop (also with a sleep(1) to make it easy on the server) and accepts new data from the polling thread. This never stops. And I have no clue how to find out if the client is still accepting data (connected). Can anyone give me some hints?
    The loop currently looks something like this:
    Code:
    	while(connected) {
    		// check the buffer for new text to send
    		if (strlen(chatter[myid].buffer) > 0) {
    			sprintf(sendbuf, "%s", chatter[myid].buffer);
    			sprintf(chatter[myid].buffer, "");
    			if(!write(sock, sendbuf, strlen(sendbuf)))
    				connected = 0; // doesn't work (never happens)
    		} 
    		sleep(1);
    	}
    I would really appreciate any help!
    If someone wants to see the code, I could upload it.

    My last problem is a minor one. Or more something like a question. ATM, my chatter struct array is a fixed array of 1000 elements. Of course I would prefer a dynamic array to support unlimited chatters. Do you think that's a good idea?
    And let's say 30 chatters connected, so the array got 30 elements long, suddenly client number 15 disconnects. Can I remove element 15 and reduce the length to 29 elements again (shifting element 16-30 to 15-29) without too much overhead (it would have to be changed all the time)?
    I fear I'm still a complete newbie in C.

    TIA
    Sorry for the long text...

    Spark

  2. #2
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Hi, and welcome!

    I can offer some pointers in answer to your questions:

    >if(!write(sock, sendbuf, strlen(sendbuf)))
    > doesn't work (never happens)
    Of course it doesn't trap properly , if there's an error doing the write, -1 is returned by write(). You'll need to modify your test. Also, it might write only some of the data, not all. If this happens you need to decide if you're going to resend the remaining bytes or just discard them. But for now:
    Code:
    if write(sock, sendbuf, strlen(sendbuf)) == -1)
       /* Handle error */
    If successful, write() returns a the number of bytes actually written. Otherwise, (-1) is returned and errno is set to indicate the error.
    >Convert this to "one-thred-per-connection" to allow unlimited numbers of connections without pre-spawning threads
    You can spawn a new process each time you receive a connect on a file descriptor if you want. There's no pre-spawning there. Or, if you only want one app running, you could malloc all that is needed to hold a new connection as one comes in, then store all the information in a list or tree.

    As for you chatter structures, you need a dynamic list of some sort: link list or binary tree. There's plenty of code around, have a search, but if you get stuck let us know.

    Any of this help?
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  3. #3
    Registered User
    Join Date
    May 2002
    Posts
    41
    Thanks.

    > Of course it doesn't trap properly , if there's an error doing the write, -1 is returned by write().

    Ok, I did that. Unfortunatly it still doesn't detect a disconnect. :/ It seems that the webbrowser doesn't really close the connection when I click on stop or close the window. Too bad. :/ Maybe I'll just have to do it the "old" way and have a timeout.


    > You can spawn a new process each time you receive a connect on a file descriptor if you want.

    That's basically what I want but with a new thread instead of a new process. Unfortunatly I don't understand much of the threading part of the webserver I used as a base so I can't easily change it. So I'm looking for a more simple threading server example that actually starts a new thread for each connection.

    The code I'm working on does it like this:
    Code:
    	while(1) {
    		node *n = Malloc(sizeof(node));
    		clntsock = accept(servsock, NULL, NULL);
    		if( clntsock < 0 )
    			die("accept() failed");
    		++requests;
    		pthread_mutex_lock(&mutex);
    		/********** CRITICAL SECTION ************/
    		n->sock = clntsock;
    		nq(n);
    #ifdef DEBUG
    		fprintf(stderr, "MTHTTPD: requests pending: %d\n", q_size);
    #endif
    		/********** END CRITICAL SECTION ********/
    		pthread_mutex_unlock(&mutex);
    		for(i=0; i < requests; i++)
    			pthread_cond_signal(&work_to_do);
    		requests = 0;
    	}
    And I don't understand anything.


    > As for you chatter structures, you need a dynamic list of some sort: link list or binary tree. There's plenty of code around, have a search, but if you get stuck let us know.

    Ok thanks. I wasn't sure if a dynamic array or a linked list would be the right thing. So I will read up on linked lists, no problem (I hope ).

    Spark

  4. #4
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Also, you might find the document here useful. Its a socket programming intro, including multi-user chat server code (explained).
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Server Architecture
    By coder8137 in forum Networking/Device Communication
    Replies: 2
    Last Post: 01-29-2008, 11:21 PM
  2. Where's the EPIPE signal?
    By marc.andrysco in forum Networking/Device Communication
    Replies: 0
    Last Post: 12-23-2006, 08:04 PM
  3. Multithreaded server, where to start?
    By Ichmael™ in forum Windows Programming
    Replies: 1
    Last Post: 02-26-2006, 01:17 AM
  4. IE 6 status bar
    By DavidP in forum Tech Board
    Replies: 15
    Last Post: 10-23-2002, 05:31 PM
  5. socket question
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-19-2002, 01:54 PM