setsockopt
函数是用于设置套接字选项的系统调用,它在多种网络编程场景中非常有用。通过 setsockopt
函数,可以设置各种套接字选项。
超时
接发超时
setsockopt
函数原型
在C语言中,setsockopt
函数的原型如下:
1 2 3 4
| #include <sys/types.h> #include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
sockfd
:要设置选项的套接字文件描述符。
level
:选项所在的协议层,例如 SOL_SOCKET
表示套接字层,IPPROTO_TCP
表示TCP协议层。
optname
:要设置的选项名称。
optval
:指向包含选项值的缓冲区的指针。
optlen
:选项值的长度。
设置 send
和 recv
超时选项
要设置 send
和 recv
的超时选项,可以使用 SO_SNDTIMEO
和 SO_RCVTIMEO
选项,它们分别用于设置发送和接收的超时时间。
服务端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| #include <iostream> #include <cstring> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
int main() { int server_fd, new_socket; struct sockaddr_in address; int addrlen = sizeof(address); char buffer[1024] = {0}; const char *response = "Hello from server";
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); }
address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(8080);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); }
if (listen(server_fd, 3) < 0) { perror("listen"); close(server_fd); exit(EXIT_FAILURE); }
struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0;
if (setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { perror("setsockopt"); close(server_fd); exit(EXIT_FAILURE); }
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { perror("accept"); close(server_fd); exit(EXIT_FAILURE); }
int bytes_received = recv(new_socket, buffer, 1024, 0); if (bytes_received < 0) { perror("recv"); } else { buffer[bytes_received] = '\0'; std::cout << "Received data: " << buffer << std::endl; }
send(new_socket, response, strlen(response), 0); std::cout << "Response sent" << std::endl;
close(new_socket); close(server_fd); return 0; }
|
客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <iostream> #include <cstring> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
int main() { int sock = 0; struct sockaddr_in serv_addr; char buffer[1024] = {0}; const char *message = "Hello from client"; struct timeval timeout;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket failed"); exit(EXIT_FAILURE); }
serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { perror("inet_pton failed"); close(sock); exit(EXIT_FAILURE); }
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("connect failed"); close(sock); exit(EXIT_FAILURE); }
send(sock, message, strlen(message), 0); std::cout << "Message sent" << std::endl;
int bytes_received = recv(sock, buffer, 1024, 0); if (bytes_received < 0) { perror("recv"); } else { buffer[bytes_received] = '\0'; std::cout << "Received response: " << buffer << std::endl; }
close(sock); return 0; }
|
当服务器超过给定的时间,就会返回accept: Resource temporarily unavailable
TCP连接超时
TCP_USER_TIMEOUT
选项用于设置TCP连接的超时时间。如果在指定的时间内没有收到对端的确认,连接将被关闭。
1 2 3 4 5 6
| int timeout_ms = 10000;
if (setsockopt(sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout_ms, sizeof(timeout_ms)) < 0) { perror("setsockopt"); }
|
close-fd超时
SO_LINGER
选项用于设置 close
操作的行为。通过设置 SO_LINGER
选项,可以控制套接字关闭时的延迟时间。
1 2 3 4 5 6 7 8
| struct linger ling; ling.l_onoff = 1; ling.l_linger = 5;
if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0) { perror("setsockopt"); }
|