2009年3月20日星期五

Socket编程和协议设计

眼下在写的一个程序涉及Socket编程,最初我写的是Java tutorial上推荐的方法,即封装出BufferedReader,再调用readLine()方法。然而请求发出去之后,却阻塞在readLine()上了,没有读到预期的应答数据。

基于TCP协议应用协议有一个好处,可以用telnet来调试。于是我祭起Putty,发起请求,这下看到了预期的应答数据。

我的程序错在哪里?错在readLine(),它要等待一个'\n'。而按照应用协议的规定,不会在一次应答结束时返回'\n'。所以readLine阻塞了。

正确的写法应该是怎样的?只从socket读取一次数据是不对的。由于网络延时是不确定的,所以读一次数据不知道是否读到了完整的应答。一定要根据应用协议的规定,读到结束字段。而这个应用协议规定了用''分隔字段。于是我必须根据应答字段的个数进行读取,直到读完一条完整应答为止。

事情还没完。根据请求是否成功,服务器应答信息的字段数是不一样的。所以应答读取的程序应该先读到成功失败标识,再判断成功失败,读取后面的应答字段。

这导致了协议对话部分的程序相当复杂,而这种复杂本来是可以避免的。为什么会出现这样的结果?

原来的协议还附了一段C程序例子。正是这段例子,让我对问题的原因有了一个大概的猜测。

这段C程序初始化了一个缓冲区,并往里面填充了0。然后从socket中进行了一次读取,放在缓冲区中。不幸的是,这段程序是错误的。因为网络延时不确定,所以读取的数据可能是不完整的应答。写例子的人就当它是完整应答了!这样写是简单,但是却是错的。

我想,如果设计协议和写C例子的人(可能是一个人)如果概念清楚,还是会把协议设计成以'\n'来结束一次应答吧。

没有评论: