Thread: Non-blocking socket connection problem

  1. #1
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43

    Arrow Non-blocking socket connection problem

    Hi all,

    This is my first post in this forum.

    I have a issue with socket connection related to non-blocking sockets. Here is the code which i am using under Linux

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/ioctl.h>
    
    #define PORT 0x1234
    
    #define PASS	0
    #define FAIL	1
    
    int main()
    {
    	int listenfd,sendfd,acceptfd;
    	struct sockaddr_in serveraddr,clientaddr;
    	int retc;
    	int accetfd;
    	int servlen = sizeof(serveraddr);
    	char *recv_buffer, *send_buffer;
    	int i,j,k;
    	int err_cnt = 0;
    	int flag;
        	int send_done;
        	int bytes_to_send, bytes_to_read;
        	int num_bytes_send, num_bytes_read;
    
    	/* initialise all */
    	listenfd = sendfd = acceptfd = 0;
    	recv_buffer = send_buffer = NULL;
    
    	/* allocate buffer for both send and receive */
    	recv_buffer = (char *)malloc (1024 * 1024);
    	if(recv_buffer == NULL)
    	{
    		printf("Can't allocate memory\n");
    		retc = FAIL;
    		goto done;
    	}
    	send_buffer = (char *)calloc(1, 1024 * 1024);
    	if(send_buffer == NULL)
    	{
    		printf("Can't allocate memory for send buffer\n");
    		retc = FAIL;
    		goto done;
    	}
    
    	/* open socket for send and receive */
    	listenfd = socket(AF_INET, SOCK_STREAM, 0);
    	if(listenfd < 0)
    	{
    		perror("listenfd socket failed");
    		retc = FAIL;
    		goto done;
    	}
    	sendfd = socket(AF_INET, SOCK_STREAM, 0);
    	if(sendfd < 0)
    	{
    		perror("sendfd socket failed");
    		retc = FAIL;
    		goto done;
    	}
    	
    	/* make both send and receive non-blocking */
    	if ( (flag = fcntl(listenfd, F_GETFL, NULL)) < 0)
    	{
            	perror("listenfd fcntl:");
            	retc = FAIL;
            	goto done;
        	}
    
        	flag |= O_NONBLOCK;
    
        	if ( fcntl(listenfd, F_SETFL, flag) < 0)
    	{
            	perror("listenfd fcntl:");
            	retc = FAIL;
            	goto done;
        	}
        	if ( (flag = fcntl(sendfd, F_GETFL, NULL)) < 0)
    	{
        	    perror("sendfd fcntl:");
        	    perror("listenfd fcntl:");
        	    retc = FAIL;
        	}
    
        	flag |= O_NONBLOCK;
    
        	if ( fcntl(sendfd, F_SETFL, flag) < 0)
    	{
        	    perror("sendfd fcntl:");
        	    perror("listenfd fcntl:");
        	    retc = FAIL;
        	}
    
    	/* Bind to socket */
    	serveraddr.sin_family = AF_INET;
    	serveraddr.sin_addr.s_addr = INADDR_ANY;
    	serveraddr.sin_port = htons(PORT);
    
    	clientaddr.sin_family = AF_INET;
    	clientaddr.sin_addr.s_addr = INADDR_ANY;
    	clientaddr.sin_port = htons(PORT);
    
    	if (bind (listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
    	{
    		perror("Bind error under listenfd");
    		retc = FAIL;
    		goto done;
    	}
    	
    	/* listen for incoming connection */
    	if (listen(listenfd, 1) == -1)
    	{
    		perror("Listen socket error");
    		retc = FAIL;
    		goto done;
    	}
    
    	/* establisg connection */
    	if (connect(sendfd, (struct sockaddr *)&clientaddr,sizeof(struct sockaddr)) < 0)
    	{
    		perror("Connect call failed");
    		retc = FAIL;
    		goto done;
    	}
    	
    	/* accept incoming connection */
    	if (accept(listenfd, (struct sockaddr *)&serveraddr, &servlen) < 0)
    	{
    		perror("Accept call failed");
    		retc = FAIL;
    		goto done;
    	}
    
    	retc = PASS;	
    	
    	/* send and receive data */
    	for ( k = 0; k < 100; k++)
    	{
            	bytes_to_send = 1024 * 16;
            	i = 0;
            	j = 0;
            	bytes_to_read = 1024 * 16;
            	send_done = 0;
            	while(1)
    		{
           			if ( send_done == 0)
    			{
           				num_bytes_send = send(sendfd, &send_buffer[j], bytes_to_send,0);
           			        if (num_bytes_send == -1)
    				{
           			             perror("Sending data failed");
           			             retc = FAIL;
           			             break;
           			        }
    				else if (num_bytes_send == 0)
    				{
           			             send_done = 1;
           			        }
    				else
    				{
           			             bytes_to_send -= num_bytes_send;
           			             j += num_bytes_send;
           			        }
           			}
           			if (retc == FAIL)
           				break;
           			num_bytes_read = read(acceptfd, &recv_buffer[i], bytes_to_read);
                		if (num_bytes_read == -1)
                		{
                			perror("Receive data failed");
                			retc = FAIL;
                			break;
                		}
                		else if (num_bytes_read == 0)
    			{
                			break; /* Break on EOF */
                		}
                		else 
    			{
                			bytes_to_read -= num_bytes_read;
                			i += num_bytes_read;
                		}
            	}
            	if ( retc == FAIL)
            		break;
            	for ( i = 0; i < 1024 * 16; i++)
    		{
            		if ( recv_buffer[i] != (char)i)
    			{
            			printf("Error: receive data not correct, \n");
            		        printf("expected : 0x%x, received: 0x%x\n", i, recv_buffer[i]);
            		        retc = FAIL;
            		        err_cnt ++;
            		        if ( err_cnt > 10) break;
            		}
            	}
            	if (retc != PASS)
            		break;
        	}
    done:
        	if ( sendfd != 0 )
    	{
        		if (close(sendfd ) < 0)
    			perror( "close sendfd:");
        	}
        	if ( acceptfd != 0 )
    	{
        		if (close(acceptfd ) < 0)
    		perror( "close accetfd:");
        	}
    	if ( listenfd != 0)
    	{
    		if (close(listenfd) < 0)
    			perror("close listen:");
    	}
    	if ( send_buffer != NULL)
            	free(send_buffer);
        	if ( recv_buffer != NULL)
            	free(recv_buffer);
    
    	printf("Test.......");
    	if(retc == PASS)
    		printf("PASSED\n");
    	else
    		printf("FAILED\n");
    
    	return retc;
    }

    When i try to run this code i am getting error while connecting to socket

    Connect call failed: Operation now in progress

    Can anyone help..... Thanks in advance

    -BalaC-

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    What are you trying to do here:

    Quote Originally Posted by cbalu View Post
    /* Bind to socket */
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    serveraddr.sin_port = htons(PORT);

    clientaddr.sin_family = AF_INET;
    clientaddr.sin_addr.s_addr = INADDR_ANY;
    clientaddr.sin_port = htons(PORT);
    I do not see a purpose to setting these sockets non block; that will only complicate your efforts in what I presume is your first attempt at tcp/ip networking.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    Hi MK27,

    Thanks for your reply, i am new to sockets in C language i thought of merging both server and client code in single .c file to just test whether i was able to send and receive data over the socket i followed so many tutorial over the internet and came up with this piece of code.

    So started with non-blocking approach and ended up in error.

    Can you provide me a detailed explanation what i am doing wrong in the code...Thanks in advance for your time

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by cbalu View Post
    Can you provide me a detailed explanation what i am doing wrong in the code...Thanks in advance for your time
    Your code actually looks pretty good* -- but I myself would never write that much all at once without, obviously, knowing if any of it will work, because when you are finished and it doesn't work, you now have quite a haystack to dissect! You should have started with the most simple conceivable task, which in this case would be to just write a client and try and connect that to a server somewhere on the internet, the same way your browser does. THEN start thinking about the server, etc. There is a real possibility that what you want to do here will not work no matter what, depending on your actual internet connection (unless you use 127.0.0.1 or two computers on one router -- a LAN).

    Since you are apparently working in a *nix environment, one thing you might want to look into is unix local sockets, which are almost identical to (but slightly simpler than) tcp/ip inet sockets. That will allow you to do client-server stuff without using the net at all.

    Anyway, the problem I highlighted in my last post is that you use a macro INADDR_ANY, which is equal to 0. That is not a valid address. My memory of these things is slightly fogging, but I would guess you believe this field is going to be filled in by a socket function, or you have confused the sin_addr.s_addr with a little chunk at the end of a sockaddr_in struct called sin_zero, which does need to
    be zero'd, eg:
    Code:
    memset(&(connto.sin_zero),0,8);
    So, you need a real address to assign to both the client and server sin_addr.s_addr. I have never tried using an identical address for both of them, so I don't know if that will work, ie. I do not know if you will be able to connect to yourself using inet sockets.


    * I'm not promising you anything tho
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    Just one theoritical query,

    Consider one simple server-client application where both running under the same system with only one eth interface then obviously address & port number for server and client must be same in order to communicate each other. If this scenario works then i think the code i have posted will also work

    And off course i will try your suggestion...And get back to you

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by cbalu View Post
    Just one theoritical query,
    Yep, that's theoretical. I dunno if it will work, but you can try.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    IMO, it would be a lot easier to look at (and comment on), if you split the code into functions, and not one bloated main() with several hundred lines of code (and complex logic and indentation to match).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    I have splitted up my code and now i have only socket connection logic in my code. Here is the code now i am currently working with

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/ioctl.h>
    
    #define PORT 0x1234
    #define SERVER_ADDR "127.0.0.1"
    #define CLIENT_ADDR "127.0.0.1"
    #define PASS	0
    #define FAIL	1
    
    int main()
    {
    		int listenfd,sendfd,acceptfd;
    		struct sockaddr_in serveraddr,clientaddr;
    		int retc;
    		int accetfd;
    		int servlen = sizeof(serveraddr);
    		char *recv_buffer, *send_buffer;
    		int flag;
    
    		/* initialise all */
    		listenfd = sendfd = acceptfd = 0;
    		recv_buffer = send_buffer = NULL;
    
    		/* allocate buffer for both send and receive */
    		recv_buffer = (char *)malloc (1024 * 1024);
    		if(recv_buffer == NULL)
    		{
    				printf("Can't allocate memory\n");
    				retc = FAIL;
    				goto done;
    		}
    		send_buffer = (char *)calloc(1, 1024 * 1024);
    		if(send_buffer == NULL)
    		{
    				printf("Can't allocate memory for send buffer\n");
    				retc = FAIL;
    				goto done;
    		}
    
    		/* open socket for send and receive */
    		listenfd = socket(AF_INET, SOCK_STREAM, 0);
    		if(listenfd < 0)
    		{
    				perror("listenfd socket failed");
    				retc = FAIL;
    				goto done;
    		}
    		sendfd = socket(AF_INET, SOCK_STREAM, 0);
    		if(sendfd < 0)
    		{
    				perror("sendfd socket failed");
    				retc = FAIL;
    				goto done;
    		}
    
    		/* make both send and receive non-blocking */
    #if 1
    		if ( (flag = fcntl(listenfd, F_GETFL, NULL)) < 0)
    		{
    				perror("listenfd fcntl:");
    				retc = FAIL;
    				goto done;
    		}
    
    		flag |= O_NONBLOCK;
    
    		if ( fcntl(listenfd, F_SETFL, flag) < 0)
    		{
    				perror("listenfd fcntl:");
    				retc = FAIL;
    				goto done;
    		}
    		if ( (flag = fcntl(sendfd, F_GETFL, NULL)) < 0)
    		{
    				perror("sendfd fcntl:");
    				perror("listenfd fcntl:");
    				retc = FAIL;
    		}
    
    		flag |= O_NONBLOCK;
    
    		if ( fcntl(sendfd, F_SETFL, flag) < 0)
    		{
    				perror("sendfd fcntl:");
    				perror("listenfd fcntl:");
    				retc = FAIL;
    		}
    #endif
    
    		/* Get system ip */
    		if ( ( inet_aton(SERVER_ADDR, &serveraddr.sin_addr.s_addr) == 0 ) || ( inet_aton(CLIENT_ADDR, &clientaddr.sin_addr.s_addr) == 0 ) )
        	{
            	perror("Can't assign server/client address");
            	retc = FAIL;
    			goto done;
        	}
    
    		/* Bind to socket */
    		serveraddr.sin_family = AF_INET;
    		//serveraddr.sin_addr.s_addr = INADDR_ANY;
    		serveraddr.sin_port = htons(PORT);
    		memset(&serveraddr.sin_zero,0,8);
    
    		clientaddr.sin_family = AF_INET;
    		//clientaddr.sin_addr.s_addr = INADDR_ANY;
    		clientaddr.sin_port = htons(PORT);
    		memset(&clientaddr.sin_zero,0,8);
    
    		printf("My system ip address is %ld\n", serveraddr.sin_addr.s_addr);
    		if (bind (listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
    		{
    				perror("Bind error under listenfd");
    				retc = FAIL;
    				goto done;
    		}
    
    		/* listen for incoming connection */
    		if (listen(listenfd, 1) == -1)
    		{
    				perror("Listen socket error");
    				retc = FAIL;
    				goto done;
    		}
    
    		/* establisg connection */
    		if (connect(sendfd, (struct sockaddr *)&clientaddr,sizeof(struct sockaddr)) < 0)
    		{
    				perror("Connect call failed");
    				retc = FAIL;
    				goto done;
    		}
    
    		/* accept incoming connection */
    		if (accept(listenfd, (struct sockaddr *)&serveraddr, &servlen) < 0)
    		{
    				perror("Accept call failed");
    				retc = FAIL;
    				goto done;
    		}
    
    		retc = PASS;	
    
    done:
    		if ( sendfd != 0 )
    		{
    				if (close(sendfd ) < 0)
    						perror( "close sendfd:");
    		}
    		if ( acceptfd != 0 )
    		{
    				if (close(acceptfd ) < 0)
    						perror( "close accetfd:");
    		}
    		if ( listenfd != 0)
    		{
    				if (close(listenfd) < 0)
    						perror("close listen:");
    		}
    		if ( send_buffer != NULL)
    				free(send_buffer);
    		if ( recv_buffer != NULL)
    				free(recv_buffer);
    
    		printf("Test.......");
    		if(retc == PASS)
    				printf("PASSED\n");
    		else
    				printf("FAILED\n");
    
    		return retc;
    }
    In this code if i disable non-blocking call then my code works fine. But if i enable non-blocking call then i am getting the following error

    Connect call failed: Operation now in progress

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Wow, cbalu, I just remembered what INADDR_ANY is for; it does gets filled in! None of the stuff I have on file has it in because I always provide an address, but I do remember using that at some point.

    I am very sorry about that -- you must have known this, why didn't you say anything?

    Anyway, it is good your code is working, sans non-block. I do not understand the nature of the error, but I still believe there is no purpose to the non-block, since this is a one to one client-server relationship.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    Hi MK27, today only i came to know the functionality of INADDR_ANY. If i would have known it then i would certainly post it (as i don't want to waste others time).

    Now upto accept call my code works fine under blocking sockets then if i try to send data using the write call i am getting error, which states that i am using Bad address

    And one more thing is that one of my colleague suggested me that i have done coding wrongly. I need to run server and client as separate program or else i need to make them run in separate threads to make it communicate each other. Is it true?

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by cbalu View Post
    And one more thing is that one of my colleague suggested me that i have done coding wrongly. I need to run server and client as separate program or else i need to make them run in separate threads to make it communicate each other. Is it true?
    Yep. Your program will stop at listen(), and of course never receive anything. I don't know why I didn't notice that -- probably I stopped at the first problem I thought I found...embarrassing. Sorry again. It is good for me to refresh my memory about these things

    You don't have to thread -- you can use fork(). Probably you will then want to write a single function which sets up a socket, given an appropriate set of parameters, and you can call that from the parent/server and child/client.

    I still think you should write a simple client that can communicate with a real server somewhere -- if you can make that happen, you know everything is working.

    You can use gethostbyname(), in netdb.h, to translate (eg) "www.cprogramming.com" into a host address you use with connect() then you send() a GET request using a path, so if you wanted a page like "www.cprogramming.com/someplace/sompage.html"

    Code:
    char request[]="GET /someplace/sompage.html HTTP/1.0\r\n\r\n";
    Then you should be able to recv() an answer.

    Once that works you will have a better feel for how the flow of execution works. If it is easier to write two separate programs rather than using fork(), just do that. IMO you might as well, there is no reason to put all this in one piece of source code.

    If you want some examples, I have a bunch of client and server things I wrote months ago, some of which I use to do file transfer and issue remote commands on a LAN. Just ask.
    Last edited by MK27; 05-26-2009 at 11:36 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    Hi MK27,

    Finally i have managed to achieve both server and client in the same code with blocking sockets. I have attached the source code which i have tried to prove my theory

    And now i have a query i have used INADDR_ANY as address for both server and client socket instead how can i read the system ip and assign it. (Please note that i don't want to assign 127.0.0.1 loopback ip) Instead i need to assign the real ip from the system in place of INADDR_ANY in the attached code.

    Thanks in advance....

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Well that's great. I feel even worse about my earlier mistake tho, because I was just looking thru my LAN server code and it does use INADDR_ANY. After the socket is set up, you can check that address using inet_ntoa (network to ascii),eg:

    Code:
    printf("accepted connection from %s \n",inet_ntoa(info.sin_addr));
    If you want to do the inverse, put the address (eg "192.168.0.1") into a char string and use inet_aton (ascii to network):
    Code:
    inet_aton(addrstr,(struct in_addr*)&server.sin_addr.s_addr);
    You should be able to find some docs for both these commands (they are in arpa/inet.h) which explain their use in more detail.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    VIM addict
    Join Date
    May 2009
    Location
    Chennai, India
    Posts
    43
    MK27 again thanks for your time, i already know about these functions.

    What i want to know is the way to get my system ip dynamically and assign it in place of INADDR_ANY so that my code will work in any system (Of course i agree that with 127.0.0.1 or INADDR_ANY it will work in any system). But, i want to know the way in which this can be achieved

    If you are not able to get me, here is the brief description of what i exactly want to have.
    Consider two system with IP's 10.0.3.40 and 10.0.3.41 so if i run the code in 10.0.3.40 system then my code should dynamically read the IP and replace it in the place of INADDR_ANY on the code and if i try to run the same code under 10.0.3.41 system then my code should get that IP dynamically in place of INADDR_ANY.

    Hope i explained my requirement well...

  15. #15
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    INADDR_ANY does seem to work. If you want to get your assigned/existing ip manually, AFAIK the only way is to parse the data returned by "ifconfig" (which is a system, not a C, command). That is awkward, which implies to me that INADDR_ANY is the proper solution.

    You may experience problems trying to connect to your machine from outside if you are using a router, which I think most people do now. I have never done this, but apparently you will have to learn about "port forwarding".
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with simple socket client/server program
    By spencer88 in forum C Programming
    Replies: 6
    Last Post: 05-05-2009, 11:05 PM
  2. Socket Connection Still Alive!!
    By maven in forum Networking/Device Communication
    Replies: 2
    Last Post: 07-21-2006, 02:14 PM
  3. socket problem
    By RevengerPT in forum C Programming
    Replies: 9
    Last Post: 01-17-2006, 09:07 AM
  4. Weird connection problem.
    By tilex in forum Networking/Device Communication
    Replies: 6
    Last Post: 02-06-2005, 10:11 AM
  5. problem closing socket
    By Wisefool in forum Networking/Device Communication
    Replies: 2
    Last Post: 10-29-2003, 12:19 PM

Tags for this Thread