Basilevs
Basilevs

Reputation: 23916

Writing to closed TCP/IP connection hangs

My TCP/IP client hangs while writing to socket. This happens even if server properly closes an accepted connection with close() (or with shutdown()) call. I've always thought that write should return with ECONNRESET error for this case.

How do i prevent hang ups in synchronous output? Or rather what am I doing wrong so that an error is not reported by write()?

Should I use send() instead of write() or they are interchangeable?

I'm testing networking in a separate application with two threads. Main thread starts server thread, that accepts connection and immediately closes it. Main thread then imitates client behavior by connecting to listening port.

Main thread code:

sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
int s = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s, (sockaddr*)(&serv_addr),  sizeof(serv_addr)) < 0) {
    close(s);
    throw runtime_error(strerror(errno));
}
listen(s,1);
start_thread(s); // posix thread accepting a connection on s is started here
//Code below imitates  TCP/IP client
struct hostent *hp;
struct sockaddr_in addr;
if((hp = gethostbyname(host.c_str())) == NULL){
    throw HErrno();
}
bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int _socket = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_socket < 0) {
    throw Errno();
}
assert(ENOTCONN==107);
assert(_socket>=0);
if(::connect(_socket, (const struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
    throw Errno();
}

while(true) {
  const char a[] = "pattern";
  if (write( _socket, a, 7)<0) // Writes 30000 times, then hangs
     break;
}

Server thread code:

int connection = accept(s);
close(connection);

EDIT: The problem reduced to my programming error. It seems I've failed to start accepting thread properly.

Upvotes: 3

Views: 2351

Answers (2)

fizzer
fizzer

Reputation: 13796

Did you perhaps set up a handler for SIGPIPE instead of setting it to SIG_IGN?

Upvotes: 0

banuj
banuj

Reputation: 3230

Each TCP connection has a receive buffer for storing data that are received but not delivered to application. If in your server you don't do read(), than the data is accumulated in receive buffer, and at one point this receive buffer becomes full, causing TCP sends Window=0 message.

Your server thread code should look like this:

char a[10];
int connection = accept(s);
while(true)
    if (read( connection , a, 7)<=0)
        break;
close(connection);

Upvotes: 1

Related Questions