关于网络软件编写的程序流程处理问题(100分)

  • 主题发起人 一个过客
  • 开始时间

一个过客

Unregistered / Unconfirmed
GUEST, unregistred user!
最近要开发一个网络软件,进行到一半不得不停下来思考一个问题:
比如这个软件是一个基于TCP/IP协议的网络聊天软件,程序流程中
经常是 发送一个命令,然后等待命令回应,然后进行下一个命令,
这样的流程怎样处理比较合适?

我觉得可能用Indy控件比较合适,因为Indy是阻塞的,比如Indy的
TIdTCPConnection就有一个SendCmd函数来完成类似功能,意思是
发送一个命令,并等待得到命令返回结果。但是这种类似的处理方式
有一个前提,就是服务器顺序处理你的命令,并顺序返回你的结果,
如果服务器接收到一个命令后,可能处理时间比较长,而这期间有
消息需要通知客户,那么在该命令返回前,就会返回给客户端这个
需要通知的消息,那么sendcmd函数得到的会不会就是这个消息,
而不是我需要的命令结果?还有,如果我的软件有一个Timer,每隔
一段时间向服务器发送一个查询请求,那么这个Timer查询请求的结果返回
是不是会被前面所说的sendcmd接收到?

类似这样的问题经常遇到,服务器并不一定顺序处理客户端的请求,
并顺序返回结果,客户端用阻塞方式很难做到一问一答的形式。

那么用非阻塞方式的TClientSocket怎么样?这个控件是基于事件驱动
的,有数据过来就激发一个事件,但是这样做问题更多,当事件发生时
(也就是收到返回数据的时候),我怎么知道该进行什么操作?因为
客户端的同一个命令可能在不同的窗口、不同的地点发出的,那么在
TClientSocket.OnRead事件里怎样区分不同的情况做出正确的操作?

另外,我看了一些demo,比如Indy自带的MailClient例子,它就是用的
SendCmd命令来实现交互操作,那么如果在这个例子里面同时存在多个
命令请求(比如Timer里面发出请求),SendCmd函数还能肯定的得到正确的结果吗?

上面的问题我思考了很久,不知道大家是怎样做的?流程处理很烦人。
 
关注,我也一直 贝这个问题困牢
 
俺最近也在研究这个问题,
我感觉,是不是自己定义一个基于TCP/IP的包,
pack = record
Len: integer;
ID: integer;
Mess:array [1..100] of char;
.....
end;
真对不同的包,用不同的ID。那边服务器也需要返回一个包,大约和这个差不多吧。
这样用根据包里的ID,就可以知道是哪个命令,什么地方发送的等等。。。。(非阻塞)

如果服务器不是你能控制的那种,就。。。。呵呵 (我也正在想。。。。)
 
你的方法看上去不错,实际用起来不行,而且我也用过类似的方法。

比如,我的客户端软件里面有一个Login的命令,这个命令可能会在任何地方使用,
比如当我查询对方信息(WhoIs)时,软件首先检查我是否已经登录,如果没有就先发
Login命令登录,成功就接着发WhoIs命令;再比如我检查别人给我留言的时候(CheckMsg)
也一样。同一个Login命令会在不同的地方多次使用,难道我需要定义无数个这样的
Login的命令包? 不然在接收到Login的回应的时候,我怎么知道该继续发WhoIs还是
CheckMsg命令? 这就是我迷惑的地方。

另外,服务器是不是自己写的不重要,有些应用使自己写的,但也有很多应用的服务器
不是自己写的,我这里主要是想讨论一种比较普遍适用的流程控制模式(设计模式?),
而不是针对具体的某项应用。
 
而且,我怎么觉得Java里面的“事件-监听者”模型和我的问题比较类似?

每个需要监听一个事件的类,需要自己实现该事件的listener接口,然后把接口
添加到该事件的监听者列表里,当事件发生时,会逐一调用列表里的接口的事件。
用类似Pascal的语法表示类似于:

//定义命令包类:
TMyCommandEvent = class
private
FEvent:TList; //存放每个监听者
public
procedure AddListener(AListenr:xxx); //添加监听者
procedure Response; //命令包被响应,由接收到数据的时候调用
end;
procedure TMyCommandEvent.AddListener(AListenr:xxx)
begin
FEvent.Add(AListener);
end;
procedure TMyCommandEvent.Response;
begin
//命令包收到回应的时候,依次调用里面的每一个监听者
for i:=0 to FEvent.count-1 do
begin
FEvent.do.... //调用
FEvent.Delete(i); //调用完就删除
end;
end;

//定一个专门处理Login命令的包
[purple]MyLoginEvent[/purple]:TMyCommandEvent;

//=============================================
//定义一个监听者例子,表示Login之后就WhoIs
//这里定义为procedure,实际应该是一个接口吧?
procedure [brown]ListenerWhoIsWhenLogin[/brown]()
begin
DoWhoIs();
end;

****************************
好,下面程序处理流程就是:
****************************

//查询用户信息
if (not Logined) then //如果没有登录
begin
//将事件添加到Login命令包的Listener列表
[purple]MyLoginEvent[/purple].AddListener([brown]ListenerWhoIsWhenLogin[/brown]);
Login(); //登录
end
else
ListenerWhoIsWhenLogin(); //如果已经登录,就直接调用 ListenerWhoIsWhenLogin;


//在socket接收到数据的时候
//处理命令返回
procedure TForm1.ClientSocket1OnRead(...);
var rsp:string;
begin
rsp:=socket.receivetext;
case rsp of
Login_Response: [purple]MyLoginEvent[/purple].Response();
//如果是Login命令的返回,就激活MyLoginEvent.Response.
//在上面的TMyCommandEvent.Response里面将依次调用里面的Listener
end;
end;


这样的流程倒是可以解决上面说的部分问题,但是同时也带来别的问题:
1、类似ListenerWhoIsWhenLogin这样的东东,岂不是也要定义很多?
2、在TMyCommandEvent.Response的那个循环里面,如果某一个监听者阻塞住了,
比如打开了一个模式的窗口(这很常见),那么后面监听者都被阻塞住了。
 
首先声明,本人没有类似开发经历,所以只是说说。

第一,以前大家开发一般不用这么底层的东西,或者说还没有遇到/没有考虑去自己做。
所以一般很少研究这个问题,但是这个问题是很早就存在的。

第二,既然很早就存在了,现在的很多通讯程序都解决这个问题了,大家可以考虑一下,或者
阻拦他们的传输内容分析一下,是怎么搞的。

还有,也许是可以考虑放弃,我是说收到了不是自己的,或者处理有问题的包可以放弃。

胡说了一通,呵呵,当水贴吧。
 
第一,我觉得这可不是底层的东西阿,这是最高层了
第二,TCP的性质决定了收到的东西肯定是自己的,肯定是有用的
问题是怎样组织 命令<->应答 这样的流程。

我想大家肯定也开发过不少网络应用了,难道就没考虑过这样的问题?
 
应答,看看这个,偶写的简单测试,多线程中很麻烦,但不用的话,界面响应不好。
在阻塞Socket,可以通过select来等待另一端Socket的消息,而不是用Timer,当然由于select
是阻塞线程的,所以它是工作在另外的线程中的。

程序很简单,就是发了数据给一端,另一端再发回收到的Count,然后检查是否是正确。
http://expert.csdn.net/Expert/topic/1093/1093894.xml?temp=2.654666E-02
 
看看wzca的方式:
pack = record
Len: integer;
COMMAND: INTEGER;
~~~~~~~~~~~~~~~~~
ID: integer;
Mess:array [1..100] of char;
.....
end;
这里我添加了一个command字段,在这里可以定义命令的类型,比如login, message等等。
然后在服务器或客户端对于接受和发送网络包应该集中控制,有点类似Windows处理消息的机制,
根据不同的command值来进行不同的处理流程(case command of .....).
我一直用这种方式,感觉还比较方便。
 
刚才仔细看了一下上面的帖子,好像wzca和一个过客就是这个意思,呵呵!不好意思。
 
如果用户数超过200以上,把INDY扔了吧,还有什么ICS,通通扔了,没用的阿
如果直接写Socket吧,还不如用INDY呢
考虑用异步Socket I/O+交叉 I/O+完成端口(IOCP)
 
哇!来了一条大牛啊! 你的意思“把INDY扔了吧,还有什么ICS,通通扔”
是不是也是直接写socket?? 不过我总觉得,indy之类的控件也是包装的
socket函数,自己写没有信心比他们写得更好阿!
 
我感觉你的问题可以这样试试:
在服务端建一个socket用来监听客户端,如果客户端传来消息就根据客户断的socket及其他信息新建个socket1,
等消息传递完毕就释放该socket1,服务器端原来的socket继续用来监听.然后服务器端再建立几个线程,用来连接客户
端,至于消息传输如果中途出现意外则自动终止服务,所以肯定会有传漏的消息.
 
to 一个过客:你可以去www.dxsock.com看看,哪里有性能比较的

我最近自己在写一个用IOCP和Overlapped I/O的服务器内核,一个线程处理上千个连接,而且CPU占用率还很低,
呵呵,过几天放个演示来请大家指点一下
 
学习,期待...
 
王婆卖瓜来了,封装完成端口和重叠I/O的TCP服务器控件开发中版本,带服务器例子
http://bbs.et8.net/bbs/showthread.php?s=&threadid=245747
 
To G5Studio:
大虾,没法下载呀,又没法注册,麻烦发到我信箱(zensonic@.sina.com)好吗??不胜感激!!
 
想要得贴地址
 
TO::G5Studio
想学习,但进不去,能否给发一个!
zhang_yz@163.com
 
顶部