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 array 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?
Related
I'm using this simple echo-server as an example.
It creates a listening connection, receives a packet, sends it back and then closes the connection.
In the initialization function, accept callback is registered in lwip like this:
void
echo_init(void)
{
echo_pcb = tcp_new();
...
echo_pcb = tcp_listen(echo_pcb);
tcp_accept(echo_pcb, echo_accept);
Connection is closed by the server after each echo session, like this:
void
echo_close(struct tcp_pcb *tpcb, struct echo_state *es)
{
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
if (es != NULL)
{
mem_free(es);
}
tcp_close(tpcb);
Documentation says that tcp_close will free pcb structure. All of the callbacks that are used for tcp server are registered with this structure.
But when client sends new packet and starts a new connection, accept callback is called! Even though tcp_accept(echo_pcb, echo_accept); (i.e. callback registration) is done only once in the init function and that echo_pcb structure is already freed after tcp_close.
So I'm confused. Why all the other callbacks are registered multiple times but accept is registered only once? Is it okay to do it like this?
Okay, so according to this answer to the same question on the lwip mailing list, that is correct behaviour. tcp_accept registers callback for a port and it won't be unregistered when tcp_close is called.
I have to program a little game for a course in C and it has to be done with using shared-memory, semaphores and a client/server architecture which can handle multiple clients (the exact requirement for the game is 2).
The two clients need to do their turns in turns and they are represented by the very same program (no fork() involved here - both started with ./client)
The server has to create all the resources when it starts up. So my main problem is regarding the semaphores. (The shared memory and the game-logic stuff works or isn't really difficult to implement.)
To decide if the server or a client has access to the shared-memory I need one semaphore. I need a second one to decide which of the clients has access. Am I right?
So I got a hint that it could be done with assigning IDs to the clients. So the shared-memory has three additional variables like so:
struct game
{
int id_needed, client_id, id_ready;
... // additional stuff that is needed for the game logic itself
};
As the server boots up I'm initializing one semaphore to be 0 and the other one to be 1.
When the first client appears it checks if his ID is still 0 (it's initialized as zero)
If so, it tries this:
while(my_id == 0)
{
if(semaphore_down(semaphore_1) == 0) // Check if I have access to shared mem
{
shared_memory->id_needed = 1;
if(shared_memory->id_ready == 1)
{
my_id = shared_memory->client_id;
(void) printf("DEBUGGING: My ID is %d\n", my_id);
}
}
}
shared_memory->id_needed = 0;
And in the server I do ...
while(1)
{
if(shared_memory->id_needed = 1)
{
(void) printf("DEBUGGING: ID is needed for another client!");
shared_memory->client_id++;
shared_memory->id_ready = 1;
(void) printf("DEBBUGING: Dispatched new ID: %d", shared_memory->client_id);
}
// If enough players, start the game ...
}
I'm really stuck here. The server just increments the ID (which is only logical), but I'm stuck as to resolve this problem.
I just want the clients to work alternately on the shared-memory and the server to check the values of the game etc.
I've never worked with semaphores before and all the documentation or examples I find do just work with one client and one server, but never multiple clients.
Please enlighten me!
I see one strange thing and two things that obviously are mistakes here
I see semaphore_down but no semaphore_up in the code you showed
you assign instead of comparing: if(shared_memory->id_needed = 1)
even if it was a comparison, it was not right anyway since compiler was free to optimize it out. Make this variable volatile to hint compiler that variable can change outside of the serial code flow. Or better declare it atomic.
Hi I am figuring out a way to listen to a socket and connect to a different socket(on same ip but different port number) simultaneously in the same program.when I listen to a socket then it keeps blocking until it receives some message so I am not able to listen and connect simultaneously.
I actually need to simulate exchange of LSP packets between different routers. So I am writing a program to simulate a router so as to run it n(number of routers)times.
Could anyone please share on how to proceed ??
If I understood your problem correctly, one of these might help.
Multi-thread or Multi-process
Basically, when you receive a client you can process a client separately in a separate thread or in a new process. You will be able to receive incoming connections and connect to new clients from other sources while processing the ones who are already connected.
Pseudo Code:
main() {
while(1) {
accept client
/*
After the fork or creation of the new thread, the loop goes back to
accepting clients while connected clients are being processed.
*/
fork or create new thread passing and client socket to it
}
}
processClient() {
do whatever you need to do...
}
Select
Select is another good way of doing non-blocking sockets. Select basically waits for data to come (ie. data, new client requests) to the server and processes them one-by-one. The server will not block on accept as it will wait until it receives something before processing it.
Psuedo Code:
main() {
while(1) {
wait on select
if new client {
accept it
}
for client in clients {
if client has data {
process it
}
}
}
}
ePoll (if you're in Linux)
ePoll is similar to Select only it can handle WAY more clients and it's a lot sexier.
Here's a repo that has each of those. My code isn't perfect here as it was a project that I did while in school.
https://github.com/koralarts/ServerBenchmarking
Iam looking to write a socket program based on libev. I noticed that several examples as stated in https://github.com/coolaj86/libev-examples/blob/master/src/unix-echo-server.c use the call backs based on init. For example,
main() {
......
ev_io_init(&client.io, client_cb, client.fd, EV_READ|EV_WRITE);
ev_io_start(EV_A_ &server.io);
}
static void client_cb (EV_P_ ev_io *w, int revents)
{
if (revents & EV_READ)
{
....
} else if (revents & EV_WRITE) {
......
}
}
My question comes from the expected behaviour, say for example, all that i read when in EV_READ is stored in a linked list. Lets say I keep getting free flow of packets to read, will i ever get a chance to get into EV_WRITE? I have to send out all that I recv through read to another socket. So Will it be once EV_READ and second time EV_WRITE? In other words when will EV_WRITE be unblocked? Or do I need to block EV_READ for EV_WRITE to be called. Can someone help me understand this?
I think you should keep write callback separated from read callback:
main() {
ev_io_init(&read.io, read_cb, client.fd, EV_READ);
ev_io_init(&write.io, writead_cb, client.fd, EV_WRITE);
ev_io_start(EV_A_ &read.io);
ev_io_start(EV_A_ &write.io);
}
This is my solution.
To answer shortly: If you allways check for one type of event first and then have an else
if for the other you risk starvation. In general I would check for both, unless the specified protocol made it impossible for both to be activated at the same time.
Here is a more iffy answer:
The link in your question does not contain a code structure such as your question. The client https://github.com/coolaj86/libev-examples/blob/master/src/unix-echo-client.c does have a similar callback. You will notice it disables write events, when it has written once.
// once the data is sent, stop notifications that
// data can be sent until there is actually more
// data to send
ev_io_stop(EV_A_ &send_w);
ev_io_set(&send_w, remote_fd, EV_READ);
ev_io_start(EV_A_ &send_w);
That looks like an attempt to avoid starvation of the pipe READ event branch. Even though Im not very familiar with libev, the github examples you linked to do not seem very robust. E.g static void stdin_cb (EV_P_ ev_io *w, int revents)does not use the return value of getline() to detect EOF. Also the send() and recv() socket operation return values are not inspected for how much was read or written (though on local named pipe streams the amounts will most likely match the amounts that were requested). If this was later changed to a TCP based connection, checking the amounts would be vital.
For an application in C, i need to response more than one clients.
I setup the connection with a code like,
bind(...);
listen(...);
while(1){
accept(...);//accept a client
recv(...);//receive something
send(...);//send something to client
bzero(buf);//clear buffer
}
This works great when i have only one client. Other clients also can connect to the server but although they command something, server does not response back to clients who connected after the first client. How can i solve this problem?
Write a server using asynchronous, nonblocking connections.
Instead of a single set of data about a client, you need to create a struct. Each instance of the struct holds the data for each client.
The code looks vaguely like:
socket(...)
fcntl(...) to mark O_NONBLOCK
bind(...)
listen(...)
create poll entry for server socket.
while(1) {
poll(...)
if( fds[server_slot].revents & POLLIN ) {
accept(...)
fcntl(...) mark O_NONBLOCK
create poll and data array entries.
}
if( fds[i].revents & POLLIN ) {
recv(...) into data[i]
if connection i closed then clean up.
}
if( fds[i].revents & POLLOUT ) {
send(...) pending info for data[i]
}
}
If any of your calls return the error EAGAIN instead of success then don't panic. You just try again later. Be prepared for EAGAIN even if poll claims the socket is ready: it's good practice and more robust.
i need to response more than one clients.
Use Threading.
Basically you want your main thread to only do the accept part, and then handle the rest to another thread of execution (which can be either a thread or a process).
Whenever your main thread returns from "accept", give the socket descriptor to another thread, and call accept again (this can be done with fork, with pthread_create, or by maintaining a thread pool and using synchronization, for instance condition variables, to indicate that a new client has been accepted).
While the main thread will handle possible new clients incoming, the other threads will deal with the recv/send.