在套接字上的accept()
之后,我试图configurationTCP keepalive。
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 */ }
在为所有四个属性调用getsockopt()
后,一切似乎都没问题。 我已经检查了Wireshark,并且没有Keep alive包被发送。 我必须将SOL_TCP
更改为IPPROTO_TCP
,因为在为TCP_KEEPIDLE
调用setsockopt()
,它将返回errno 92(Protocol not found)。
在为传出连接调用socket()
之后,我正在做同样的事情,并且工作正常。
我正在使用C和Linux。
接受之后, setsockopt
可能不工作有什么原因吗?
这是一个最小的工作示例。 如果它适合你,你可以用它作为参考。
#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; }
输出示例( tcpdump
每秒报告keepalive数据包):
$ ./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 kernel
SO_KEEPALIVE
应与SOL_SOCKET
一起使用,而不是IPPROTO_TCP
或SOL_TCP
。 请参阅socket(7)和tcp(7) 。
所以试试这个:
int val = 1; setsockopt(SockConnected, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
如果SO_KEEPALIVE
设置不正确,我猜TCP_KEEPIDLE
和类似的选项会被忽略,而SOL_TCP
是IPPROTO_TCP
的同义词。
如果没有帮助,请考虑发布一个能够重现问题的最小示例。