View on GitHub

K.F.Storm

Welcome to K.F.Storm's Home!

Sharpshooter开发日志(2011-11-30)

今天主要解决了两个问题:一是传输格式化文本,二是对于大数据的发送和接收处理。

1. 传输格式化文本

之前的文本框用的是TextBox,为了支持格式化文本,将聊天窗口中的聊天记录和输入框改为RichTextBox,这样就能粘贴格式化文本了(比如word文档、网页等,但还不能像word那样方便地编辑)。

剩下的问题就是传输了,参考MSDN的文档如何:保存、加载和打印 RichTextBox 内容,就知道了TextRange类可以选定FlowDocument类的一段内容,然后调用TextRange.Save,可将选定的内容写入到流中,同样的,TextRange.Load可将选定的内容替换为流中的内容。重要的是,RichTextBox中的内容就是以FlowDocument的形式存在的(RichTextBox的Document属性),也就是说,只需要利用TextRange类将RichTextBox.Document写入内存流中,再从流中读取出字节数组,然后向服务器发送字节数组,就能起到发送格式化文本的目的了。

当另一客户端接收到字节数组时,先将字节数组写入内存流中,然后利用TextRange类选中RichTextBox.Document的结束位置,再调用TextRange.Load方法从内存流中读出内容,能够替换掉TextRange选中的内容(最后位置,选中内容为空)了,也就起到了在聊天记录中添加记录的作用。

格式化文本效果图:

clip_image002

2. 大数据的发送和接收处理

实现了传输格式化文本后,一个头疼的问题出现了,当发送数据量太大时(其实也不是很大,就一张小图片),客户端会与服务器断开连接(目前客户端与服务器通信时出现任何错误都会强迫相应的ClientManager关闭,从而导致断开连接),并且可能是发送数据的客户端断开,也可能是接收数据的客户端断开。

显然,这个问题肯定与数据量有关,所以我最先想到的事情就是增大Socket的SendBufferSize和ReceiveBufferSize,把服务器和客户端都改为1M。这个改动相当有用,发送一些小图片已经没什么问题了,但发送大图片时仍然可能断开连接(而且是无法预测的:同一张800*600的图片,第一次发可能不会断开,但第二次发就可能断开了)。想了半天也不知道是为什么,那就单步调试吧。最后发现是Socket接收数据时出现了问题(服务器和客户端都有可能)。

之前说过,Socket发送Message时发送的数据包含两个部分,第一部分为固定的4个字节,保存了第二部分的大小,第二部分为Message序列化后的字节数组。之前的做法是,当需要接收数据时,先让Socket接收4个字节的数据,这样就得到了Message的长度,然后让Socket正好再接收那么长的数据。本以为这样做行了,没想到Socket报告它收到的数据长度可能会小于指定的长度,原因就在于只要流中有还未读取的数据,Socket就可以接收这些数据,指定的长度并不代表要接收的数据量,而是代表最大接收量(MSDN没写清楚)。而网络是有延迟的,所以发送大数据时经常会出现收到的数据长度小于指定的长度的情况,所以在知道Message的长度后,不能通过一次Receive调用接收全部数据,而应该写一个循环不断接收数据,直到接收的数据量达到要求的数据量为止。这样修改之后,目前为止就再也没出现过因发送图片而断开连接的情况了。

效果图:

clip_image004

评论

(无)