Threads in a client/server program
For college, I am developing a local relay chat. I have to program a chat server and client that will only work on sending messages on different terminal windows on the same computer with threads and FIFOs.
The FIFOs part I am having no trouble, the threads part is the one that is giving me some headaches.
The server has one thread for receiving commands from a FIFO (used by all clients) and another thread for each client that is connected.
For each client that is connected I need to know a certain information. Firstly, I was using global variables, which worked as longs as there was only one client connected, which is much of a chat, to chat alone.
So, ideally I would have some data like:
-nickname
-name -email -etc...per client that is connected. However, I don't know how to do that.
I could create a client_data[MAX_NUMBER_OF_THREADS] where client_data was a struct with everything I needed to have access to, but this would require to, in every communication between server and client to ask for the id of the client in the arra开发者_如何转开发y client_data and that does not seem very practical
I could also instantiate a client_data immediately after creating the thread but it would only be available in that block, and that is not very practical either.
As you can see I am in need of a little guidance here. Any comment, piece of code or link to any relevant information is greatly appreciated.
I don't know what language you're using but here are some basic ideas:
- Start your server in a thread (possibly your main thread).
- The server's while loop will block on accepting a socket connection.
- When the socket connection is accepted it should spawn a new thread to handle the connection.
- Start communicating with the client in the new thread.
A simple socket server loop looks like this (in Java):
while(true){
ClientWorker w;
try{
//server.accept returns a client connection
w = new ClientWorker(server.accept(), textArea);
Thread t = new Thread(w);
t.start();
} catch (IOException e) {
// log the exception or something...
}
}
If you're wondering what it does- the ClientWorker
is available here. In C# if you're creating a new Thread
don't forget to set its IsBackground
property to true
so the thread closes when your app shuts down, i.e. no hanging threads.
Remember: accepting a socket connection or receiving data from a socket is usually a blocking call, which means that your thread will block until somebody connects to the socket or data comes through the socket.
In C#:
- The Chat Client: http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html
- The Chat Server: http://www.geekpedia.com/tutorial240_Csharp-Chat-Part-2---Building-the-Chat-Server.html
- A Basic Client/Server: http://www.dreamincode.net/forums/topic/33396-basic-clientserver-chat-application-in-c%23/
In Java:
- Chat Client/Server: http://pirate.shu.edu/~wachsmut/Teaching/CSAS2214/Virtual/Lectures/chat-client-server.html
- Nakov Chat Client/Server: http://inetjava.sourceforge.net/lectures/part1_sockets/InetJava-1.9-Chat-Client-Server-Example.html
In C++
- On Code Project: http://www.codeproject.com/KB/cpp/chat_client_server.aspx
- Another Code Project TCP/IP chat client/server: http://www.codeproject.com/KB/IP/ipchat.aspx
Update
Instead of doing global variables, just define a struct
for the client account and declare an account variable for each user... here is how you can define the account information:
struct account {
char nickname[32];
char first_name[32];
char last_name[32];
char e_mail[32];
char password[32];
};
When the client sends a message it should have a standard format: FROM|TO|CONTENT
struct message{
char nickname_from[32];
char nickname_to[32]; // optional
char msg_content[256];
};
Put each message
on the fifo [queue] and you will have all the information you need to identify who sent it.
Here is some psuedo code that might actually almost run. Note, I'm not freeing what I allocate, I'm not checking errors, I'm just trying to demonstrate how to pass a structure to a thread and use a simple mutex.
There is one thing to be careful of, The function pointer for threads specifies a void *
argument, which could be literally any kind of type. In the thread, we assume that its safe to cast the thread argument to a type that we've defined for use. If you are passing multiple possible types, you have to be careful :)
I'm not quite sure about the structure of your program, or how you are handling threads, but here's a short approach-agnostic example on how to pass data to them:
typedef struct client {
char *firstname;
char *lastname;
char *email;
char *nickname
} client_t;
pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
void *client_thread(void *threadarg)
{
client_t *client = (client_t *) threadarg;
pthread_mutex_lock(&client_lock);
/* read and write to client structure */
pthread_mutex_unlock(&client_lock);
/* do some other stuff */
pthread_exit(NULL);
}
int main(void)
{
client_t *client;
pthread_t cthread;
client = (client_t *)malloc(sizeof(struct client));
if (client == NULL)
return 1;
client->firstname = strdup("Joe Public");
/* set the rest of the data */
pthread_create(&cthread, NULL, (void *)client_thread, (void *)client);
/* join / detach / etc */
/* Free all the structure members and the structure itself */
return 0;
}
I'm pretty sure this is what you were asking?
精彩评论