linux, tcp/ip, issues with bind - Page 1
Forum section: electronics / general

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2015, 09:18:57 pm
content: Code:int tcp_ip_sock_get(int port){int servSock; /* Socket descriptor for server */int clntSock; /* Socket descriptor for client */struct sockaddr_in echoServAddr; /* Local address */struct sockaddr_in echoClntAddr; /* Client address */unsigned short echoServPort; /* Server port */unsigned int clntLen; /* Length of client address data structure */echoServPort = port;/* Create socket for incoming connections */servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);if (servSock < 0){DieWithError("socket() failed");return 0;}/* Construct local address structure */memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */echoServAddr.sin_family = AF_INET; /* Internet address family */echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */echoServAddr.sin_port = htons(echoServPort); /* Local port *///int option=1;//int reuse=1;//if(setsockopt(servSock,SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0)//if(setsockopt(servSock,SOL_SOCKET,(SO_REUSEADDR),(char*)&option,sizeof(option)) < 0)// if (setsockopt(servSock, SOL_SOCKET, SO_REUSEPORT,(const char*)&reuse, sizeof(reuse)) < 0)//{// DieWithError("setsockopt failed");// return 0;//}/* Bind to the local address */if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){DieWithError("bind() failed");return 0;}/* Mark the socket so it will listen for incoming connections */if (listen(servSock, MAXPENDING) < 0){DieWithError("listen() failed");return 0;}//while (1)//{/* Set the size of the in-out parameter */clntLen = sizeof(echoClntAddr);/* Wait for a client to connect */clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen);if (clntSock < 0){DieWithError("accept() failed");return 0;}/* clntSock is connected to a client! */printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));printf(" +sock.server=%ld\n", servSock);printf(" +sock.client=%ld\n", clntSock);// HandleTCPClient(clntSock);//}return clntSock;}hi guysabout tcp/ip networking, i am experimenting an issues with bind()this code is not working, perhaps it works the first time i invoke it, then bind fails, i have to wait 2 seconds, and then it works againCode:while (1){clntSock=tcp_ip_sock_get(2000);HandleTCPClient(clntSock);close(clntSock);}while the following code is workingCode:void tcp_ip_sock{int servSock; /* Socket descriptor for server */int clntSock; /* Socket descriptor for client */struct sockaddr_in echoServAddr; /* Local address */struct sockaddr_in echoClntAddr; /* Client address */unsigned short echoServPort; /* Server port */unsigned int clntLen; /* Length of client address data structure */echoServPort = 2000;/* Create socket for incoming connections */servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);if (servSock < 0){DieWithError("socket() failed");return 0;}/* Construct local address structure */memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */echoServAddr.sin_family = AF_INET; /* Internet address family */echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */echoServAddr.sin_port = htons(echoServPort); /* Local port *//* Bind to the local address */if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){DieWithError("bind() failed");return 0;}/* Mark the socket so it will listen for incoming connections */if (listen(servSock, MAXPENDING) < 0){DieWithError("listen() failed");return 0;}while (1)/{/* Set the size of the in-out parameter */clntLen = sizeof(echoClntAddr);/* Wait for a client to connect */clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen);if (clntSock < 0){DieWithError("accept() failed");return 0;}/* clntSock is connected to a client! */printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));printf(" +sock.server=%ld\n", servSock);printf(" +sock.client=%ld\n", clntSock);HandleTCPClient(clntSock);}}what's wrong with bind()?

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2015, 09:20:37 pm
content: my linux hasn't SO_REUSEPORT defined

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2015, 09:24:26 pm
content: i have been reading"how-to-forcibly-close-a-socket-in-time-wait"

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2015, 09:27:57 pm
content: and"tcp-option-so-linger-zero-when-its-required"

author: westfw
author_rank: Super Contributor
timestamp: January 17, 2015, 09:41:29 pm
content: There's a reason that connections sit in TIMEWAIT when they're done.The usual practice is to pick a different local port on the client side, so that you have:client:random --> server:echoport(I can't tell you how to do that with sockets, though.)

author: legacy
author_rank: Super Contributor
timestamp: January 17, 2015, 10:12:16 pm
content: the problem is this:Quotei have to think about a solution

author: codeboy2k
author_rank: Super Contributor
timestamp: January 18, 2015, 12:11:12 am
content: Most server implementations would fork (or pre-fork) and hand off the work to another process, which can close the socket after it finishes sending. The main process that is handing the accept() connections is never closed. So you never get into a TIMEWAIT state.However, during development and testing you often crash and get into a TIMEWAIT state, that can take between 30s and 120s to expire. So in this case you want to use SO_REUSEADDR on the socket options. And in general your server should use SO_REUSEADDR.However, SO_REUSEADDR does not let you start a second server on the same port if the port is already in use. This is why most TCP servers use a worker model, where only one master process opens the socket then it forks after each accepted connection (or pre-forks and hands out work to pre-forked and waiting workers).Google introduced SO_REUSEPORT to enable them to create a simple server process model that can be executed multiple times on the same host, and each server process can open the same local port. To do so, they specify SO_REUSEPORT and then the open succeeds. Incoming connections are handed off fairly to each server listening on the same port, and this is done by the kernel. So this avoids the more complex (and sometimes unfair) user-land pre-forked or multi-threaded but single port server model.SO_REUSEPORT was introduced in kernel 3.9 (but BSD had it before that).With your simple server, SO_REUSEPORT would help you out, but you need to use kernel 3.9.If you can't use kernel 3.9, then your server code needs to fork() after accept(), and in the parent: close the socket (from accept) and continue the loop to go back into accept() for more; (2) in the child, write to the socket (from accept) and close it and exit.EDIT: in your case, for (2) return the socket descriptor to the caller. The parent loops back to accept more, and never returns from this function call.