socket的send(),recv()以及缓冲区之间的关系

来自:
socket编程缓冲区大小对send()的影响_wangst4321的专栏-CSDN博客
TCP/UDP的接收缓冲区和发送缓冲区_Swallow_he的博客-CSDN博客
socket之send与发送缓冲区大小的关系_水果刀的专栏-CSDN博客

每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的流量/拥塞控制便是依赖于这两个独立的缓冲区以及缓冲区的填充状态。

接收缓冲区

接收缓冲区把数据缓存到内核,应用进程一直没有调用recv()进行读取的话,此数据会一直缓存在相应socket的接收缓冲区内。不管进程是否调用recv()读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。

recv():把内核缓冲区中的数据拷贝到应用层用户的buffer里面,并返回。

发送缓冲区

进程调用send()发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核(拷贝到内核就返回)发送缓冲区之中,然后send便会返回。recv()换句话说,send()返回之时,数据不一定会发送到对端去(和write写文件有点类似),只是完成了拷贝动作而已。

recv()send():仅仅是把应用层缓冲区的数据拷贝进socket的内核发送缓冲区中(send()只负责拷贝,拷贝到内核就返回),发送是TCP的事情,和send()其实没有太大关系。

数据发送和接收的过程:
在这里插入图片描述

tcp、udp接收缓冲区的不同

接收缓冲区被TCP和UDP用来缓存网络上来的数据,一直保存到上层应用进程读走为止。

对于TCP

如果应用进程一直没有读取,接收缓冲区满了之后,发生的动作是:接收端通知发送端,接收窗口关闭(win=0),这便是滑动窗口的实现。保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。

recv()如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。

查看测试机的socket发送缓冲区大小:

cat /proc/sys/net/ipv4/tcp_wmem

在这里插入图片描述
第一个值是一个限制值,socket发送缓存区的最少字节数;
第二个值是默认值;
第三个值是一个限制值,socket发送缓存区的最大字节数;

根据实际测试,发送缓冲区的尺寸在默认情况下的全局设置是16384字节,即16k。

对于udp

recv()每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发(尽最大能力交付),不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。

当套接口接收缓冲区满时,新来的数据报无法进入接收缓冲区,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。

缓冲区大小对send()的影响

Socket编程中,使用send()传送数据时,返回结果受到以下几个因素的影响:

  • Blocking模式或non-blocking模式
  • 发送缓冲区的大小
  • 接收窗口大小

send函数在发送的数据长度大于发送缓冲区大小,或者大于发送缓冲区剩余大小时,socket会怎么反应

socket之send与发送缓冲区大小的关系_水果刀的专栏-CSDN博客

recv()当send的数据长度大于socket的缓冲区长度时,不管是windows还是linux,阻塞还是非阻塞,send都会分帧发送,分帧到缓冲区能够接收的大小

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 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。 sendrecv函数的使用方法如下: ```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) { // 接收失败 } ``` 使用sendrecv函数时需要注意以下几点: - sendrecv函数都是阻塞式的,即程序会一直等待直到发送或接收完所有数据。 - 如果发送或接收的数据量比较大,需要多次调用sendrecv函数。 - 如果发送或接收的数据量比较小,建议使用TCP_NODELAY选项关闭Nagle算法,以提高发送和接收的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值