带TCP的非阻塞套接字

时间:2010-12-28 09:32:30

标签: networking tcp ip nonblocking packet

我正在使用Java非阻塞套接字和TCP编写程序。我知道TCP是一种流协议,但是底层IP协议使用数据包。当我调用SocketChannel.read(ByteBuffer dst)时,我是否总能获得IP数据包的全部内容?或者它可以在数据包中间的任何位置结束?

这很重要,因为我正在尝试通过通道发送单个消息,每个消息都足够小,可以在单个IP数据包中发送而不会被分段。如果我总是可以通过在接收器端调用read()来获取整个消息,那将是很酷的,否则我必须实现一些方法来重新组装消息。

编辑:假设在发送方,消息以较长的间隔(如1秒)发送,因此它们不会在一个IP数据包中组合在一起。在接收方,用于调用read(ByteBuffer dst)的缓冲区足以容纳任何消息。

3 个答案:

答案 0 :(得分:2)

TCP是一个字节流。每次读取将接收1到您提供的缓冲区大小的最大值以及当时可读取的字节数。

TCP对您的消息概念一无所知。客户端的每次发送都可能导致另一端需要0次或更多次读取。零或更多,因为您可能会获得一条返回多条“消息”的读取。

您应该始终编写您的读取代码,以便它可以处理您的消息框架并重新组合部分消息或拆分多个消息。

您可能会发现,如果您不打扰这种复杂性,那么您的代码似乎在大多数时间都“工作”,不依赖于此。只要您在繁忙的网络或互联网上运行,或者只要增加邮件的大小,您就会被破坏的代码咬伤。

我在这里讨论一下TCP消息框架:http://www.serverframework.com/asynchronousevents/2010/10/message-framing-a-length-prefixed-packet-echo-server.html和这里:http://www.serverframework.com/asynchronousevents/2010/10/more-complex-message-framing.html虽然它是关于C ++实现的,所以它可能对您感兴趣,也可能不感兴趣。

答案 1 :(得分:1)

套接字API不保证send()和recv()调用与TCP套接字的数据报相关联。在发送方面,事情可能已经重新组合,例如系统可以推迟发送一个数据报以查看应用程序是否有更多数据;在接收方,如果调用者指定的大小需要中断数据包,则读取调用可以从多个数据报中检索数据,或者部分数据报。

IOW,TCP套接字API假定您有一个字节流,而不是一系列数据包。您需要确保继续调用read(),直到有足够的字节来表示请求。

答案 2 :(得分:0)

来自SocketChannel文档:

A socket channel in non-blocking mode, for example, cannot read 
any more bytes than are immediately available from the socket's input buffer;

因此,如果您的目标缓冲区足够大,您应该能够使用套接字输入缓冲区中的整个数据。