简述一下环境: java netty 的服务端, cocos2dx 的客户端

昨天测试的时候 发生了一个奇怪的现象。 服务端在本地跑的时候, 都是正常的。 放到阿里云的服务器上面去的时候。 在客户端与服务端进行第一次连接的时候一切OK,然后第二次连接的时候 就出现了问题。。。 问题具体发生的原因我现在也还没弄明白。。。

然后,我就查阅了一下 有关 windows select IO 异步模型的资料。 虽然这病没有帮助我解决问题, 但总归是有了些启发。

然后我想,我加一下发送的数据包的长度进去吧。 于是乎,我在 netty 上面加了一个 解码器, 标注了发来的数据包会标准它的长度。 然后客户端在发送的时候会先发一个 表示长度的数据。 一般是采用 4个字节长度的大小。

因为大小端的问题, 在弄长度的时候 也发生了乱七八糟的问题。长度不能正确被解析,因为我也没有什么经验,所以好多元素对于我来说都是未知的。 我也不能确定问题到底在哪, 所以也比较蛋疼。 这种时候, 没办法,只能使用排除法了。 我先写了一个 java 的类 来测试大小端的问题。

我使用 java.nio.bytebuffer 类来生成byte数组。 我先 使用 putInt 方法, 将要发送的字节数量 put 进去, 然后在放入具体的数据。

Socket socket = new Socket("127.0.0.1", 7000);

ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.putInt(8);
buffer.putInt(1);
buffer.putInt(2);

socket.getOutputStream().write(buffer.array(), 0, 12);
socket.getOutputStream().flush();

这样测试之后, 发现长度解码器是可以正确使用的。

所以得出结论。 既然长度解码器是可以使用的, 那么只能说明客户端部分的代码是有问题的。 所以调试客户端部分的代码。 因为在客户端进行了多次的send ,所以无法判断问题到底出现在什么地方。 所以只保留一个 send, 进行测试。 我本来的做法是先把长度send 过去, 再进行send 数据。 后来发现这种方式是不对,会产生数据。正确的做法应该是: 将数据包的长度和数据一起发送给服务端。相关代码如下:

/* 这是c#代码, 改改就可以在c++中使用了。 这段代码也是我借鉴其他同事的 */

int nOffset = 0;

m_sendBuffer[nOffset + 3] = (byte)(nSize >> 0);      // nSize 是数据包的长度
m_sendBuffer[nOffset + 2] = (byte)(nSize >> 8);
m_sendBuffer[nOffset + 1] = (byte)(nSize >> 16);
m_sendBuffer[nOffset + 0] = (byte)(nSize >> 24);

/* 上述代码可以把数据包的长度 用大端的方式 放在发送缓冲的前面位置。因为java才用的是大端模式, c++ 采用的小端模式。  据说 大小端是因为CPU 来决定的。 x86平台都是小端。 但是呢,我也不是很懂,所以考虑那么多的处理也没有什么意义只能先当 java是大端, c++ 是小端了。  出现了响应的情况,再进行处理把。 */

memcpy((m_sendBuffer+4),data,nSize);    // 将要发送的数据 copy 到发送缓冲中

send(fd,m_sendBuffer,nSize+4,0);   // 连同标记长度的4个字节也要发送出去。

这样处理之后, netty 就能正确的收到 长度标识。然后读取到标记的字节到ByteBuf中。 但是呢, ByteBuf 收到的字节是按照大端方式排序的。 所以需要对其进行处理。

ByteBuf buf = (ByteBuf)msg;
buf = buf.order(ByteOrder.LITTLE_ENDIAN);

这样之后, 就可以正确的处理发送过来的内容了。

嗯。。。 是不是很麻烦呢。。 确实呢, 如果直接都用c++进行编写,这样的情况应该就没有了把。 但是呢, 那样的话就要去踩 C++ 的坑, so 其实还好啦。 就大小端的问题比较头疼, 处理好了,别的应该就没有什么难的了。

以前总是喜欢快速的解决问题。 即,搜到代码, 不去理解而是直接选择使用。 出了错误直接换一个地方的代码。 好多情况都会出现代码可以使用,所以有些养成这样的习惯了。其实这是一个不好的习惯。 因为这样只是表面的解决问题了, 具体原理无法理解, 一旦出现 错误了,整个人都会直接懵逼了。会想, 这特么到底是因为什么呀。 艹, 你麻痹的, 真是头疼。

所以那种方式的直接使用是不正确的。 不要急着去解决问题。 可以先看看别人写的文章,到底是因为什么, 这么做的作用是什么, 原理是什么。 了解了之后就相当于提高了自己的内功,而不只是一个纸老虎 了。

要相信 磨刀不误砍柴工。 工欲善其事必先利其器。

netty 长度解码器相关资料: http://www.cnblogs.com/zhuawang/p/4047993.html