escribir en un socket cerrado no generó un SIGPIPE como se esperaba
Frecuentes
Visto 1,243 equipos
1
I've already read about how to prevent SIGPIPE
, then I write a small program to test it. Here is the code.
servidor.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void hdl(int sig_num, siginfo_t *sig_info, void *context)
{
printf("got you, SIGPIPE!\n");
}
int main()
{
int sfd, cfd;
struct sockaddr_in saddr, caddr;
struct sigaction act;
memset (&act, '\0', sizeof(act));
act.sa_sigaction = hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGPIPE, &act, NULL) < 0) {
return 1;
}
sfd= socket(AF_INET, SOCK_STREAM, 0);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=inet_addr("192.168.22.91");
saddr.sin_port=htons(12345);
if(bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr)) )
{
printf("bind error\n");
return -1;
}
if(listen(sfd, 1))
{
printf("error\n");
return -1;
}
char buf[1024] = {0};
while(1) {
printf("Server listening...\n");
cfd=accept(sfd, (struct sockaddr *)NULL, NULL);
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
if((ret = write(cfd, buf, strlen(buf)))<0)
{
if(errno == EPIPE)
fprintf(stderr, "SIGPIPE");
}
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);
}
close(sfd);
}
cliente.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int ret, fd;
struct sockaddr_in sa_dst;
char buffer[] = "hello, world";
char rcv_buf[128] = {0};
fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sa_dst, 0, sizeof(struct sockaddr_in));
sa_dst.sin_family = AF_INET;
sa_dst.sin_port = htons(12345);
sa_dst.sin_addr.s_addr = inet_addr("192.168.22.91");
ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr));
if(ret != -1)
{
send(fd, buffer, strlen(buffer), 0);
close(fd);
}
return 0;
}
When I run the server and the client on the same linux machine, on the server side, the first write()
returns the number of bytes written while I expect a SIGPIPE
signal because I closed the socket on the client side, the second write()
does generate a SIGPIPE
señal.
But when I ran the client on another linux machine or on a Windows machine(implement the same client with Winsock), I did't catch any SIGPIPE
signal, and the second write()
still returns the size of the buffer
. Can someone tell me what's going on?
2 Respuestas
1
It can't happen on the first write, for two reasons:
- The localhost doesn't know that the peer has closed the socket for reading. A FIN has been received but that could just be because the peer has shutdown for output. Only an RST will tell it that, and it doesn't get that util the next I/O at the earliest.
- Almacenamiento en búfer.
NB you're corrupting the value of errno
al perror(),
so testing it afterwards isn't valid.
contestado el 29 de mayo de 14 a las 08:05
I use tcpdump to capture the packets between client and server, a RST
does send to server after first write
. Then I'm wondering why no SIGPIPE
signal when the server and client run on different machines? - volar
You mean there was an RST but no SIGPIPE in the same test? - user207421
Yes. no SIGPIPE
RST
when C&S running on different machines. - volar
So the RST must have come after the write()-s returned. Buffering would explain that. - user207421
0
Just Change this in SERVER and it will work
fcntl(cfd, F_SETFL, O_NONBLOCK);
int size = read(cfd, buf, 1024);
if(size == -1)
printf("read error\n");
sleep(2); // sleep for a while to make sure the client closed the socket
int ret;
ret = write(cfd, buf, strlen(buf));
sleep(2);
ret = write(cfd, buf, strlen(buf)); // write again.
printf("write return %d\n", ret);
Respondido 03 Feb 15, 13:02
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c sockets network-programming sigpipe or haz tu propia pregunta.
Strictly, it is not safe to call
printf()
in a signal handler. There's a list of safe functions, andprintf()
is not in the list. I doubt that's the main problem, but do remember for future. You didn't set thesa_mask
member of your structure; since you aren't using the extra information in your signal handler, you shouldn't use SA_SIGINFO. - Jonathan Leffler@JonathanLeffler Thanks for the tip. I use
sigaction
just to test whether SIGPIPE signal is generated, so don't noticeprintf
is not in the list of function we can safely call from a signal handler. - jflyThere's no sigpipe on windows - zoska
@zoska Server always runs on linux, only client may run on Windows. - jfly