WSARecv()是从一个套接口接收数据的程序。主要用于在重叠模型中接收数据。
int WSARecv(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Parameters
s
[in] A descriptor identifying a connected socket.
lpBuffers
[in, out] A pointer to an array of WSABUF structures. Each WSABUF structure contains a pointer to a buffer and the length, in bytes, of the buffer.
dwBufferCount
[in] The number of WSABUF structures in the lpBuffers array.
lpNumberOfBytesRecvd
[out] A pointer to the number, in bytes, received by this call if the receive operation completes immediately. If the lpOverlapped parameter is non-NULL, this parameter is optional and can be set to NULL.
lpFlags
[in, out] A pointer to flags used to modify the behavior of the WSARecv function call.
lpOverlapped
[in] A pointer to a WSAOVERLAPPED structure (ignored for nonoverlapped sockets).
lpCompletionRoutine
[in] A pointer to the completion routine called when the receive operation has been completed (ignored for nonoverlapped sockets).
Return Value
If no error occurs and the receive operation has completed immediately, WSARecv returns zero. In this case, the completion routine will have already been scheduled to be called once the calling thread is in the alertable state. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError. The error code WSA_IO_PENDING indicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time. Any other error code indicates that the overlapped operation was not successfully initiated and no completion indication will occur.
如果没有发生错误,并且接收操作已经立即完成,则WSARecv返回零。在这种情况下,一旦调用线程处于alertable状态,完成例程将被调度为被调用。否则,将返回SOCKET_ERROR值,并通过调用WSAGetLastError检索特定的错误代码。错误代码WSA_IO_PENDING指示重叠操作已经成功启动,稍后将指示完成。任何其他错误代码都表示没有成功启动重叠操作,也不会出现完成指示。
看实例代码,从代码中窥视其用法:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable: 4127) // Conditional expression is a constant
#pragma comment(lib, "ws2_32.lib")
#define DATA_BUFSIZE 5
#define MAX_ASYN_IO_BUFF_COUNT 2
/**
@name : 重叠结构,可用于异步IO
*/
struct AsynIoResultImp: public OVERLAPPED
{
AsynIoResultImp()
{
connSocket = INVALID_SOCKET;
IniBuf();
}
// 测试用就不考虑释放了
void IniBuf()
{
for (size_t i = 0; i < MAX_ASYN_IO_BUFF_COUNT; ++i)
{
buffList[i].len = DATA_BUFSIZE;
buffList[i].buf = new char[DATA_BUFSIZE];
}
buffCount = MAX_ASYN_IO_BUFF_COUNT;
recvBytes = 0;
}
SOCKET connSocket;
WSABUF buffList[MAX_ASYN_IO_BUFF_COUNT];
DWORD buffCount;
DWORD recvBytes;
};
void main(int argc, char **argv)
{
WSADATA wsd;
struct addrinfo *result = NULL, *ptr = NULL, hints = { 0 };
DWORD Flags;
int err, rc;
AsynIoResultImp io;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0)
{
fprintf(stderr, "Unable to load Winsock: %d\n", rc);
return;
}
// Initialize the hints to retrieve the server address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo("192.168.10.42", "3014", &hints, &result);
if (rc != 0)
{
fprintf(stderr, "getaddrinfo failed: %d\n", rc);
return;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
{
io.connSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (io.connSocket == INVALID_SOCKET)
{
fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
return;
}
rc = connect(io.connSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
if (WSAECONNREFUSED == (err = WSAGetLastError()))
{
closesocket(io.connSocket);
io.connSocket = INVALID_SOCKET;
continue;
}
fprintf(stderr, "connect failed: %d\n", err);
freeaddrinfo(result);
closesocket(io.connSocket);
return;
}
break;
}
if (io.connSocket == INVALID_SOCKET)
{
fprintf(stderr, "Unable to establish connection with the server!\n");
freeaddrinfo(result);
return;
}
printf("Client connected...\n");
// Create an event handle and setup an overlapped structure.
io.hEvent = WSACreateEvent();
if (io.hEvent == NULL) {
fprintf(stderr, "WSACreateEvent failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(io.connSocket);
return;
}
char data[DATA_BUFSIZE+1] = { 0 };
// Call WSARecv until the peer closes the connection
// or until an error occurs
while (1)
{
io.IniBuf();
Flags = 0;
rc = WSARecv(io.connSocket, (LPWSABUF)io.buffList, io.buffCount, &io.recvBytes, &Flags, &io, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError())))
{
fprintf(stderr, "WSARecv failed: %d\n", err);
break;
}
rc = WSAWaitForMultipleEvents(1, &io.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED)
{
fprintf(stderr, "WSAWaitForMultipleEvents failed: %d\n", WSAGetLastError());
break;
}
rc = WSAGetOverlappedResult(io.connSocket, &io, &io.recvBytes, FALSE, &Flags);
if (rc == FALSE)
{
fprintf(stderr, "WSARecv operation failed: %d\n", WSAGetLastError());
break;
}
for (size_t i = 0; i < MAX_ASYN_IO_BUFF_COUNT; ++i)
{
size_t len = min(DATA_BUFSIZE, io.recvBytes - i*DATA_BUFSIZE);
memmove(data, io.buffList[i].buf, len);
data[len] = '\0';
printf("Read %d bytes %s\n", io.recvBytes, data);
if (len != DATA_BUFSIZE) { break; }
}
WSAResetEvent(io.hEvent);
// If 0 bytes are received, the connection was closed
if (io.recvBytes == 0)
break;
}
WSACloseEvent(io.hEvent);
closesocket(io.connSocket);
freeaddrinfo(result);
WSACleanup();
return;
}
服务器发送数据:1234567890123
收到结果如下: