Socket 编程中,TCP 流的结束标志与粘包问题

由于 TCP 自己是无边界的协议,所以它并无结束标志,也没法分包。html

socket和文件不同,从文件中读,读到末尾就到达流的结尾了,因此会返回-1或null,循环结束,可是socket是链接两个主机的桥梁,一端没法知道另外一端到底还有没有数据要传输。
socket若是不关闭的话,read之类的阻塞函数会一直等待它发送数据,就是所谓的阻塞。java

若是发送的东西很是多必需要用循环读,能够有如下解决方案:编程

  • 调用socket的 shutdownOutput 方法(Java)关闭输出流,该方法的文档说明为,将此套接字的输出流置于“流的末尾”,这样另外一端的输入流上的read操做就会返回-1。
  • 约定结束标志,当读到该结束标志时退出再也不read。 (Http 的 Transfer-Encoding: Chunked 首部,表示将以一个 length 为 0 的 chunk 作结束标志)
  • 设置超时(timeout),会在设置的超时时间到达后抛出SocketTimeoutException异常而再也不阻塞。
  • 双方定义好通讯协议,在协议头部约定好数据的长度。当读取到的长度等于这个长度时就再也不继续调用read方法。(Http 的 content-length 首部,会给出主体的长度)

而若是须要发送多个相互独立的内容,内容之间就须要有明确的分界,方法有:服务器

  1. 像 multipart-form 同样,使用 boundary 字串作分割,使用 Content-Type 等首部作内容标识。
  2. 用二进制帧作分割,在帧首部定义好帧的长度和其余信息。

参考

关于java网络编程中获取输入流中数据的问题
Linux编程之socket:tcp流协议产生的粘包问题及解决方法
终端如何与服务器通讯——玩转通讯协议(源码下载)网络

相关文章
相关标签/搜索