Thread: Unix sockets

  1. #1
    Registered User
    Join Date
    Jan 2006
    Location
    Europe/Belgrade
    Posts
    78

    Unix sockets

    Hi,
    I'm experimenting with Unix sockets, and I have a problem when client interrupts connection (with Ctrl-C for example).
    Server accepts connections and each client is treated in forked process (talk() in the code). On each client's request server responds, and that works until client closes the connection (with close()). Server then knows that client finished because talk() returned and prints message Client quitted. But, if I interrupt the client execution with Ctrl-C, server sometimes (not always, but often) does not return from talk(), i.e. it does not know that client interrupted the connection! Why is that?
    If I put usleep(0) after each client's request, then the communication between client and server is slower, but this problem does not occur! Does it mean that client is too fast for the server?
    Also, this problem does not happen with Internet sockets. Am I doing something wrong with Unix sockets?
    Thanks!

    server:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>
    
    
    void talk(int client_fd)
    {
    	char text[100];
    	int status;
    
    	while (1)
    	{
    		memset(text, 0, 100);
    		status = recv(client_fd, text, 100, 0);
    		if (!status)// client closed the connection (Ctrl+C for example)
    			break;
    		text[status] = '\0';
    		printf("Received: %s\n", text);
    		send(client_fd, text, strlen(text), 0);
    	}
    }
    
    
    void sigchld_handler(int s)
    {
        while(waitpid(-1, NULL, WNOHANG) > 0)
    		;
    }
    
    
    int main()
    {
    	int server_fd;
    	struct sockaddr_un server_addr;
    	struct sigaction sa;
    
    	server_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
    	server_addr.sun_family = AF_LOCAL;
    	strcpy(server_addr.sun_path, "my.sck");
    	bind(server_fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    	listen(server_fd, 5);
    	
    // kill zombie child process
    
    	sa.sa_handler = sigchld_handler;
    	sigemptyset(&sa.sa_mask);
    	sa.sa_flags = SA_RESTART;
    	sigaction(SIGCHLD, &sa, NULL);
    	
    	while (1)
    	{
    		struct sockaddr_un client_addr;
    		socklen_t addr_len;
    		int client_fd;
    		
    		client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);
    		if (!fork())// talk with client in child process
    		{
    			talk(client_fd);
    			close(client_fd);
    			printf("Client quitted.\n");
    			break;
    		}
    		else
    			printf("Server waits...\n");
    	}
    	close(server_fd);
    
    	return 0;
    }
    and client:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    
    
    int main(int argc, char* const argv[])
    {
    	int server_fd;
    	struct sockaddr_un server_addr;
    	char message[100];
    
    	server_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
    	server_addr.sun_family = AF_LOCAL;
    	strcpy(server_addr.sun_path, "my.sck");
    	connect(server_fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    
    	int i = 1;
    	while (i++ < 50000)
    	{
    		sprintf(message, "%d", i);
    		send(server_fd, message, strlen(message), 0);
    		int status = recv(server_fd, message, 100, 0);
    		message[status] = '\0';
    		printf("Response: %s\n", message);
    		/* usleep(0); */
    	}
    	close(server_fd);
    
    	return 0;
    }

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You may want to catch the SIG_QUIT signal that is sent to the process when you press CTRL-C, and send a "I'm leaving, Bye" message to the server.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    Jan 2006
    Location
    Europe/Belgrade
    Posts
    78
    Hm, that could be solution, but question still remains: why Internet server knows that client interrupted and does not have broken pipe, but Unix server cannot figure it out and receives broken pipe? This way, any client can crash my server.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Maybe it uses the pipe in a different way perhaps using a timeout to detect loss of contact?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Jan 2006
    Location
    Europe/Belgrade
    Posts
    78
    Any suggestion how to put timeout into server?

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by karas View Post
    Hm, that could be solution, but question still remains: why Internet server knows that client interrupted and does not have broken pipe, but Unix server cannot figure it out and receives broken pipe? This way, any client can crash my server.
    They can only "crash" the server if you don't catch SIGPIPE, which is probably what you should be doing. If a SIGPIPE comes in during a call to recv(), the recv() will return -1 and errno will be set to EINTR. You can then retry the recv() and get a 0 status. You can't just assume it was SIGPIPE, because any signal could have caused the interrupted return.

    Also, on the client side, catch SIGINT and shut down gracefully by closing the socket, also it might be a good idea to call shutdown() on it.

  7. #7
    Registered User
    Join Date
    Jan 2006
    Location
    Europe/Belgrade
    Posts
    78
    Ok, and why SIGPIPE is raised with Unix sockets and not with Internet sockets? When I use Internet sockets, there's no need for server to catch this signal, only check when recv() returns 0.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by karas View Post
    Ok, and why SIGPIPE is raised with Unix sockets and not with Internet sockets? When I use Internet sockets, there's no need for server to catch this signal, only check when recv() returns 0.
    Some info on SIGPIPE

    Notice you only get a SIGPIPE on an Internet socket when you try to WRITE to it after a RST. But if the server negotiates a shutdown, you get FIN, not RST. Whereas on a UNIX socket there is no such thing, and you get SIGPIPE regardless.

  9. #9
    Registered User
    Join Date
    Jan 2006
    Location
    Europe/Belgrade
    Posts
    78
    Thanks, that's what I needed to know.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Unix Nonblocking Reads on Sockets
    By winderjj in forum Networking/Device Communication
    Replies: 5
    Last Post: 09-10-2008, 07:17 AM
  2. Difference between Unix sockets and winsock.
    By antex in forum Networking/Device Communication
    Replies: 15
    Last Post: 01-21-2005, 04:53 PM
  3. Winsock vs Unix Sockets
    By khoxxxy in forum Networking/Device Communication
    Replies: 4
    Last Post: 08-05-2003, 05:13 AM
  4. Unix Sockets
    By prvindia in forum Linux Programming
    Replies: 5
    Last Post: 03-11-2003, 09:16 AM
  5. new to unix sockets
    By lithium in forum C Programming
    Replies: 3
    Last Post: 01-20-2003, 05:53 AM