hprose for java源码分析-18 服务器接收数据过程

18 服务器接收数据过程

书接上文。接下来分析服务器接收数据的过程,接收方法如下:

Connection类

120行,设置本方法运行的超时时间,若本方法在超时时间内未完成,将通知上层应用超时了。

121行,从channel读取数据到inbuf中。inbuf成员变量,初始化为

private ByteBuffer inbuf = ByteBufferStream.allocate(1024);

122行,若返回值n<0,说明读到流结束标记,此后便断开连接,

否则n表示本次读取了多少字节的数据到inbuf中。

初始时dataLength为-1, headerLength=4,条件

用来确定要接收的数据长度是多少。

客户端发送数据的格式为 :

长度(4字节,最高二进制位为1,即读出后为负值) + id(4字节) + 内容

若inbuf.postion() >= headerLength成立,说明已读取了至少4个字节,而此时可以确定长度已接收了,代码

130行,读取数据长度dataLength, 若 dataLength

=headerLength,说明已接收到id字段,

150行,从索引4读取id。

至此,通过接收到的数据已确定了长度,id,即确定了head部分,但内容部分还没有确定。

由于没有读完内容部分,接下来会继续从channel中读取数据并解析。但有个问题,由于

inbuf容量初始化为1024,若数据长度dataLength超出了1024,Inbuf装不下,怎么办?此时,能想到的就是重新分配一段空间,然后往新的空间读取数据。

135行,判断 头部+数据部分长度是否超出了inbuf的容量,是的话,重新分配一段内存,然后

将老内存内容拷贝到新内存上,同时释放老内存,最后inbuf指向新分配的内存。

inbuf空间可能不够的问题解决了,接下来就是将剩余的内容读入了。

怎样判定内容部分读完了?由于数据长度dataLength确定了,若

inbuf.position() >= headerLength + dataLength表示已读完。 inbuf存的是从channel接收的实际数据,inbuf.position()可以表示已读取实际数据的长度,而这个实际数据包括了头和内容。即实际读到的数据长度已经超过了 headerLength +dataLength,就表示内容已读完。

152行,判断数据是否读完,需要在dataLength>=0的前提下。

数据读完了,也就是已读到了一个完整的数据包,此时,就需要把这个数据包独立出来。

154行,分配一个长度为dataLength的内存data。

156行,设置inbuf的当前位置为 headerLength, 因为此位置开始存的才是实际数据。

159行,将inbuf中从position位置开始到limit间的数据拷贝到 data中,即将实际的内容数据读取到data中,而此时data中已存储了一个完整的数据包。

163行,将data通知到上层逻辑,由上层逻辑去处理。

接下来还原headerLength为4,dataLength为-1,id为null,即将变量还原成初态,为接收下个数据包作准备。

以上看起来没有问题,但似乎遗漏了什么。

一个完整包data是从inbuf中解析出来了,但Inbuf中只会包含一个完整的包吗?有可能inbuf中包含了一个完整的包,并且包含下一个包的部分数据。此时inbuf数据处理要做好,即解析出data包的时候,inbuf原有的剩余数据还不能扔掉,否则会造成数据丢失。

157行,记录下了inbuf的原有长度。

160行,将inbuf的数据拷贝到data后,重新恢复了limit,

161行,调了compact(),即将 inbuf从当前postion到limit间的数据拷贝到了inbuf的开始位置,即拷贝到索引0处开始的位置。

当将inbuf数据拷贝到data后,inbuf的当前位置刚好就是inbuf剩余数据的第一个字节处。

此时从inbuf当前位置,即剩余数据的第一个字节处拷贝到inbuf的开始位置,就保证了剩余数据不会丢失,从而为解析下一个包作了准备。

到此,一个完整包的接收过程已介绍完毕。

接下来,需要看看服务器如何去处理这个包。

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();