【求助】【再次描述问题】WebSocket 消息有时延迟很久。
发布于 10 年前 作者 sjfkai 20041 次浏览 最后一次编辑是 8 年前

2014-8-19再次描述问题。

有时客户端在发送二进制数据时,服务端收到时少了一个字节,这时服务器会等待这个字节,到来之后才调用onMessage。 然而这个字节是在一段时间(20s)没有通信,服务器发送ping消息,客户端回应pong时。和pong一起收到的。 客户端发送的时候是没有问题的。 应该不是WebSocket包的原因。 有没有大神帮忙分析一下。。

###↓↓↓这是之前的描述 使用WebSocket 客户端发送message到服务器端,即使是在本地有时会有很长的延迟(10s左右)才收到

项目使用的websocket包是Worlize/WebSocket-Node 简单调试了一下源码,发现当需要接收的数据包多于一个的时候,第二个数据包会在发送后很久才到达。 (目前我还不清楚数据包是怎样分的,同样的请求数据有时一个包,有时两个包。)

源码里有关buffer的东西太多,有点弄不懂了。。

有没有遇到过同样问题的大神帮忙指点指点

今天把WebSocket包换成了einaros/ws,问题反而更严重了。

在ws/lib/Receiver.js中有一个expectData方法,其功能就是按照长度length保存WebSocket包的data

Receiver.prototype.expectData = function(length, handler) {
  if (length == 0) {
    handler(null);
    return;
  }
  this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation);
  this.expectHandler = handler;
  var toRead = length;//需要读取的长度
  while (toRead > 0 && this.overflow.length > 0) {
    var fromOverflow = this.overflow.pop();//第一个包(一般只有一个,而且fromOverflow.length=toRead,
                                       //但是问题出现的时候fromOverflow.length=toRead-1,也就是少一个字节)
                                       //正常情况下会再循环一次读取下一个字节,可问题是下一个包还没收到 this.overflow.length = 0,所以并没有循环读取,而是直接返回了
    if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead));
    var read = Math.min(fromOverflow.length, toRead);
    fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset);
    this.expectOffset += read;
    toRead -= read;
  }
};

为什么第二个包接收到的这么慢呢? 再深层的代码就是nodejs的net.js 和 _stream_readable.js了。

再次求助啊。。谢谢大家了

18 回复

好像用socket.io会简单些. 如果只要纯websoscket的话, 这个库会简单些ws

@meteor 但是现在库不能换了额。。哎

有没有nodelay之类的设置?

@sinsupakaka 应该没有吧? 这个怎么设置?客户端还是服务端?

我之前有弄个,怎么感觉没什么延时 用的是 ws

@feiin 哎这个是前人留下来的项目,用的是那个包。也不一定是包的问题。也有可能是客户端的问题。但是有些迷茫不知道怎么找。。已经找到websocket包的最底层了。。。

再次求助啊。。谢谢大家了

@sjfkai 再次求助。。。

这库的代码没法看,说说思路看看你能不能找到问题吧 1.抓包检查少的字节是否确实已经从客户端发送出去了,如果未发送,检查客户端的发送buffer的实现 2.在服务端抓包看是否收到了这个字节,如果收到了,检查服务端接收buffer的实现,因为消息可能是达到一个阈值才会触发onMessage事件的 3.在库的Receiver和buffer实现里多打一点log看

最近才用websocket-node写了个服务器 https://github.com/Hi-Rube/RChat-Server android客户端2g网络发消息秒速到达,没觉得有延迟啊~

@Hi-Rube 好像不错的样子,学习下。

@jeremy16601 随便写的一个,但是有一个内存泄漏点。。。希望大哥能找出来~ :D

请问楼主找到解决方案来吗?求教!

@Hi-Rube memory leak 可能是那个连接管理设计有问题,你每压入一个新的 connection 会给它分配一个 clientList.length 的 index,删除的时候按 index 搜索。这样是有问题的,比如说有10个链接,index6被删除了,那么这时候 index 是这样分布的 [0, 1, 2, 3, 4, 5, 7, 8 , 9] => clientList.length 9 再有新的连接进来,就变成了这样: [0, 1, 2, 3, 4, 5, 7, 8 , 9, 9] 这个时候,假如最后一个connection掉了,要删除最后一个连接的时候就需要删除 index9,结果删除的会是活动中的前一个9,而不是真正断掉的最后一个9。所以 leak 了。

是不是采用了默认的Nagle算法,该算法在网络中存在极少数有效数据的时候不会立即发送,只有等到下一批数据到来时才会发,可以通过socket.setNoDelay(true)解除该算法

expectData需要传入 length 参数,会不会是这个参数有问题,少了1?

@fifaroom 你也有这个问题? 我解决的办法就是改了一下协议,少一个字节的时候就立即ping一下。下一个包就把少的那一个字节带过来了。 具体什么原因依旧不知道。

回到顶部