消息服务设计问题:如何不阻塞消息?

我们使用通讯软件发消息的时候,如果消息中包含了一张大图或者一个大文件,程序会同时接受大文件和后来发送的消息而不是等待大文件传输完毕才收发消息。对于简单的点对点单连接TCP通讯来讲,输入输出流各只有一条,这意味着未完成的大文件传输会阻碍后续的消息传输。

一种可能的设计方案是让大于某个长度的消息在新的线程、新的socket连接中传输。

消息1{length=234}-->normalMeesageQueue
消息1{length=434}-->normalMeesageQueue
消息1{length=2234}-->newBigMeesageQueue
消息1{length=934}-->normalMeesageQueue
消息1{length=5334}-->newBigMeesageQueue

例子中假设消息大小分类的阈值为1024Bytes,则小于阈值的消息在一般的消息循环线程中收发;每个大于阈值的消息都开启一个新的线程收发。

多线程收发大消息可以解决消息阻塞的问题。

进一步处理超大型消息,比如上百兆的大文件传输的时候,为了避免给服务器太大压力,可以采用点对点传输而不再是经过服务器中转。如果你有足够的成本运营一个超大带宽和存储容量的服务器的话当我没说。也可以采用例如http://tmp.link这样的临时文件中转服务,不过使用第三方服务尤其是这样不支持加密传输的服务意味着数据不安全。

将大消息放到单独的线程和socket中处理,解决的是客户端发送大消息到服务端的阻塞问题,但是服务端发送到客户端的线程和socket仍然只有一套,还是会阻塞。

要让服务端发送大消息到客户端不阻塞数据流,有两种方案。

第一种方案,我们可以让客户端像服务端一样建立额外的serversocket,专用于接收消息。客户端在登陆的时候告诉服务端本次建立的serversocket的端口,服务端使用这个端口向客户端发送大消息。

让客户端像服务端一样

第二种方案,服务端在发送大消息的时候先用小消息通知客户端,客户端建立额外的socket并使用该socket向服务端发送获取大消息的确认信息,服务端向该socket发送大消息。

由于客户端机器上端口占用情况不可控,可能面临端口已被占用、端口未开放等问题,在客户端上创建ServerSocket条件不稳定,所以认为第二种方案更加合适。