I'm writing a TCP server in C and find something unusual happens once the listening fd get "Too many open files" error. The accept call doesn't block anymore and returns -1 all the time.
I also tried closing the listening fd and re-opening, re-binding it, but didn't seem to work.
My questions are why accept keeps returning -1 in this situation, what am I supposed to do to stop it and make the server be able to accept new connections after any old clients closed? (the socket is of course able to accept correctly again when some connections closed)
====== UPDATE: clarification ======
The problem occurs just because the number of active clients is more than the limit of open fds, so I don't close any of the accepted fds in the sample code, just to make it reproduce more quickly.
I add the timestamp each time accept returns to the output and slow down connect frequency to once in 2 seconds, then I find that in fact the "Too many open files" error occurs immediately after the lastest success accept. So I think that is because when the maxium fds is reached, each call to accept will return immediately, and the return value is -1. (What I thought is that accept would still block, but returns -1 at the next incoming connect. The behavior of accept in this situation is my own theory, not from the man page. If it's wrong, please let me know).
So to my second question, to make it stop, I think it's a solution that stop to call accept before any connection is closed.
Also update the sample codes. Thanks for your help.
====== Sample codes ======
Here is how I test it. First set ulimit -n to a low value (like 16) and run the server program compiled from the following C source; then use the Python script to create several connections
/* TCP server; bind :5555 */
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
#define PORT 5555
void error(char const* msg)
{
perror(msg);
exit(1);
}
int listen_port(int port)
{
int parentfd; /* parent socket */
struct sockaddr_in serveraddr; /* server's addr */
int optval; /* flag value for setsockopt */
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0) {
error("ERROR opening socket");
}
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(parentfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {
error("ERROR on binding");
}
if (listen(parentfd, 5) < 0) {
error("ERROR on listen");
}
printf("Listen :%d\n", port);
return parentfd;
}
int main(int argc, char **argv)
{
int parentfd; /* parent socket */
int childfd; /* child socket */
int clientlen; /* byte size of client's address */
struct sockaddr_in clientaddr; /* client addr */
int accept_count; /* times of accept called */
accept_count = 0;
parentfd = listen_port(PORT);
clientlen = sizeof(clientaddr);
while (1) {
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t*) &clientlen);
printf("accept returns ; count=%d ; time=%u ; fd=%d\n", accept_count++, (unsigned) time(NULL), childfd);
if (childfd < 0) {
perror("error on accept");
/* the following 2 lines try to close the listening fd and re-open it */
// close(parentfd);
// parentfd = listen_port(PORT);
// the following line let the program exit at the first error
error("--- error on accept");
}
}
}
The Python program to create connections
import time
import socket
def connect(host, port):
s = socket.socket()
s.connect((host, port))
return s
if __name__ == '__main__':
socks = []
try:
try:
for i in xrange(100):
socks.append(connect('127.0.0.1', 5555))
print ('connect count: ' + str(i))
time.sleep(2)
except IOError as e:
print ('error: ' + str(e))
print ('stop')
while True:
time.sleep(10)
except KeyboardInterrupt:
for s in socks:
s.close()
why accept keeps returning -1 in this situation
Because you've run out of file descriptors, just like the error message says.
what am I supposed to do to stop it and make the server be able to accept new connections after any old clients closed?
Close the clients. The problem is not accept() returning -1, it is that you aren't closing accepted sockets once you're finished with them.
Closing the listening socket isn't a solution. It's just another problem.
EDIT By 'finished with them' I mean one of several things:
They have finished with you, which is shown by recv() returning zero.
You have finished with them, e.g. after sending a final response.
When you've had an error sending or receiving to/from them other than EAGAIN/EWOULDBLOCK.
When you've had some other internal fatal error that prevents you dealing further with that client, for example receiving an unparseable request, or some other fatal application error that invalidates the connection or the session, or the entire client for that matter.
In all these cases you should close the accepted socket.
The answer of EJP is correct, but it does not tell you how to deal with the situation. What you have to do is actually do something with the sockets that you get as accept returns. Simple calling close on them you won't receive anything of course but it would deal with the resource depletion problem. What you have to do to have a correct implementation is start receiving on the accepted sockets and keep receiving until you receive 0 bytes. If you receive 0 bytes, that is an indication that the peer is done using his side of the socket. That is your trigger to call close on the socket as well and deal with the resource problem.
You don't have to stop listening. That would stop your server from being able to process new requests and that is not the problem here.
The solution I implemented here was to review the value of the new (accepted) fd and if that value was equal or higher then the allowed server capacity, then a "busy" message is sent and the new connection is closed.
This solution is quite effective and allows you to inform your clients about the server's status.
Related
I'm learning socket programming in C. I have gotten my server to create a socket that was successful, but when I try to bind my socket to a port nothing happens. No error occurs and it is not successful. It's as if the bind() function is not even executing at all.
I've checked out the documentation on the bind() function here but there's no mention of why it won't execute at all. I've also tried searching through this site with no avail.
I also tried following this tutorial from start to finish but the error (or lack thereof) still occurs.
Here is my full code leading up to the problem:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "include.h"
int main() {
// Descriptors. Used to check the status of functions such as socket, listen, bind etc.
// If a descriptor is equal to 0, then everything is okay. Else, if they are equal to -1, something went wrong.
int socketDescriptor, newSocketDescriptor = 1;
// The process ID of a child process (the client) when a new one is spawned (the client connects).
pid_t childPID;
// A string to hold the commands being sent a received.
char* commandBuffer = calloc(BUFFER_SIZE, sizeof(char));
// A structure to hold information on the server address.
struct sockaddr_in serverAddress;
memset(&serverAddress, '\0', sizeof(serverAddress));
// Fill in the server address information.
// Set the address family to AF_INET, which specifies we will be using IPv4.
// htons() takes the given int and converts it to the appropriate format. Used for port numbers.
// inet_addr() takes the given string and converts it to the appropriate format. Used for IP addresses.
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// A structure to hold information a client when a new one connects to this server.
struct sockaddr_in clientAddress;
memset(&clientAddress, '\0', sizeof(clientAddress));
// socklen_t defines the length of a socket structure. Need this for the accept() function.
socklen_t addressSize;
// Creating the socket.
// AF_NET specifies that we will be using IPv4 addressing.
// SOCK_STREAM specifies that we will be using TCP to communicate.
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketDescriptor < 0) {
perror("ERROR CREATING SOCKET");
exit(1);
}
else
printf("Socket created successfully.\n");
// Binding to the specified port. 0 if everything is fine, -1 if there was an error.
if (bind(socketDescriptor, (struct sockaddr*) & serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
printf("Socket bound to %s:%s.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
The last if statement at the bottom is where the code fails. It should either print and error or print "Socket bound to 127.0.0.1:80" but neither happens. See an example here.
I'm lost for what to do.
A server socket won't show up in a netstat listing unless you call listen after binding the socket.
Also, you're using the %s format specifier in your printf after the bind call on serverAddress.sin_addr.s_addr and serverAddress.sin_port. These are not strings but integers. Using the wrong format specifier invokes undefined behavior and is likely causing your program to crash. Using the correct format specifier such as %d or %x will fix this.
if (bind(socketDescriptor, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
// use %x to print instead
printf("Socket bound to %x:%x.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
if (listen(socketDescriptor, 3) < 0) {
perror("listen failed");
} else {
printf("socket is listening\n");
}
This question already has answers here:
Detecting TCP Client Disconnect
(9 answers)
Closed 4 years ago.
I have basic tcp application written in C. It basically sends data to a tcp server. I have connected two PC's with cross cable. I send data from one, and successfully get this data from another one. I have built this mechanism to test If somehow connection broken by unhealty ways (ruptured cable etc.), I want to be informed as client. But things doesn't work as I wanted.If I manually stop tcpserver, client side is informed, but when I start program, connection establishes, data starts to flow, then I unplug the cable, and both sides behaves like nothing happened. Client still sends data with no error, and server still shows the client connected but data flow stops. After a few minutes, I plug cable again, the datas -which considered as sent but not sent- flushes suddenly then program continues normally. How can I detect a broken connection like this? Any help would be appreciated. Here is the code;
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
const char* server_name = "192.168.5.2";
const int server_port = 30152;
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
// creates binary representation of server name
// and stores it as sin_addr
// http://beej.us/guide/bgnet/output/html/multipage/inet_ntopman.html
inet_pton(AF_INET, server_name, &server_address.sin_addr);
// htons: port in network order format
server_address.sin_port = htons(server_port);
// open a stream socket
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("could not create socket\n");
return 1;
}
// TCP is connection oriented, a reliable connection
// **must** be established before any data is exchanged
if (connect(sock, (struct sockaddr*)&server_address,
sizeof(server_address)) < 0) {
printf("could not connect to server\n");
return 1;
}
// send
// data that will be sent to the server
const char* data_to_send = "HELLO THIS IS DATA!";
while(1)
{
int err = send(sock, data_to_send, strlen(data_to_send), 0);
if(err==-1)
{
printf("ERROR \n");
break;
}
else
{
printf("sent \n");
sleep(1);
}
}
printf("EOP\n");
// close the socket
close(sock);
return 0;
}
If the peer of a TCP connection closes the connection, it will lead to a recv call on your end to return 0. That's the way to detect closed (but not broken) connections.
If you don't currently receive anything from the peer, you need to make up a protocol on top of TCP which includes receiving data.
Furthermore, sending might not detect broken connections (like missing cables etc.) directly, as there are a lot of retransmissions and timeouts. The best way is again to implement some kind of protocol overlaying TCP, one that for example contains a kind of "are you there" message which expects a reply. If a reply to the "are you there" message isn't received within some specific timeout, then consider the connection broken and disconnect.
When a process runs out of file descriptors, accept() will fail and set errno to EMFILE.
However the underlying connection that would have been accepted are not closed, so there appears to be no way to inform the client that the application code could not handle the connection.
The question is what is the proper action to take regarding accepting TCP connections when running out of file descriptors.
The following code demonstrates the issue that I want to learn how to best deal with(note this is just example code for demonstrating the issue/question, not production code)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static void err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
int serversocket;
struct sockaddr_in serv_addr;
serversocket = socket(AF_INET,SOCK_STREAM,0);
if(serversocket < 0)
err("socket()");
memset(&serv_addr,0,sizeof serv_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(6543);
if(bind(serversocket,(struct sockaddr*)&serv_addr,sizeof serv_addr) < 0)
err("bind()");
if(listen(serversocket,10) < 0)
err("listen()");
for(;;) {
struct sockaddr_storage client_addr;
socklen_t client_len = sizeof client_addr;
int clientfd;
clientfd = accept(serversocket,(struct sockaddr*)&client_addr,&client_len);
if(clientfd < 0) {
continue;
}
}
return 0;
}
Compile and run this code with a limited number of file descriptors available:
gcc srv.c
ulimit -n 10
strace -t ./a.out 2>&1 |less
And in another console, I run
telnet localhost 65432 &
As many times as needed until accept() fails:
The output from strace shows this to happen:
13:21:12 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
13:21:12 bind(3, {sa_family=AF_INET, sin_port=htons(6543), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
13:21:12 listen(3, 10) = 0
13:21:12 accept(3, {sa_family=AF_INET, sin_port=htons(43630), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 4
13:21:19 accept(3, {sa_family=AF_INET, sin_port=htons(43634), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 5
13:21:22 accept(3, {sa_family=AF_INET, sin_port=htons(43638), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 6
13:21:23 accept(3, {sa_family=AF_INET, sin_port=htons(43642), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 7
13:21:24 accept(3, {sa_family=AF_INET, sin_port=htons(43646), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 8
13:21:26 accept(3, {sa_family=AF_INET, sin_port=htons(43650), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 9
13:21:27 accept(3, 0xbfe718f4, [128]) = -1 EMFILE (Too many open files)
13:21:27 accept(3, 0xbfe718f4, [128]) = -1 EMFILE (Too many open files)
13:21:27 accept(3, 0xbfe718f4, [128]) = -1 EMFILE (Too many open files)
13:21:27 accept(3, 0xbfe718f4, [128]) = -1 EMFILE (Too many open files)
... and thousands upon thousands of more accept() failures.
Basically at this point:
the code will call accept() as fast as possible failing to accept the same TCP connection over and over again, churning CPU.
the client will stay connected, (as the TCP handshake completes before the application accepts the connection) and the client gets no information that there is an issue.
So,
Is there a way to force the TCP connection that caused accept() to fail to be closed (so e.g. the client can be quickly informed and perhaps try another server )
What is the est practice to prevent the server code to go into an infinite loop when this situation arises (or to prevent the situation altogether)
You can set aside an extra fd at the beginning of your program and keep track of the EMFILE condition:
int reserve_fd;
_Bool out_of_fd = 0;
if(0>(reserve_fd = dup(1)))
err("dup()");
Then, if you hit the EMFILE condition, you can close the reserve_fd and use its slot to accept the new connection (which you'll then immediately close):
clientfd = accept(serversocket,(struct sockaddr*)&client_addr,&client_len);
if (out_of_fd){
close(clientfd);
if(0>(reserve_fd = dup(1)))
err("dup()");
out_of_fd=0;
continue; /*doing other stuff that'll hopefully free the fd*/
}
if(clientfd < 0) {
close(reserve_fd);
out_of_fd=1;
continue;
}
Complete example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static void err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
int serversocket;
struct sockaddr_in serv_addr;
serversocket = socket(AF_INET,SOCK_STREAM,0);
if(serversocket < 0)
err("socket()");
int yes;
if ( -1 == setsockopt(serversocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) )
perror("setsockopt");
memset(&serv_addr,0,sizeof serv_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(6543);
if(bind(serversocket,(struct sockaddr*)&serv_addr,sizeof serv_addr) < 0)
err("bind()");
if(listen(serversocket,10) < 0)
err("listen()");
int reserve_fd;
int out_of_fd = 0;
if(0>(reserve_fd = dup(1)))
err("dup()");
for(;;) {
struct sockaddr_storage client_addr;
socklen_t client_len = sizeof client_addr;
int clientfd;
clientfd = accept(serversocket,(struct sockaddr*)&client_addr,&client_len);
if (out_of_fd){
close(clientfd);
if(0>(reserve_fd = dup(1)))
err("dup()");
out_of_fd=0;
continue; /*doing other stuff that'll hopefully free the fd*/
}
if(clientfd < 0) {
close(reserve_fd);
out_of_fd=1;
continue;
}
}
return 0;
}
If you're multithreaded, then I imagine you'd need a lock around fd-producing functions and take it when you close the extra fd (while expecting to accept the final connection) in order to prevent having the spare slot filled by another thread.
All this should only makes sense if 1) the listening socket isn't shared with other processes (which might not have hit their EMFILE limit yet) and 2) the server deals with persistent connections (because if it doesn't, then you're bound to close some existing connection very soon, freeing up a fd slot for your next attempt at accept).
Problem
You cannot accept client connections, if the maximum number of file descriptors is reached. This can be a process limit (errno EMFILE) or a global system limit (errno ENFILE). The client does not immediately notice this situation and it looks to him like the connection was accepted by the server. If too many such connections pile up on the socket (when the backlog runs full), the server will stop sending syn-ack packets and the connection request will time out at the client (which can be quite an annoying delay)
Number of file descriptors
It is of course possible, to extend both limits when they are hit. For the process wide limit, use setrlimit(RLIMIT_NOFILE, ...), for the system wide limit sysctl() is the command to call. Both may require root privileges, the first one only to rise the hard limit.
However, there usually is a good reason for the file descriptor limit to prevent overusage of system resources, so this will not be a solution for all situations.
Recovering from EMFILE
One option is to implement a sleep(n) after EMFILE is received, one second should be enough to prevent additional system load by calling accept() too often. This may be useful to handle short bursts of connections.
However, if the situation doesn't normalize soon, other measures should be taken (for example, if sleep() had to be called 5 times in a row or similar).
In this case it is advisable to close the server socket. All pending client connections will be terminated immediately (by receiving a RST packet) and the clients can use another server if applicable. Furthermore, no new client connections are accepted, but immediately rejected (Connection Refused) instead of timing out as it might happen when the socket is held open.
After the contention releases, the server socket can be opened again. For the EMFILE case it is only necessary to track the number of open client connections and re-open the server socket, when these fall below some threshold. In the system-wide case, there is not a general answer for that, maybe just try after some time or use the /proc filesystem or system tools like lsof to find out when the contention ceases.
One solution I've read about is to keep a "spare" file descriptor handy that you can use to accept and immediately close new connections when you're over fd capacity. For example:
int sparefd = open("/dev/null", O_RDONLY);
Then, when accept returns with EMFILE, you can:
close(sparefd); // create an available file descriptor
int newfd = accept(...); // accept a new connection
close(newfd); // immediately close the connection
sparefd = open("/dev/null", O_RDONLY); // re-create spare
It's not exactly elegant, but it's probably a little better than closing the listening socket in some circumstances. Be wary that if your program is multi-threaded then another thread might "claim" the spare fd as soon as you release it; there's no easy way to solve that (the "hard" way is to put a mutex around every operation that might consume a file descriptor).
I've encountered a case where using write() server-side on a remotely closed client doesn't return 0.
According to man 2 write :
On success, the number of bytes written is returned (zero indicates
nothing was written). On error, -1 is returned, and errno is set
appropriately.
From my understanding: when using read/write on a remotely closed socket, the first attempt is supposed to fail (thus return 0), and the next try should trigger a broken pipe. But it doesn't. write() acts as if it succeeded in sending the data on the first attempt, and then i get a broken pipe on the next try.
My question is why?
I know how to handle a broken pipe properly, that's not the issue. I'm just trying to understand why write doesn't return 0 in this case.
Below is the server code I wrote. Client-side, I tried a basic C client (with close() and shutdown() for closing the socket) and netcat. All three gave me the same result.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define MY_STR "hello world!"
int start_server(int port)
{
int fd;
struct sockaddr_in sin;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
perror(NULL);
return (-1);
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1
|| listen(fd, 0) == -1)
{
perror(NULL);
close(fd);
return (-1);
}
return (fd);
}
int accept_client(int fd)
{
int client_fd;
struct sockaddr_in client_sin;
socklen_t client_addrlen;
client_addrlen = sizeof(struct sockaddr_in);
client_fd = accept(fd, (struct sockaddr *)&client_sin, &client_addrlen);
if (client_fd == -1)
return (-1);
return (client_fd);
}
int main(int argc, char **argv)
{
int fd, fd_client;
int port;
int ret;
port = 1234;
if (argc == 2)
port = atoi(argv[1]);
fd = start_server(port);
if (fd == -1)
return (EXIT_FAILURE);
printf("Server listening on port %d\n", port);
fd_client = accept_client(fd);
if (fd_client == -1)
{
close(fd);
printf("Failed to accept a client\n");
return (EXIT_FAILURE);
}
printf("Client connected!\n");
while (1)
{
getchar();
ret = write(fd_client, MY_STR, strlen(MY_STR));
printf("%d\n", ret);
if (ret < 1)
break ;
}
printf("the end.\n");
return (0);
}
The only way to make write return zero on a socket is to ask it to write zero bytes. If there's an error on the socket you will always get -1.
If you want to get a "connection closed" indicator, you need to use read which will return 0 for a remotely closed connection.
This is just how the sockets interface was written. When you have a connected socket or pipe, you are supposed to close the transmitting end first, and then the receiving end will get EOF and can shut down. Closing the receiving end first is "unexpected" and so it returns an error instead of returning 0.
This is important for pipes, because it allows complicated commands to finish much more quickly than they would otherwise. For example,
bunzip2 < big_file.bz2 | head -n 10
Suppose big_file.bz2 is huge. Only the first part will be read, because bunzip2 will get killed once it tries sending more data to head. This makes the whole command finish much quicker, and with less CPU usage.
Sockets inherited the same behavior, with the added complication that you have to close the transmitting and receiving parts of the socket separately.
The point to be observed is that, in TCP, when one side of the connection closes its
socket, it is actually ceasing to transmit on that socket; it sends a packet to
inform its remote peer that it will not transmit anymore through that
connection. It doesn't mean, however, that it stopped receiving too. (To
continue receiving is a local decision of the closing side; if it stops receiving, it can
lose packets transmitted by the remote peer.)
So, when you write() to a socket that is remotely closed, but
not locally closed, you can't know if the other end is still waiting to read
more packets, and so the TCP stack will buffer your data and try to send it. As
stated in send() manual page,
No indication of failure to deliver is implicit in a send(). Locally detected
errors are indicated by a return value of -1.
(When you write() to a socket, you are actually send()ing to it.)
When you write() a second time, though, and the remote peer has definitely
closed the socket (not only shutdown() writing), the local TCP stack has probably
already received a reset packet from the peer informing it about the error on
the last transmitted packet. Only then can write() return an error, telling
its user that this pipe is broken (EPIPE error code).
If the remote peer has only shutdown() writing, but still has the socket open,
its TCP stack will successfully receive the packet and will acknowledge the
received data back to the sender.
if you read the whole man page then you would read, in error return values:
"EPIPE fd is connected to a pipe or *socket whose reading end is closed*."
So, the call to write() will not return a 0 but rather -1 and errno will be set to 'EPIPE'
Everything compiles without errors and warnings. I start the program. I visit localhost:8080 and the program stops - great. I try to run the program again and I get Error: unable to bind message. Why?
Code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PORT 8080
#define PROTOCOL 0
#define BACKLOG 10
int main()
{
int fd;
int connfd;
struct sockaddr_in addr; // For bind()
struct sockaddr_in cliaddr; // For accept()
socklen_t cliaddrlen = sizeof(cliaddr);
// Open a socket
fd = socket(AF_INET, SOCK_STREAM, PROTOCOL);
if (fd == -1) {
printf("Error: unable to open a socket\n");
exit(1);
}
// Create an address
//memset(&addr, 0, sizeof addr);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
if ((bind(fd, (struct sockaddr *)&addr, sizeof(addr))) == -1) {
printf("Error: unable to bind\n");
printf("Error code: %d\n", errno);
exit(1);
}
// List for connections
if ((listen(fd, BACKLOG)) == -1) {
printf("Error: unable to listen for connections\n");
printf("Error code: %d\n", errno);
exit(1);
}
// Accept connections
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
printf("Error: unable to accept connections\n");
printf("Error code: %d\n", errno);
exit(1);
}
//read(connfd, buffer, bufferlen);
//write(connfd, data, datalen);
// close(connfd);
return 0;
}
Use the SO_REUSEADDR socket option before calling bind(), in case you have old connections in TIME_WAIT or CLOSE_WAIT state.
Uses of SO_REUSEADDR?
In order to find out why, you need to print the error; the most likely reason is that another program is already using the port (netstat can tell you).
Your print problem is that C format strings use %, not &. Replace the character in your print string, and it should work.
First, have a look into the following example:
Socket Server Example
Second: The reason why the second bind fails is, because your application crashed, the socket is still bound for a number of seconds or even minutes.
Check with the "netstat" command if the connection is still open.
Try putting the following code just before bind()
int opt = 1;
if (setsockopt(<Master socket FD>, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))<0) {perror("setsockopt");exit(EXIT_FAILURE);}if(setsockopt(<Master socket FD>, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(opt))<0) {
perror("setsockopt");exit(EXIT_FAILURE);}
Reason behind socket bind error 98:
Socket is 4 tuple (server ip, server port , client ip, client port)
When any two sockets tuples matches , error 98 is thrown
When you terminate the code on server side, it means you are ending connection with tcp client .
Now server is the one which sends FIN to client and goes to TIME_WAIT state.
Typically , in TIME_WAIT sate server sends ack packets continuously to client , assuming that if any ack gets lost in between .
Time out it depends on implementation of code . It could be from 30 seconds to 2 minutes or more.
If you run the code again , server is in TIME_WAIT , hecne port is already in use . This is because any service running on server will use fixed port which is not the case with client .
That is why in real life, server will never send FIN to client .It is client who sends FIN in order to end connection.
Even if client connects again before timeout of TIME_WAIT, he will be connected to server because , he will use now a different port thus socket tuple changes .
If it is implemented in reverse way , if server sends FIN , there after any new connection would not be accept till timeout ends .
Why port is busy ?
It is because in TIME_Wait , the one who sends FIN first, must transmit ack packets continuously till timeout expires.