views:

545

answers:

3

In socket programming in Linux I need to write data in socket but I don't know socket is open or close . how to I know that socket is open and close without read ?

printf("befor read%d\n", n);
bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
    break;
}
printf("befor write%d, s: %d \n", n , sockfd);

n = write(newsockfd, buffer, n);
if (n <= 0)
{
    break;
}

I read from sockfd and I sure this connection is open . When to write buffer in newsockfd I don't know newsockfd is open or close how to check newsockfd is closed ?


I know problem . in middle of writing connection closed . for example write 1024 data in 500 connection closed and program closed. how to avoid this ?

+6  A: 

The way to check if you can write to a socket is, surprisingly, to try and write to it :-)

If the socket has been closed, you will get a -1 return code from write and you can examine errno to see what the problem was.

If the socket is still valid but you just can't write any data at the moment, write will return 0. The read call also behaves in a similar fashion, returning -1 if there's a problem.

Basically, for write:

  • if you get back a -1, there's been a problem and you should check errno to see if it's recoverable or fatal.
  • If you get back a 0, then you can't write anything at the moment (may be a network backlog or some other problem but definitely not (yet) fatal).
  • If you get a value less that what you wanted, then some of the data has been sent. Adjust your pointers so you can try send the rest in the next cycle. Do not assume a positive return value means the entire block has been sent.
  • If you get back the same number as the number of bytes you tried to send, the entire buffer has been accepted for delivery.
  • If you get back more than what you asked to be sent, send an email off to the kernel developers with some acerbic comment. Linus et al will love that :-)

Update: As caf has pointed out in the comments, I forgot to take into account the signal handling. You have to ignore the broken pipe signal or write will fail internally by raising that signal.

You can do this by inserting:

struct sigaction new_actn, old_actn;
new_actn.sa_handler = SIG_IGN;
sigemptyset (&new_actn.sa_mask);
new_actn.sa_flags = 0;
sigaction (SIGPIPE, &new_actn, &old_actn);

before starting to use the socket functions. You can then use:

sigaction (SIGPIPE, &old_actn, NULL);

to restore the previous signal handling.

paxdiablo
in the next line see if(n<=0) but in write function some error occured and close program
SjB
@SjB, do *not* assume problems if `write` returns 0. This can happen if there's a temporary network backlog. If the backlog turns into a real problem, the session will be shutdown and you will eventually get -1. Until then, just keep trying.
paxdiablo
I know problem . in middle of writing connection closed . for example write 1024 data in 500 connection closed and program closed
SjB
pax, you are forgetting that by default trying to `write` to socket that has been closed by the other end will result in your process recieving a `SIGPIPE` signal, the default action of which is to terminate the process.
caf
My mistake. Fixed now (hopefully).
paxdiablo
+1  A: 

Socket programming can be rather tricky, because you often don't know an error has occurred until much later.

For instance, if the machine you are writing to shuts down abnormally, the write call may succeed ( because you were able to write to your internal OS buffers ), only to fail during the close call.

Unless you have an application-layer way of verifying the socket is active ( i.e., sending a message and requiring a response within some time period ) you have no way of knowing. If you are using a standard protocol, something may already exist to handle errors.

So the short answer is that you need to check for error returns from pretty much every call that touches the socket ( read, write, close, etc... ).

Chris Arguin
+1  A: 

I use send() instead write() that handle no signal :

bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
    break;
}
n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL);
if (n2 == -1)
{
    close(sockfd);
    close(newsockfd);
    return;
}
if (n2 != n)
{
    break;
}
SjB
This will work, and the other alternative is to use `sigaction` to ignore `SIGPIPE` (set its handler to `SIG_IGN`).
caf