windows下怎么设置recv()的非阻塞模式
时间: 2024-10-22 08:04:41 浏览: 11
在Windows环境下,为了设置`recv()`函数为非阻塞模式,你需要使用` overlapped I/O` 和 `WSAEventSelect` 或者 `CreateIoCompletionPort` 等机制。以下是基本步骤:
1. **初始化OVERLAPPED结构**:
使用` overlapped` 结构体来保存I/O操作的状态。这通常包括一个事件句柄(`hEvent`),用于接收异步完成的通知。
```cpp
WSABUF buf;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(OVERLAPPED));
buf.buf = buffer;
buf.len = buffer_length;
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
```
2. **设置socket选项**:
使用`ioctlsocket()` 函数设置SO_UPDATE_ACCEPT_CONTEXT选项,将`OVERLAPPED`指针关联到套接字上。这一步很重要,因为后续的`recv()`会通过这个结构来完成异步操作。
```cpp
u_long updateContext = (ULONG_PTR)&overlapped;
if (ioctlsocket(socket, FIONBIO, &updateContext) == SOCKET_ERROR) {
// 处理错误
}
```
3. **注册事件**:
可以选择使用`WSAEventSelect()` 或 `CreateIoCompletionPort()` 来注册套接字事件。例如,如果你使用`WSAEventSelect()`:
```cpp
DWORD dwError = WSAEventSelect(socket, hEvent, EV_RXCHAR | EV_ERR);
if (dwError != 0) {
// 处理错误
}
```
4. **发起接收请求**:
使用`recv()`函数,现在它不会阻塞,而是立即返回,如果数据可用则填充缓冲区并唤醒等待线程。
```cpp
int bytesReceived = recv(socket, &buf.buf, buf.len, MSG_PEEK);
if (bytesReceived > 0) {
// 数据已准备好,处理数据...
} else if (bytesReceived == 0) { // 连接关闭
// 处理结束连接
} else { // 错误
DWORD error = GetLastError();
// 检查错误...
}
```
5. **检查结果和取消事件**:
当你处理完数据或者遇到错误后,需要关闭或取消注册事件,以及释放`OVERLAPPED`结构中的资源。
```cpp
if (overlapped.hEvent != NULL) {
CloseHandle(overlapped.hEvent);
}
// 如果不再需要接收,可以设置套接字为阻塞模式
if (ioctlsocket(socket, FIONBIO, NULL) == SOCKET_ERROR) {
// 处理错误
}
```
阅读全文