TCP发送接口(如send(),write()等)的返回值与成功发送到接收端的数据量无直接关系

原文链接: http://blog.csdn.net/ordeder/article/details/17240221

1. TCP发送接口:send()

        TCP发送数据的接口有send,write,sendmsg。在系统内核中这些函数有一个统一的入口,即sock_sendmsg()。由于TCP是可靠传输,所以对TCP的发送接口很容易产生误解,比如sn = send(...); 错误的认为sn的值是表示有sn个字节的数据已经发送到了接收端。其实真相并非如此。

        我们知道,TCP的发送和接收在在内核(linux)中是有对应的缓冲的:

struct sock{
...
struct sk_buff_head	receive_queue;	//接收的数据报队列
struct sk_buff_head	write_queue;	//即将发送的数据报队列
...
}
        对于发送端而言,用户空间调用send(data)等发送接口将数据发送,内核会将data拷贝到内核空间的socket对应的缓冲中,即sock.write_queue。而send()函数的返回值仅仅是表示本次send()调用中成功拷贝的字节数(用户空间->内核空间对应的sock缓冲队列)。具体发送和接收端的接收就由TCP协议完成,虽然TCP是可靠传输,但是这个前提是发送端和接收端的网络是连接的,否则你懂得。这样,对于调用send()发送的用户而言,如果想要确定接收方是否成功接受数据,就得需要靠其他的办法查询。

2. send()阻塞和非阻塞

前面已说过,sn=send(data)负责将数据拷贝到内核空间,而具体发送是有tcp后续完成(这里面就包括流量控制等)。对已阻塞和非阻塞仅仅是对于数据从用空空间拷贝到内核空间的发送缓冲这段期间而言的。

        1. 如果发送缓冲剩余空间大于欲发送data的字节数,对于阻塞和非阻塞而言都能成功将数据拷贝至内核缓冲,返回的sn即等于欲发送的数据的字节数。

        2.如果发送缓冲剩余空间小于欲发送data的字节数,

                    a. 那么阻塞模式会进行阻塞,等待内核缓冲的空闲空间,然后继续将数据拷贝到内核缓冲中,直到全部拷贝为止。返回rn即为data的数据量。

                    b. 非阻塞模式,当内核发送缓冲被填满后,立即返回。rn等于data中已被拷贝到发送缓冲的数据量。

3. 如何判定接收成功接收数据?

        1.接收端回复应答信息。

                这个方法比较土,但也是比较实用的。

        2.计算发送端sock已发送数据量

           可参考:如何判断TCP数据包是否发送成功 作者提到可以使用 ioctl接口:ioctl(tcp_socket, SIOCOUTQ, &value);


4. 参考:


TCP之send函数研究  

recv send 阻塞和非阻塞  

如何判断TCP数据包是否发送成功 


  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Java编写TCP协议发送和接收数据接口,可以使用Java自带的Socket和ServerSocket类。 首先,创建一个ServerSocket对象,指定监听的端口号: ```java ServerSocket serverSocket = new ServerSocket(8888); ``` 然后,创建一个Socket对象,指定连接的IP地址和端口号: ```java Socket socket = new Socket("127.0.0.1", 8888); ``` 接下来,可以使用socket对象的输入输出流来发送和接收数据: ```java // 发送数据 OutputStream outputStream = socket.getOutputStream(); outputStream.write("hello".getBytes()); // 接收数据 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = inputStream.read(buffer); String result = new String(buffer, 0, len); System.out.println(result); ``` 当有客户端连接到ServerSocket时,可以使用accept()方法获取到一个Socket对象,然后就可以进行数据的收发了: ```java Socket socket = serverSocket.accept(); ``` 完整的代码示例: ```java // 服务端 ServerSocket serverSocket = new ServerSocket(8888); Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = inputStream.read(buffer); String result = new String(buffer, 0, len); System.out.println(result); OutputStream outputStream = socket.getOutputStream(); outputStream.write("world".getBytes()); socket.close(); serverSocket.close(); ``` ```java // 客户端 Socket socket = new Socket("127.0.0.1", 8888); OutputStream outputStream = socket.getOutputStream(); outputStream.write("hello".getBytes()); InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = inputStream.read(buffer); String result = new String(buffer, 0, len); System.out.println(result); socket.close(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值