WinSock中关于阻塞接收/发送超时的一个BUG

在WinSock中,recvfrom和recv函数默认为永久阻塞模式,可通过setsockopt设置SO_RCVTIMEO来实现超时控制。示例代码展示了如何设置阻塞时间以避免无限等待。虽然Linux平台对此处理方式不同,但作者认为Linux的相对时间设定更合理。
摘要由CSDN通过智能技术生成

在阻塞模型中,recvfrom和recv函数默认都是永久阻塞的,即没有数据到来和不发生错误的情况下函数的调用不会返回,但是可以调用setsockopt来设置阻塞时间。设置了合适的阻塞时间,可以让接收函数超时返回。

int setsockopt(
  __in          SOCKET s,
  __in          int level,
  __in          int optname,
  __in          const char* optval,
  __in          int optlen
);
SO_RCVTIMEO int Receives time-out in milliseconds (available in the Microsoft implementation of Windows Sockets 2).
SO_SNDTIMEO int Sends time-out in milliseconds (available in the Microsoft implementation of Windows Sockets 2).

SO_RECVTIMEO即可控制接收函数的超时时间。例代码如下:

#include <WinSock2.h>
#include <Windows.h>
#include <stdio.h>
#include <time.h>

#pragma comment(lib, "
好的,以下是一个简单的基于 Winsock 的 C/S 通讯例子,其客户端和服务器端都是使用 C 语言编写的。 服务器端代码: ```c #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsa; SOCKET server_sock, client_sock; struct sockaddr_in server_addr, client_addr; int client_addr_size = sizeof(client_addr); char buffer[1024] = {0}; // 初始化 Winsock if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { printf("Failed. Error Code : %d", WSAGetLastError()); return 1; } // 创建服务器端套接字 if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { printf("Could not create socket : %d", WSAGetLastError()); WSACleanup(); return 1; } // 初始化服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(8888); // 绑定服务器端套接字 if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) { printf("Bind failed with error code : %d", WSAGetLastError()); closesocket(server_sock); WSACleanup(); return 1; } // 监听客户端连接请求 listen(server_sock, 3); printf("Server listening on port 8888...\n"); // 接收客户端连接并处理 while ((client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_size)) != INVALID_SOCKET) { printf("Connection accepted from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 接收客户端数据并回复 while (1) { // 接收客户端数据 int num_bytes = recv(client_sock, buffer, sizeof(buffer), 0); if (num_bytes == SOCKET_ERROR) { printf("recv failed with error code : %d", WSAGetLastError()); closesocket(client_sock); WSACleanup(); return 1; } if (num_bytes == 0) { printf("Connection closed by client.\n"); closesocket(client_sock); break; } // 处理客户端数据 buffer[num_bytes] = '\0'; printf("Received message from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer); // 回复客户端数据 if (send(client_sock, buffer, num_bytes, 0) == SOCKET_ERROR) { printf("send failed with error code : %d", WSAGetLastError()); closesocket(client_sock); WSACleanup(); return 1; } } } // 关闭服务器端套接字 closesocket(server_sock); // 清理 Winsock WSACleanup(); return 0; } ``` 客户端代码: ```c #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsa; SOCKET sock; struct sockaddr_in server_addr; char buffer[1024] = {0}; // 初始化 Winsock if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { printf("Failed. Error Code : %d", WSAGetLastError()); return 1; } // 创建客户端套接字 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { printf("Could not create socket : %d", WSAGetLastError()); WSACleanup(); return 1; } // 初始化服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8888); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 连接服务器端套接字 if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { printf("Connect failed with error code : %d", WSAGetLastError()); closesocket(sock); WSACleanup(); return 1; } printf("Connected to server.\n"); // 发送数据到服务器端并接收回复 while (1) { // 发送数据到服务器端 printf("Enter message: "); gets_s(buffer, sizeof(buffer)); if (send(sock, buffer, strlen(buffer), 0) == SOCKET_ERROR) { printf("send failed with error code : %d", WSAGetLastError()); closesocket(sock); WSACleanup(); return 1; } // 接收服务器端回复 int num_bytes = recv(sock, buffer, sizeof(buffer), 0); if (num_bytes == SOCKET_ERROR) { printf("recv failed with error code : %d", WSAGetLastError()); closesocket(sock); WSACleanup(); return 1; } if (num_bytes == 0) { printf("Connection closed by server.\n"); closesocket(sock); break; } // 处理服务器端回复 buffer[num_bytes] = '\0'; printf("Received message from server: %s\n", buffer); } // 关闭客户端套接字 closesocket(sock); // 清理 Winsock WSACleanup(); return 0; } ``` 这个例子简单地实现了一个回显服务器,客户端向服务器发送数据,服务器接收到数据后将其回传给客户端。你可以在这个例子的基础上进行扩展和修改,以满足你的具体需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值