Quantcast
Channel: Sam的技术Blog
Viewing all articles
Browse latest Browse all 158

Linux Socket详解 <十一> socket收发缓冲区

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

socket在发送和接收时,根据不同的协议族和Type,会有不同类型的缓冲区。现研究如下。

1. TCP socket的接收和发送缓冲区
socket(AF_INET, SOCK_STREAM, 0);
每个TCP Socket在内核中都有一个发送缓冲区和一个接收缓冲区, TCP的全双工工作模式以及TCP的滑动窗口就是依赖这两个独立的buufer以及Buffer的填充状态。
对端发送过来数据,内核把数据缓存入接收缓冲区,应用程序一直没有调用read()读取的话,此数据会一直缓存在相应的socket的接收缓冲区。 若应用程序调用read(),会把接收缓冲区的数据读取用应用程序层的buffer.

应用程序调用write()或send()时,仅仅是把buffer中的数据copy到socket的发送缓冲区中。write()或send()返回时,data并不一定已经发送到对端了。

如果应用进程一直没有读取,buffer满了之后,发生的动作是:通知对端TCP协议中的窗口关闭。这个便是滑动窗口的实现。保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。

int rcvbuf = 0;
int sndbuf = 0;
socklen_t optlen;
int ret_opt = 0;
strcpy(buf, send_buf);

// 1. socket
iSocket_Server = socket(AF_INET, SOCK_STREAM, 0);
if(iSocket_Server == -1)
{
perror("socket()");
return -1;
}

// 1.4: Get socket send and receive buffer size
optlen = sizeof(sndbuf);
ret_opt = getsockopt(iSocket_Server, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen);
if(ret_opt == 0)
printf("\nSend buffer length: %d\n", sndbuf);

ret_opt = getsockopt(iSocket_Server, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen);
if(ret_opt == 0)
printf("\nRecv buffer length: %d\n", rcvbuf);

获取的结果是:
Send Buffer length: 16384
Recv Buffer Length: 87380


但Sam疑惑的是,从TCP Socket一段发送,另一端不Read,为何竟然可以发送3579904byte???
这与Recv Buffer 大小并不相符。



2. UDP的接收缓冲区
每个UDP Socket都有一个接收缓冲区,没有发送缓冲区。有数据就直接发送,不管对方是否能够正确接收,也不管对端接收缓冲区是否已经满了。
UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。



 

Viewing all articles
Browse latest Browse all 158

Trending Articles