socket编程:recv()函数详解

官方文档:https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv

1. 函数原型

recv函数从连接的套接字或绑定的无连接套接字接收数据。

int WSAAPI recv(
  SOCKET s,//标识已连接套接字的描述符。
  char   *buf,//指向缓冲区的指针,以接收传入的数据。
  int    len,//buf参数指向的缓冲区的长度(以字节为单位)。
  int    flags//一组影响此功能行为的标志。 
);

**本质:**复制

  • 数据的接收都是由协议本身做的,也就是socket的底层做的,系统会有一段缓冲区,存储着接收到的数据。
  • 咱们外边调用recv的作用,就是通过socket找到这个缓冲区,并把数据复制到咱们的参数2指向的地址,复制参数3个。

2. 函数使用

#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 __cdecl main() {

    //----------------------
    // Declare and initialize variables.
    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\n", 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\n", 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\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // Send an initial buffer
    iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection since no more data will be sent
    iResult = shutdown(ConnectSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(ConnectSocket);
        WSACleanup();
        return 1;
    }

    // Receive until the peer closes the connection
    do {

        iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
        if ( iResult > 0 )
            printf("Bytes received: %d\n", iResult);
        else if ( iResult == 0 )
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());

    } while( iResult > 0 );

    // cleanup
    closesocket(ConnectSocket);
    WSACleanup();

    return 0;
}

3. 参数详解

  • s

    • 客户端或服务端的socket,每个客户端对应唯一的socket
  • buf

    • 客户端消息的存储空间,也就是个字符数组
    • 一般为1500字节
      • 网络传输的最大单元,1500字节,也就是客户端发过来的数据,一次最大就是1500字节,这是协议规定,这个数值也是根据很多情况,总结出来的最优值
      • 所以客户端最多一组来1500字节,咱们这头1500读一次,就够了。
  • len

    • 想要读取到字节个数,一般是参数2的字节数-1,把\0字符串结尾留出来
  • flags

    • 一般设置为0

    • MSG_PEEK:窥视传入的数据。 数据被复制到缓冲区中,但不会从输入队列中删除。

    • MSG_OOB:处理带外(OOB)数据。

    • MSG_WAITALL:

      仅当发生以下事件之一时,接收请求才会完成:

      • 调用方提供的缓冲区已完全满。
      • 连接已关闭。
      • 该请求已被取消或发生错误。

4. 返回值

  • 读出来的字节大小
    • 读没了咋办?
      • 在recv函数卡着,等着客户端发来数据(即阻塞、同步)
      • 阻塞的
  • 客户端下线,返回0
    • 释放客户端socket
  • 执行失败,返回SOCKET_ERROR
    • WSAGetLastError() 得到错误码
    • 根据错误码信息做相应处理
      • 重启
      • 等待
      • 不用理会
  • 34
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
send函数recv函数是VC++中Socket编程中最常用的两个函数,它们分别用于发送数据和接收数据。 send函数的原型如下: ```c++ int send( SOCKET s, const char* buf, int len, int flags ); ``` 参数说明: - s:需要发送数据的Socket。 - buf:指向包含要发送数据的缓冲区的指针。 - len:要发送的数据的字节数。 - flags:调用方式标志。 返回值说明: - 成功:返回实际发送的字节数。 - 失败:返回SOCKET_ERROR。 recv函数的原型如下: ```c++ int recv( SOCKET s, char* buf, int len, int flags ); ``` 参数说明: - s:需要接收数据的Socket。 - buf:指向接收数据的缓冲区的指针。 - len:要接收的数据的最大字节数。 - flags:调用方式标志。 返回值说明: - 成功:返回实际接收的字节数。 - 失败:返回SOCKET_ERROR。 send和recv函数的使用方法如下: ```c++ char sendbuf[] = "Hello, world!"; int sendbuflen = sizeof(sendbuf); int sentbytes = 0; sentbytes = send(sock, sendbuf, sendbuflen, 0); if (sentbytes == SOCKET_ERROR) { // 发送失败 } char recvbuf[1024]; int recvbuflen = sizeof(recvbuf); int receivedbytes = 0; receivedbytes = recv(sock, recvbuf, recvbuflen, 0); if (receivedbytes == SOCKET_ERROR) { // 接收失败 } ``` 使用send和recv函数时需要注意以下几点: - send和recv函数都是阻塞式的,即程序会一直等待直到发送或接收完所有数据。 - 如果发送或接收的数据量比较大,需要多次调用send或recv函数。 - 如果发送或接收的数据量比较小,建议使用TCP_NODELAY选项关闭Nagle算法,以提高发送和接收的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级D洋葱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值