Socket中粘包的坑的处理

来源:互联网 发布:淘宝评价怎么修改好评 编辑:程序博客网 时间:2024/06/06 03:05

经常在网上看到很多类似于粘包的问题以及处理,但是因为这个跟自己本身的工作内容关系不大,所以也就没怎么了解。结果今天就被坑了一大把。

起因

最近由于有个投屏的软件需要模拟多个客户端进行连接投屏,所以用java写了个客户端模拟多个同时进行并发同屏的情况。而他的协议过程是这样子的。当你发送开始投屏的命令一样,接收端也就是我们所说的服务端会回复几条socket的信息(这个是重点),但是因为我们是模拟客户端的,所以并不是所有的数据都是我关心的。只有其中一条关于回复的端口的信息是需要接收处理。所以就有了坑的问题了。

问题

在测试的过程中发现,经常是有概率的出现模拟了4个客户端进行并发时服务端只回复了3条关于端口的数据,总会有概率的少了一两条。那问题总得定位到底是代码处理的问题,还是说是机器本身就没有收到对应的包呢。
以下是wireshark抓包的结果
这里写图片描述

实际证明是有收到这个回复包的, 那么就证明确实是代码的问题了。那代码问题在哪 我们看看出错的代码

 byte len[] = new byte[1024]; int count = socket.getInputStream().read(len); byte[] temp = new byte[count]; for (int i = 0; i < count; i++) {     temp[i] = len[i]; } ...   if (temp[9] == 1) {       switch (temp[10]) {           case 101:               Msg.CMsgConnectResp cMsgConnectResp = Msg.CMsgConnectResp.parseFrom(msg);               log.append("收到指令类型:" + (temp[9]) + ", 指令号:" + temp[10] + "连接结果:" + cMsgConnectResp.getResultType() + ", 接收端版本:" + cMsgConnectResp.getReceiverVersion() + ", 支持最大窗口数量:" + cMsgConnectResp.getMaxWindowCount() + "\n");....

代码实际很简单就是声明一个byte的数组,每次读1024个字节。再来将读取到的数据进行解析,表面上看起来没什么问题。

可是细想一个问题。就是刚才我们提到的,当我们进行投屏的时候,服务端是会连续回复几个socket的数据的,然而我们一下子读了那么1024个字节的数据,就会把几个数据包都读到一起,那如果幸运的话,回复端口的数据先到了,嗯 没问题,那如果是其他数据类型先到了,会发生什么事情呢。。很悲剧。数据包会被丢弃掉。

解决

既然遇到这个问题,就肯定有解决的方法。下来看看解决的方式

 byte len[] = new byte[11]; socket.getInputStream().read(len); byte[] msgLenArray = new byte[4]; System.arraycopy(len, 0, msgLenArray, 0, 4); int msgLen = (MsgUtils.bytesToInt2(msgLenArray)); if (msgLen > 0) {     byte contentByte[] = new byte[msgLen];     socket.getInputStream().read(contentByte);     System.out.println(len[9]);     System.out.println(len[10]);     if (len[9] == 1) {     }

以上就能够完美的解决问题了,我们每次读取都读11个字节。因为协议头的长度就是11个字节。再来根据协议头里面的body的长度我们再去读对应的长度。这样子就避免了读取的时候盲目的读取1024个长度的问题了。

原创粉丝点击