ID #8317

Socket网络编程学习笔记(4):TCP消息边界处理

在前面的几篇中,讲了关于套接字Socket以及利用套接字助手类来进行服务 端和客户端之间的通信,在此中间并没有对发送的信息进行任何的处理。在本篇 中将会讲一下TCP通信时的信息边界问题。

通过套接字或其助手类来接收信息时,是从缓存区里一次性把全部的缘存都 读取出来,只要你设置的缓存够大,它就能读取这么多,这样就会导致这样的情 况出现。如果服务端连续发送信息到客户端,如我连续发送字符串 “message 1”、“message 2”、“message 3”、“message 4”、“message 5”,我预想的是 在客户端也是能够收到这样的五个完整的字符串,如果用前二篇中讲的方法,在 同台机子上测试的话,是正常的,因为同台机子上网络信息传送出现的异常会比 较少,但如果把客户端与服务端部署在不同的机器上,则会出现一些异想不到的 现象。你会发现接收到的字符都被打乱了,会出现如“3message 4” 的字符串,这样的话,我们就不能把服务端发送的信息正常的还原。这个就是消 息的边界问题,要解决这个问题,方法有很多,现抽取其中几个来讲一下:

1、固定尺寸的消息

这是最简单但也是最昂贵的解决TCP消息问题的方案。就是要设计一种协议, 永远以固定的长度传递消息,通过将所有的消息都设置为固定的尺寸,在从远程 设备中接收到完整的消息时,TCP接收程序就能够了解发送的情况了。用这各地 意味着必须将短消息加长,造成网络带宽资源的浪费。

2、使用消息尺寸信息

这个方案允许使用可变长度的消息,惟一的不足就是接收端的远程设置必须 了解每一个变长消息的确切长度。具体的方法是,在发送消息的时候,一起发送 该消息的长度。那么在客户端接收的时候就能知道该消息的长度是多少,再来读 取消息。

3、使用消息标记

该方案使用预先确定的一个字符(或多个字符)来指定消息的结束,通过这 种方式来分隔不同的消息。但用这种方法必须对所接收到的每一个字符进行检查 以便确定为结束标记,这对于大型消息来说,可能导致系统性能的下降,不过对 于C#语言来说,提供了一些类,能够用于简化这个过程,那就是System.IO命名 空间流类,下面我们也着重来讲一下这各方法。至于第二种方法,将在下一篇中 与在消息中传送实体类信息相结合来讲述。

在上一篇中,我们已经提到NetworkStream类,利用该类来传送和接收消息。 在这里,再提一下另外的二个流类,那就是StreamReader和StreamWriter,这二 个类也可用于TCP协议发送和接收文本消息。

当我们得到Socket连接的一个NetworkStream对象时,可以通过下面的方法得 到StreamWriter和StreamReader对象。

1NetworkStream ns = s.GetStream();
2      StreamReader sr = new StreamReader(ns);
3      StreamWriter sw = new StreamWriter(ns);

这样我们 就可以通过StreamWriter来发送消息,通过StreamReader来接收消息:

1//发送消息
2string welcome = "Welcome to my test sever ";
3
4      sw.WriteLine(welcome);
5      sw.Flush();

接收消息:

1//接收消息
2string data = "";
3data = sr.ReadLine();

这样是不是比以前的做法更简单了,而且同时也解决了TCP消息边界问题了。

但是用这各方法必须得注意以下二点:

1、这种方法其实就是利用消息标记来解决边界问题的,这里的标记就是换行 符,也就是说,StreamWriter中的WriteLine()和StreamReader中的ReadLine() 一定要成对使用,不然如果发送的信息中没有换行符,则客户机中用ReadLine() 读取信息时,将无法结束,将堵塞程序的执行,一直等待换行符。

2、另外还要保证在发送的消息本身不应该带有换行符,如果消息本身带有换 行符,则这些换行符将被ReadLine()方法错误地作为标记,影响数据的完整性。

关于TCP消息边界处理就暂时讲到这里了,由于自己的理解也不够深,难免会 出现错误,请各位及时纠正。在下一篇中,将讲述传送实体类方面的问题。


2011-07-02 10:00
阅读:
I'm VC , Just U know Y
本站部分文章来源于互联网,版权归原作者所有。

延伸阅读:

WCF分布式开发步步为赢(14):WCF安全编程--基本概念

多线程服务器的常用编程模型

趣味编程:将事件视为对象(参考答案)

再说lock-free编程

从针对接口编程到依赖注入