recv函数详解
recv函数是WinSock编程中用于从已连接的套接字或绑定的无连接套接字接收数据的核心函数,该函数通过复制协议接收到的数据到应用程序指定的缓冲区来实现数据的接收,以下是对recv函数的详细解析:
一、函数原型
int WSAAPI recv( SOCKET s, char *buf, int len, int flags );
参数 | 类型 | 说明 |
s | SOCKET | 标识已连接套接字的描述符。 |
buf | char | 指向缓冲区的指针,以接收传入的数据。 |
len | int | buf 参数指向的缓冲区的长度(以字节为单位)。 |
flags | int | 一组影响此功能行为的标志。 |
二、返回值
如果未发生错误,recv将返回收到的字节数,buf
参数指向的缓冲区将包含接收的这些数据。
如果连接已正常关闭,则返回值为零。
如果发生错误,则返回值为SOCKET_ERROR
,并且可以通过调用WSAGetLastError
来检索特定的错误代码。
三、参数详解
1、s (SOCKET): 标识一个已连接的套接字的描述符,这个套接字必须已经通过connect
或accept
与远程端点建立了连接。
2、**buf (char*)**: 指向用于接收传入数据的缓冲区的指针,这个缓冲区必须足够大,以容纳预期接收的数据量,如果接收到的数据大于缓冲区的大小,多余的数据将被截断,并且需要多次调用recv来完整接收数据。
3、len (int):buf
参数指向的缓冲区的长度(以字节为单位),它指定了缓冲区的最大容量,即最多可以接收多少字节的数据。
4、flags (int): 一组影响此函数行为的标志,常见的标志包括:
MSG_PEEK
: 查看传入数据,数据将被复制到缓冲区中,但并不从输入队列中删除。
MSG_OOB
: 处理带外数据(参见2.2.3节具体讨论)。
MSG_WAITALL
: 仅当发生以下事件之一时,接收请求才会完成:调用方提供的缓冲区已完全满;该连接已关闭;请求已取消或发生错误,如果基础传输不支持MSG_WAITALL
,或者套接字处于非阻塞模式,则此调用将失败并出现WSAEOPNOTSUPP
,如果MSG_WAITALL
与MSG_OOB
、MSG_PEEK
或MSG_PARTIAL
一起指定,则此调用将失败并显示WSAEOPNOTSUPP
,数据报套接字或面向消息的套接字不支持此标志。
四、错误代码
WSANOTINITIALISED
: 在使用此函数之前,必须成功调用WSAStartup
。
WSAENETDOWN
: 网络子系统失败。
WSAEFAULT
:buf
参数未完全包含在用户地址空间的有效部分。
WSAENOTCONN
: 套接字未连接。
WSAEINTR
: 阻塞进程被WSACancelBlockingCall
取消。
WSAEINPROGRESS
: 阻止 Windows Sockets 1.1 调用正在进行,或者服务提供程序仍在处理回调函数。
WSAENETRESET
: 对于面向连接的套接字,此错误表示连接已中断,因为保持活动检测到操作正在进行时失败,对于数据报套接字,此错误显示生存时间已经过期。
WSAENOTSOCK
: 描述符不是套接字。
WSAEOPNOTSUPP
: 指定了MSG_OOB
,但套接字不是流样式(如类型SOCK_STREAM
),与此套接字关联的通信域中不支持 OOB 数据,或者套接字是单向的,仅支持发送操作。
WSAESHUTDOWN
: 套接字已关闭,当一个套接字以SD_SEND
或SD_BOTH
为参数调用shutdown
关闭后,无法接收套接字上的更多数据。
WSAEWOULDBLOCK
: 套接字标记为非阻塞,接收操作将阻塞。
WSAEMSGSIZE
: 消息太大,无法放入指定的缓冲区,并且已被截断。
WSAEINVAL
: 套接字未绑定,或者指定了未知标志,或者为启用了SO_OOBINLINE
的套接字指定了MSG_OOB
,或者仅对字节流套接字len
为零或负数。
WSAECONNABORTED
: 由于超时或其他故障,虚拟线路已终止,因为套接字不可再用,应用程序应关闭套接字。
WSAETIMEDOUT
: 因为网络故障或对等系统无法响应,已经丢弃了连接。
WSAECONNRESET
: 执行硬性或异常关闭的远程端重置了虚拟线路,因为套接字不可再用,应用程序应关闭套接字,在 UDP 数据报套接字上,此错误将指示以前的发送操作导致 ICMP“端口无法访问”消息。
五、使用示例
以下是一个简单的示例代码,演示如何使用recv函数从TCP连接的另一端接收数据:
#define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <Ws2tcpip.h> #include <stdio.h> // Link with ws2_32.lib #pragma comment(lib, "Ws2_32.lib") #define DEFAULT_BUFLEN 512 #define DEFAULT_PORT "27015" int main() { WSADATA wsaData; int iResult; SOCKET ConnectSocket = INVALID_SOCKET; struct sockaddr_in clientService; char *sendbuf = "this is a test"; char recvbuf[DEFAULT_BUFLEN]; int recvbuflen = DEFAULT_BUFLEN; // Initialize Winsock iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); if (iResult != NO_ERROR) { printf("WSAStartup failed: %d ", iResult); return 1; } // Create a SOCKET for connecting to server ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ConnectSocket == INVALID_SOCKET) { printf("Error at socket(): %ld ", WSAGetLastError()); WSACleanup(); return 1; } // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(27015); // Connect to server. iResult = connect(ConnectSocket, (SOCKADDR *)&clientService, sizeof(clientService)); if (iResult == SOCKET_ERROR) { closesocket(ConnectSocket); printf("Unable to connect to server: %ld ", WSAGetLastError()); WSACleanup(); return 1; } // Send an initial buffer iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0); if (iResult == SOCKET_ERROR) { printf("send failed: %d ", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } printf("Bytes Sent: %ld ", iResult); // shutdown the connection since no more data will be sent iResult = shutdown(ConnectSocket, SD_SEND); if (iResult == SOCKET_ERROR) { printf("shutdown failed: %d ", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } // Receive until the peer closes the connection do { iResult = recv(ConnectSocket, recvbuf, len(recvbuf), 0); if (iResult > 0) { printf("Bytes received: %d ", iResult); printf("Received data: %s ", recvbuf); } else if (iResult == 0) { printf("Connection closed "); } else { printf("recv failed: %d ", WSAGetLastError()); } } while (iResult > 0); // Clean up and close sockets closesocket(ConnectSocket); WSACleanup(); return 0; }
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1247783.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复