f



TCP server in C

Hi guys,

At comp.lang.c suggested me to drop this question here:

I have created multiprocess tcp server, code is here ->

http://pastebin.com/8M0kBD2X

In general, server is waiting for buffer from Client and answering with 
its own buffer.

So I have compiled server and client code. Server is started, and I have 
created 10 Client instances by running command below:

for a in {1..10}; do echo "$a";./client & done

The problem is that server produces following output:
--------------
../server_fork2
Socket created.
Binding to port 8000
Received message: Client is sending message.
  Message sent: Server is sending message.
Could not create client socket!Received message: Client is sending message.
  Message sent: Server is sending message.
Could not create client socket!Received message: Client is sending message.
  Message sent: Server is sending message.
Could not create client socket!Received message: Client is sending message.
  Message sent: Server is sending message.
--------------

I simply do not know if I have put close(client_socket) (in code -> 
close(c)) in correct place.

Additionally, can you tell me how to avoid "unable to fork" issue by 
limiting number of child processes?

Best regards,
Marcin
0
Mr
10/29/2016 9:28:04 AM
comp.unix.programmer 10848 articles. 0 followers. kokososo56 (350) is leader. Post Follow

4 Replies
554 Views

Similar Articles

[PageSpeed] 10

"Mr. Wrobel" <mr@e-wrobel.pl> writes:

> At comp.lang.c suggested me to drop this question here:

I was abut to reply but I see (from a post in comp.lang.c) that you've
fixed it.  Often the way -- just a bit of time is often all you need.

<snip>
-- 
Ben.
0
Ben
10/29/2016 12:54:57 PM
W dniu 29.10.2016 o 14:54, Ben Bacarisse pisze:
> "Mr. Wrobel" <mr@e-wrobel.pl> writes:
>
>> At comp.lang.c suggested me to drop this question here:
>
> I was abut to reply but I see (from a post in comp.lang.c) that you've
> fixed it.  Often the way -- just a bit of time is often all you need.
>
> <snip>
>
Thanx ;-)
0
Mr
10/29/2016 1:41:03 PM
"Mr. Wrobel" <mr@e-wrobel.pl> writes:

[...]

> The problem is that server produces following output:
> --------------
> ./server_fork2
> Socket created.
> Binding to port 8000
> Received message: Client is sending message.
>  Message sent: Server is sending message.
> Could not create client socket!Received message: Client is sending message.
>  Message sent: Server is sending message.
> Could not create client socket!Received message: Client is sending message.
>  Message sent: Server is sending message.
> Could not create client socket!Received message: Client is sending message.
>  Message sent: Server is sending message.
> --------------
>
> I simply do not know if I have put close(client_socket) (in code -> 
> close(c)) in correct place.

This problem is slightly different. Your code is

    while (1)
    {
    if ((c = accept(s, (struct sockaddr *) &client, &clilen)) < 0)
    {
        printf("Could not create client socket!");
	return 1;
    }
    pid = fork();
    if (pid < 0)
    {
	puts("Error on fork");
    }
    if (pid == 0)
    {
    close(s);

// Whole client-server communication:
    speak(c, sendbuf, getbuf);
// End of whole client-server communication.

    }
    else close(c);
    }

You fork a handler process per connection but after handling the
connection, this process doesn't exit. Hence, it now also tries to run
the accept-loop but it's copy of the accepting socket was closed by the
close(s).

There are some more problems/ missing things in this code, namely,

- you should set the SO_REUSEADDR socket option so that the server can
  be restarted despite the socket used by the previously running
  instance of the server still exists in the system (in TIME_WAIT state)

- the length argument for accept needs to be initialized

- assuming your handler processes were exiting, they'd accumulate as
  zombies because the parent process doesn't wait for them


Code with these issue fixed:

-------
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>

int speak(int c, char *sendbuf, char *getbuf)
{
    int server_read, server_write;
    server_read = read(c, getbuf, 255);
    if (server_read < 0)
    {
        puts("Error reading from socket");
    }
    else
    {
        printf("Received message: %s\n", getbuf);
    }

    server_write = write(c, sendbuf, 255);
    if (server_write < 0)
    {
        puts("Error sending!");
    }
    else
    {
        printf(" Message sent: %s\n", sendbuf);
    }
    return 0;
}

static void sigchld_handler(int unused)
{
    while (waitpid(-1, NULL, WNOHANG) >0);
}

int main()
{
    int s, c, pid;
    struct sockaddr_in server, client;
    socklen_t clilen;
    char getbuf[2048];
    char sendbuf[] = "Server is sending message."; 
    int port = 8000;

    signal(SIGCHLD, sigchld_handler);
    
    // Creating socket:
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) < 0)
    {
        printf("Could not create server socket!");
    }
    else
    {
	printf("Socket created.\n");
    }

    c = 1;
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &c, sizeof(c));
    
    // Setuping network struct:
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_family = AF_INET;
    server.sin_port = htons( port );
    
    // Binding socket to port:
    if (bind(s, (struct sockaddr *) &server,sizeof(server)) < 0)
    { 
	puts("ERROR on binding");
	return 1;
    }
    else
    {
	printf ("Binding to port %i\n", port);
    }
    // Listen for connections:
    listen(s, 5);		 
    clilen = sizeof(client);
    while (1)
    {
	clilen = sizeof(client);
	if ((c = accept(s, (struct sockaddr *) &client, &clilen)) < 0)
	{
	    printf("Could not create client socket!");
	    return 1;
	}
	pid = fork();
	if (pid < 0)
	{
	    puts("Error on fork");
	}
	if (pid == 0)
	{
	    close(s);

// Whole client-server communication:
	    speak(c, sendbuf, getbuf);
// End of whole client-server communication.

	    _exit(0);
	}
	else close(c);
    }
    getchar();
    return 0;
}
0
Rainer
10/29/2016 4:44:37 PM
Rainer Weikusat <rweikusat@talktalk.net> writes:

[...]

> - the length argument for accept needs to be initialized

[...]


>     // Listen for connections:
>     listen(s, 5);		 
>     clilen = sizeof(client);

It is actually initialized here. But this is not a good habit to get
into as accept (and other functions taking in/out length arguments in
this way) modifies the value to indicate the size of the returned
address or the size of the address which had been returned had the passed
buffer been large enough.
0
Rainer
10/29/2016 8:29:24 PM
Reply: