C sockets - keeping pool of connections for reuse - s - c

I am writing a two daemon application - a client and a server. It is a very basic version of distributed shell. Clients are connecting to the server, and server issues a command, that is propagated to every client.
I dont know how to create the socket logic on server-side - I do some testing and for now I am accepting connections in an loop and for every incoming connection I fork a child to process the connection
while (1) {
clisockfd = accept(sockfd, (struct sockaddr *) &cliaddr, &clilen);
if (clisockfd < 0) {
log_err("err on opening client socket");
exit(EXIT_FAILURE);
}
/* create a new child to process the connection */
if((pid = fork()) < 0) {
log_err("err on forking, something is really broken!");
exit(EXIT_FAILURE);
}
if(!pid) {
/* here we are in forked process so we dont need the sockfd */
close(sockfd);
/* function that handles connection */
handle_connection(clisockfd);
exit(EXIT_FAILURE);
} else {
close(clisockfd);
}
}
However what I have now have some disadvantages - I can accept a connection, do something with it, and return to main process (forked process have to return, and then execution in main process is resumed). I would like to keep every socketfd somewhere(a list?) and be able to choose one of those (or all of them) and send to this socketfd a command that I want to issue on my client/s. I assume that I cant do it in traditional accept->fork->return to main process manner.
So it probably should looks like:
client connects -> server set up a new socketfd and saves it somewhere -> drops to shell where I can choose one of socket and send it a command -> somewhere in the whole process it also should wait for next incoming client connections - but where?
If someone could give me an idea what mechanisms should I use to create the logic that I need? Maybe it would be better to issue connection from server to client, not from client to server.
Regards,
Krzysztof

I assume that I cant do it in traditional accept->fork->return to main process manner.
You could but it will be hard to design/maintain.
The best solution is to use select() (POSIX), epoll() (Linux), kqueue() (BSD) or I/O Completion Ports (Windows) depending on your platform.
There is a good examples/explanations about select() in Beej's network programming guide.

Related

C web server using threads on windows

I started writing a c web server a while ago (windows 8), but I tried using only threads by myself, without using the select() option.
This is my main loop, and I'm opening each new thread like this:
uintptr_t new_thread;
while (client_sock = accept(server->sock, (struct sockaddr *)&client_info, &size))
{
if (client_sock <= 0) quit();
printf("\n[***] : Got a connection from localhost on port %d\n",ntohs(client_info.sin_port));
code = init_connection(client_sock);
if (code)
{
new_thread = _beginthread(handle_connection, 0, ID++, client_sock);
if (new_thread == -1)
{
fprintf(stderr, "Could not create thread for sending data: %d\n", GetLastError());
closesocket(client_sock);
quit();
}
}
else
{
debug("Failed to init connection");
closesocket(client_sock);
debug("Connection to client ended");
}
}
First of all, I would love to here if I can make this code better.
Testing this program by trying to enter the localhost from chrome, I see that no more data is sent (after recieving one http request).
My question is what would be the best way for the program to act then: close the thread and when another request will be made it will open a new one? if so, how do I close that thread? if not, when should I close that thread?
Normally, when implementing a server that forks separate processes, I would make the child process stay alive to serve predefined amount of requests (e.g. 100) and then kill itself. This is to reduce overhead created by forking and on the other hand recover from possible memory leaks or other problems in the process. Threads are lighter than processes, so it may make sense to close them faster.
I think you should compare the benefits and drawbacks. Measure the overhead of thread creation and closing compared to keeping them alive. In any case you must make sure that there is limit on the number threads you have alive at one time.
About the windows specifics on creating ans closing the thread you could go and add e.g. this response.

Socket Programming - Multiple connections: Forking or FD_SET?

I'm trying to understand the different practices when it comes to socket programming and handling multiple connections.
In particular when a server needs to serve multiple clients.
I have looked at some code examples; where some use fd_set and others use a fork() system call.
Roughly:
FD_SET
//Variables
fd_set fds, readfds;
//bind(...)
//listen(...)
FD_ZERO(&fds);
FD_SET(request_socket, &fds);
while(1) {
readfds = fds;
if (select (FD_SETSIZE, &readfds, NULL, NULL, NULL) < 0)
//Something went wrong
//Service all sockets with input pending
for(i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET (i, &readfds)) {
if (i == request_socket) {
/* Connection request on original socket. */
int new;
size = sizeof (clientname);
new = accept (request_socket, (struct sockaddr *) &clientname, &size);
if (new < 0)
//Error
fprintf (stderr, "Server: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port));
FD_SET (new, &fds);
}
else {
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0) { //handles queries
close (i);
FD_CLR (i, &fds);
}
}//end else
fork()
//bind()
//listen()
while(1) {
//Connection establishment
new_socket = accept(request_socket, (struct sockaddr *) &clientaddr, &client_addr_length);
if(new_socket < 0) {
error("Error on accepting");
}
if((pid = fork()) < 0) {
error("Error on fork");
}
if((pid = fork()) == 0) {
close(request_socket);
read_from_client(new_socket);
close(new_socket);
exit(0);
}
else {
close(new_socket);
}
}
My question is then: what is the difference between the two practices (fd_set and fork)? Is one more suitable than the other?
You would choose between one of the two approaches, select() or fork() based on the nature of the IO operations you have to do once you receive a connection from a client.
Many IO system calls are blocking. While a thread is blocked on IO performed for one client (e.g. connecting to a database or server, reading a file on disk, reading from the network, etc.), it cannot serve the other clients' requests. If you create a new process with fork(), then each process can block independently without impeding progress on the other connections. Although it may seem advantageous to start a process for each client, it has drawbacks: multiple processes are harder to coordinate, and consume more resources. There is no right or wrong approach, it is all about trade-offs.
You may read about "events vs threads" to understand the various tradeoffs to consider: See: Event Loop vs Multithread blocking IO
The select() system call approach (which you've called the FD_SET approach), would generally classify as a polling approach. Using this, a process can wait on multiple file descriptor events at once, sleep there, and be woken up when activity arises on at least one of the file descriptors specified in the FD_SET. You may read the man page on select for details (man 2 select). This will allow the server process to read from the multiple clients bit by bit (but still one at a time), as soon as new data arrives on any socket of interest.
Trying to call read() on a socket that has no data available would block -- select just makes sure you only do it on those that have data available. It is generally called in a loop so that the process comes back for the next piece of work. Writing the program in that style often forces one to handle requests iteratively, and carefully, because you want to avoid blocking in your single process.
fork() (man 2 fork) creates a child process. Child processes are created with a copy of the file descriptors open in the parent, which explains all the fd-closing business when the system call returns. Once you have a child process to take care of the client's socket, then you can write straightforward linear code with blocking calls without affecting the other connections (because those would be handled in parallel by other child processes of the server).
The main difference between the two practices is the number of processes used to handle multiple connections. With select, single process (in fact a single thread) can handle concurrent connections from multiple clients. When we use the fork based approach, a new process is created for every new connections. So if there are N concurrent client connections, there will be N processes to handle those connections.
When we use select, we don't need to worry about shared memory or synchronization as everything is happening within the same thread of execution.
On the other hand, when we use select, we need to be more careful while coding as the same thread of execution is going to handle multiple clients. In fork based approach, the child process has to handle only a single client so it tends to be bit easier to implement.
When we use fork based approach, we end up using more system resource as a result of creating more processes.
The choice of approach depends on the application - expected number of connections, the nature of connections (persistent or short duration), whether there is a need to share data among connection handlers etc.

Why do we need to create different processes for each client in a concurrent server in C?

I was working on a simple client server program, with the intention of creating a chat program. I am new to socket programming in C. I have learnt that, to serve multiple clients, the server needs to fork a new process each time a client connects. Each time a client requests connection, the accept() function returns a descriptor id and after the fork() the parent closes the id.
Instead I didn't close the ID, such that each new client will get a newid, when accept() is invoked.
nsockfd = accept(lsockfd, (struct sockaddr *) &cli_addr, &cli_len);
now this is stored in 2 variables:
if (client1 < 0)
{ client1 = nsockfd;
printf("if loop %d\n",nsockfd);
}
else
{ client2 = nsockfd;
printf("else loop %d\n",nsockfd);
}
Now rest of code is
snprintf(buf, sizeof(buf), "Hi client1 Nice to meet you.",inet_ntoa(cli_addr.sin_addr));
ret = send(client1, buf, strlen(buf), 0);
if (ret == -1) {
perror("Error sending message");
exit(1);
}
printf("SRV - %s\n", buf);
strcpy(buf,"");
snprintf(buf, sizeof(buf), "Hi client2 Nice to meet you.",inet_ntoa(cli_addr.sin_addr));
if(client2 > 0)
{ret = send(client2, buf, strlen(buf), 0);
if (ret == -1) {
perror("Error sending message");
exit(1);
}
printf("SRV - %s\n", buf);
strcpy(buf,"");
Here the code is working as intended; each client prints only one of the statements.
If this is a flawless method, why is it taught that fork() should be used for serving each client.
I am working on a localhost? Is this the reason that this code is working for me?
It isn't a concurrent server if you don't either fork() or process the connection in a (new?) thread. That's the definition of a concurrent server.
If I'm reading your code correctly, what you've got is a simple sequential server. It can only process one connection at a time. That's fine if the computation required for each response is minimal, as in your example. It's not so good if the computation involves a lot of effort — access disk or database, for example.
Note that a sequential server design is completely legitimate. So too is a concurrent server design. They should be applied to different workloads. Generally, though, a concurrent server will handle large traffic volumes better than a sequential server. Imagine if Google used sequential servers for responding to search requests!
Another design uses a thread pool or process pool with one thread or process farming out the work to other threads or processes. These are trickier to write so they work well.

client/server architecture with multiple clients

I need to implement a server/client code in C.
Server needs to be able to accept exactly four connections at the time.
I can't get this working. What I've done so far:
1. create a socket
2. set it to non-blocking: fcntl(sock,F_SETFL, O_NONBLOCK);
3. bind it
4. listen: listen(sock, 4);
The part which I am not quite sure about is how to accept the client's connection. My code looks something like this:
while (1) {
if ((sockfd = accept(sock, (struct sockaddr *) &client_addr, &client_size)) < 0) {
perror("Error\n");
}
read(sockfd, &number, sizeof(number));
write(sockfd, &number, sizeof(number));
}
When I execute client and server code, client seems to be writing something to the socket, which server never receives and the entire execution blocks.
What is the proper way to accept connections from multiple clients?
One basic workflow for this kind of server, if you don't want to use multithreading, is like this:
Create an fd_set of file descriptors to watch for reading
Open a socket
Bind the socket to a port to listen on
Start listening on the socket
Add the socket's file descriptor to the fd_set
While not done
Use select to wait until a socket is ready to read from
loop through the fds in your fd_set that have data available
If the current fd is your listening socket, accept a new connection
Else, it's a client fd. Read from it, and perhaps write back to it.
This page shows a flowchart of the above process. (Scroll down for a very nicely annotated example.)
This page is chock full of examples for select.
You should look the man of select. It will tell you when and which sockets are ready to write/read

Accept multiple subsequent connections to socket

I have a listener that will pass arbitrary data, HTTP requests, to a network socket which is then delivered over TCP. This works fine for the first request but the listener does not accept subsequent new requests.
My question is:
If I have sock=accept(listener,(struct addr *)&sin, &sinlen); then, based on the socket function reference, the listener socket remains open and I should be able to re-call accept() any number of times for subsequent requests. Is this correct? If so, can someone more familiar than I with socket programming please explain how this code might look?
Yes, you can accept() many times on the listening socket. To service multiple clients, you need to avoid blocking I/O -- i.e., you can't just read from the socket and block until data comes in. There are two approaches: you can service each client in its own thread (or its own process, by using fork() on UNIX systems), or you can use select(). The select() function is a way of checking whether data is available on any of a group of file descriptors. It's available on both UNIX and Windows.
Here is a simple example from Beej's Guide to Network Programming.
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
The child process — after the fork() — handles the communication asynchronously from accept()ing further connections in the parent.
Yes, you have the right general idea.
While my C socket programming is a bit rusty, calling accept on a server socket sets up the communications channel back to the client side of the socket. Calling accept on future connection attempts will set up multiple socket channels.
This means that one should take care to not overwrite a single shared structure with a specific connection's data, but it doesn't sound like that's the kind of error you would be prone to make.

Resources