使用send()函数发送数据,系统如何知道数据发送成功
函数作用
我们知道,服务端中有一个接收缓存区,客户端中有一个发送缓存区,同时每个TCP socket在内核中也都有一个发送缓冲区和一个接收缓冲区,
send()函数的作用就是将客户端或服务端中的数据拷贝到SOCKET的发送缓存区中
recv()函数的作用就是将SOCKET的接收缓存区中数据拷贝到客户端或服务端的接收缓存区中
综上,send()函数和recv()函数只完成应用层到传输层的数据搬运,并不直接将数据传送到数据的另一端去,真正完成数据的传输的是协议功能(TCP/UDP)
函数参数
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
sockfd:创建的sockfd文件描述符,
buf:发送数据所在的数据区,
len:发送数据的长度,
flags:标志位默认设置为0
send()函数的返回值
1、成功执行时,返回发送的字节数。
2、失败则返回SOCKET_ERROR
ssize_t recv ( int sockfd, void *buf, size_t len, int flags);
recv()函数的返回值
1、成功执行时,返回接收到的字节数。
2、若另一端已关闭连接则返回0,这种关闭是对方主动且正常的关闭
3、失败返回-1,errno被设为以下的某个值
如何判断数据是否发送成功?
通过send()函数的返回值,应用层只知道数据是否“拷贝”成功,另一端是否接收数据成功仅靠send()函数的返回值是判断不了的,
对方是否接收数据成功发送端是判断不了的,如果发送端需要知道接收端是否接收数据成功,需要接收端给发送端返回一个值来确定(应用层面确定数据发送成功)
系统底层确定数据是否发送成功(协议层面确定数据发送成功)
TCP协议会确保数据完整的发送出去,同时保证数据到达接收端的SOCKET接收缓存区
TCP数据报首部包含发送数据包的基本信息,比如数据长度
TCP协议的ACK确认机制
当SOCKET发送缓存区的大小为0的时候,也可以确定数据完全发送出去,buffer.size()==0
补充:
1、滑动窗口在SOCKET的缓存区里面,窗口的大小会根据接收端的处理情况动态变化(保证SOCKET的接收缓冲区不会溢出)
2、TCP 的SOCKET有接收缓存区和发送缓存区,而UDP的socket只有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。