Después de accept() en un socket, estoy tratando de configurar el mantenimiento de TCP.
SockConnected = accept(SockListen, &RemoteAddr, &RemoteLen); /* A bit of checking goes here */ if (setsockopt (SockConnected , SOL_SOCKET, SO_KEEPALIVE, (ST_CHAR *) &sockopt_on, sizeof (int) ) ) { /* Error logging */ } if (setsockopt(SockConnected , IPPROTO_TCP, TCP_KEEPIDLE, (char*)&(sockopt_tcp_keep_idle), sizeof(sockopt_tcp_keep_idle))) { /* Error logging */ } if (setsockopt(SockConnected, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&(sockopt_tcp_keep_intvl), sizeof(sockopt_tcp_keep_intvl))) { /* Error logging */ } if (setsockopt(SockConnected, IPPROTO_TCP, TCP_KEEPCNT, (char*)&(sockopt_tcp_keep_cnt), sizeof(sockopt_tcp_keep_cnt))) { /* Error logging */ } Después de llamar a getsockopt() para las cuatro propiedades, todo parece estar bien. Revisé Wireshark y no se están enviando paquetes Keep Alive. Tuve que cambiar SOL_TCP a IPPROTO_TCP , porque al llamar a setsockopt() para TCP_KEEPIDLE devolvía errno 92 (Protocolo no encontrado).
Estoy haciendo lo mismo después de llamar a socket() para una conexión saliente y funciona perfectamente.
Estoy usando C y Linux.
¿Hay alguna razón por la que setsockopt no funcione después de aceptar?
Aquí hay un ejemplo de trabajo mínimo. Si te funciona, puedes usarlo como referencia.
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/signal.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/tcp.h> #define check(expr) if (!(expr)) { perror(#expr); kill(0, SIGTERM); } void enable_keepalive(int sock) { int yes = 1; check(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1); int idle = 1; check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(int)) != -1); int interval = 1; check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(int)) != -1); int maxpkt = 10; check(setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(int)) != -1); } int main(int argc, char** argv) { check(argc == 2); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(12345); check(inet_pton(AF_INET, argv[1], &addr.sin_addr) != -1); int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); check(server != -1); int yes = 1; check(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != -1); check(bind(server, (struct sockaddr*)&addr, sizeof(addr)) != -1); check(listen(server, 1) != -1); if (fork() == 0) { int client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); check(client != -1); check(connect(client, (struct sockaddr*)&addr, sizeof(addr)) != -1); printf("connected\n"); pause(); } else { int client = accept(server, NULL, NULL); check(client != -1); enable_keepalive(client); printf("accepted\n"); wait(NULL); } return 0; } Salida de ejemplo ( tcpdump informa paquetes de actividad cada segundo):
$ ./a.out 127.0.0.1 & [1] 14010 connected accepted $ tcpdump -n -c4 -ilo port 12345 dropped privs to tcpdump tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes 18:00:35.173892 IP 127.0.0.1.12345 > 127.0.0.1.60998: Flags [.], ack 510307430, win 342, options [nop,nop,TS val 389745775 ecr 389745675], length 0 18:00:35.173903 IP 127.0.0.1.60998 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745775 ecr 389745075], length 0 18:00:36.173886 IP 127.0.0.1.12345 > 127.0.0.1.60998: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745875 ecr 389745775], length 0 18:00:36.173898 IP 127.0.0.1.60998 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 389745875 ecr 389745075], length 0 4 packets captured 8 packets received by filter 0 packets dropped by kernelSO_KEEPALIVE debe usarse con SOL_SOCKET , no con IPPROTO_TCP o SOL_TCP . Ver socket(7) y tcp(7) .
Así que prueba esto:
int val = 1; setsockopt(SockConnected, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); Supongo que TCP_KEEPIDLE y opciones similares simplemente se ignoran si SO_KEEPALIVE no se configuró correctamente, y SOL_TCP es un sinónimo de IPPROTO_TCP .
Si no ayuda, considere publicar un ejemplo mínimo que reproduzca el problema.