IdTCPClient的持续监听接收如何优化(233分)

  • 主题发起人 主题发起人 soketbudong
  • 开始时间 开始时间
S

soketbudong

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用IdTCPClient1接收数据,使用两种方式
while (true) do begin stringread:=IdTCPClient1.ReadLn(#$7e#$0d);
sleep(80);
end;
方式接收,可是当新开了一个线程后,程序速度变得很慢。
而我使用线程同步接收效果也不是很好,read等待的时间很长,程序几乎锁在这里,使用那个freeze控件一样。接触indy时间不长,indyclient如何才能流畅接收数据呢?
当有数据传来时,用什么方法可以判断?这样用来避免read的等待
 
你怎么不看看indy的demo .
我前几天才测试过这个demo,不会出现你说的状况。
{-----------------------------------------------------------------------------
Demo Name: ClientFrmMainUnit
Author: Helge Jung (helge@eco-logic-software.de)
Copyright: Indy Pit Crew
Purpose:
History: Improvements supplied by: Enver ALTIN
Date: 27/10/2002 00:24:26
Checked with Indy version: 9.0 - Allen O'Neill - Springboard Technologies Ltd - http://www.springboardtechnologies.com
-----------------------------------------------------------------------------
Notes:

Demonstration on how to use TIdTCPServer and TIdTCPClient
with using Threads and WriteBuffer/ReadBuffer

}

unit ClientFrmMainUnit;

interface

uses
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,
IdBaseComponent,IdComponent,IdTCPConnection,IdTCPClient,StdCtrls,
GlobalUnit;

type
TClientFrmMain=class(TForm)
CBClientActive:TCheckBox;
IncomingMessages:TMemo;
Label1:TLabel;
Client:TIdTCPClient;
Label3:TLabel;
EditMessage:TEdit;
ButtonSend:TButton;
Edit1:TEdit;
Edit2:TEdit;
procedure CBClientActiveClick(Sender:TObject);
procedure ButtonSendClick(Sender:TObject);
procedure FormClose(Sender:TObject; var Action:TCloseAction);
procedure FormCreate(Sender:TObject);
procedure EditMessageKeyPress(Sender:TObject; var Key:Char);
private

public

end;

TClientHandleThread=class(TThread)
private
CB:TCommBlock;
procedure HandleInput;
protected
procedure Execute; override;
end;

var
ClientFrmMain:TClientFrmMain;
ClientHandleThread:TClientHandleThread; // variable (type see above)

implementation

{$R *.DFM}
procedure sendMessage(CommBlock:TCommBlock);
begin
ClientFrmMain.Client.WriteBuffer(CommBlock,SizeOf(CommBlock),True);
end;

//´¦Àí·þÎñÆ÷·µ»ØµÄÐÅÏ¢...
procedure TClientHandleThread.HandleInput;
begin
ClientFrmMain.IncomingMessages.Lines.Add(CB.MyUserName+': '+copy(CB.Msg,1,pos(#13,CB.Msg)-1));
ClientFrmMain.IncomingMessages.Lines.Add(copy(CB.Msg,pos(#13,CB.Msg)+1,length(CB.Msg)));
if CB.Command='Quit' then
begin
if ClientHandleThread<>nil then ClientHandleThread.Terminate;
ClientFrmMain.Client.Disconnect;
end;
end;

//&para;&Aacute;&Egrave;&euml;&acute;&Oacute;·&thorn;&Icirc;&ntilde;&AElig;÷·&micro;&raquo;&Oslash;&micro;&Auml;&ETH;&Aring;&Iuml;&cent;&sup1;&copy;&acute;&brvbar;&Agrave;í.
procedure TClientHandleThread.Execute;
begin
while not Terminated do
begin
if not ClientFrmMain.Client.Connected then
Terminate
else
try
ClientFrmMain.Client.ReadBuffer(CB,SizeOf(CB));
Synchronize(HandleInput);
except
end;
end;
end;

//&AElig;&ocirc;&para;&macr;&iquest;&Iacute;&raquo;§&para;&Euml;,&ordm;&Iacute;·&thorn;&Icirc;&ntilde;&AElig;÷&frac12;&oslash;&ETH;&ETH;&Aacute;&not;&frac12;&Oacute;...
function connectToserver(hostip:string):boolean;
begin
with ClientFrmMain do
begin
try
//&Ouml;÷&raquo;ú&micro;&Auml;IP&micro;&Oslash;&Ouml;·&ordm;&Iacute;&para;&Euml;&iquest;&Uacute;&iexcl;&pound;
Client.Host:=hostip;
Client.Port:=strtoint(Edit2.text);
Client.Connect(10000); // in Indy < 8.1 leave the parameter away
ClientHandleThread:=TClientHandleThread.Create(True);
ClientHandleThread.FreeOnTerminate:=True;
ClientHandleThread.Resume;
except
on E:Exception do MessageDlg('&Aacute;&not;&frac12;&Oacute;·&thorn;&Icirc;&ntilde;&AElig;÷&Ecirc;±·&cent;&Eacute;ú&acute;í&Icirc;ó:'+#13+E.Message,mtError, [mbOk],0);
end;
end;
end;

procedure TClientFrmMain.CBClientActiveClick(Sender:TObject);
begin
if CBClientActive.Checked then
connectToserver(Edit1.text)
else
begin
if ClientHandleThread<>nil then
ClientHandleThread.Terminate;
Client.Disconnect;
end;
ButtonSend.Enabled:=Client.Connected;
// CBClientActive.Checked:=Client.Connected;
end;

procedure TClientFrmMain.ButtonSendClick(Sender:TObject);
var
CommBlock:TCommBlock;
begin
CommBlock.Command:='test'; // assign the data
CommBlock.MyUserName:='&sup2;&acirc;&Ecirc;&Ocirc;&iquest;&Iacute;&raquo;§&para;&Euml;';
CommBlock.Msg:=EditMessage.text;
sendMessage(CommBlock);
end;

procedure TClientFrmMain.FormClose(Sender:TObject;
var Action:TCloseAction);
begin
if ClientHandleThread<>nil then
ClientHandleThread.Terminate;
Client.Disconnect;
end;

procedure TClientFrmMain.FormCreate(Sender:TObject);
begin
Edit1.text:=get_ip;
end;

procedure TClientFrmMain.EditMessageKeyPress(Sender:TObject;
var Key:Char);
begin
if Key=#13 then ButtonSend.Click;
end;

end.
 
问题: 使用indytcpserver/indytcpclient在局域网内测试发送4M文件竟然用了20分钟,请看代码 ( 积分: 100 )
分类: 局域网 / 通讯

来自: dfw001, 时间: 2003-07-08 17:49:00, ID: 2012315
TCommBlock = record //定义数据传输格式
Command:char; //命令格式,a表示msg是传过来的文件
// b表示msg是传过来的聊天文本
Name:string[10]; //接收人姓名
Msg:array[0..1024] of char; //传送的内容
end;

//分块发送
CommBlock.Command :='a';
CommBlock.Name:='user01';
while 已发送的长度<文件总长度 do
begin
FillChar(CommBlock.Msg ,1025,0);
if 文件总长度-已发送的长度>1025 then
每次发送的长度:=1025
else
每次发送的长度:=文件总长度-已发送的长度;
stream1.Position :=Sendsize;
stream1.Read(CommBlock.msg,每次发送的长度);
//开始传送文件
form1.IdTCPClient1.Socket.Send(CommBlock,sizeof(CommBlock));
inc(已发送的长度,每次发送的长度);
end;
//分块接受
if CommBlock.command='a' then //开始传送文件
begin
i:=sizeof(CommBlock.Msg ); //每次接受的长度
stream1.Write(CommBlock.msg,i);//写文件
i_count:=i_count+i; //累计接受的长度
if i_count>=总长度 then
begin
Freeandnil(Stream1);
Messagebox(handle,'文件发送完毕!','提示息',mb_ok+mb_iconinformation);
end;
end
end;

高手指点一下。如何提高速度! dfw001@tom.com

来自: 参宿四, 时间: 2003-07-08 19:01:00, ID: 2012517
把每次发送的字节数改大。
这个用UDP也可以发的啊。

来自: dfw001, 时间: 2003-07-08 19:29:00, ID: 2012582
兄弟们帮帮忙啊

来自: barton, 时间: 2003-07-08 21:16:00, ID: 2012774
我没有用过Indy,按说没权力发言。不过我还是想表达我的几点不解:
1.UDP完全可以实现,速度也更快,只是需要改成一问一答式,防止丢包。
2.为什么每次传1025字节?好怪的一个数字。一般每次传送的总长度为2的幂比较好,看你
的结构中Command计4字节;Name计11字节;Msg计1025字节共1040字节,虽然按4字节对
齐,但要是我一定会选择1024字节,也就是Msg长1009字节或者2033字节。
3.接收方如何得到文件长度?当然,有可能是你别的传送过程传的,但既然已经传送了文件
长度,为什么不连Command和Name两个字段随文件长度一次传过去?反正TCP/IP是基于流的。
4.你的传送过程实际上是不停的,这和不分块没什么区别。按我从前不用API时候的经验,
每传送一次加一点延迟效果会更好。我不知道你用的Indy是通过什么机制来驱动,如果通过
事件来驱动则非常简单,直到收到系统的“发送区已空”的通知才发送下一块。

来自: firstrose, 时间: 2003-07-08 21:35:00, ID: 2012815
奇怪,我就用socket,606k的就一秒多一点。indy是block的。建议用socket!最快!
还有,你的数据分块对于indy是小了点,最好2-4k(对indy)。

来自: Rocklee, 时间: 2003-07-09 0:03:00, ID: 2013077
Indy是基于Block加线程。
很好用
我一点也不觉得慢。
其实根本用不着像作者那样做。
可以先发个命令标志过去,说明接下来的,是聊天文本还是传送文件。

如果传文件,可以先发送文件字节数(用writeinteger),再发送文件名(用
writeln),再发送文件流(用WriteStream)

如果是发送聊天文本的,就用writeln发送。

相应地,接收端,也是根本命令标志,判断聊天文本/传送文件
要一步一步对着干:
writeinteger == readinteger
writeln == readln
writestream == readstream


原理就是这样,不过值得一提的是,如果是小文件(不大于10M)就可以一次性用
writestream发出,如果够大的,就会非常慢,那不是indy的问题,是Delphi的TfileStream
处理问题。建议使用openfile api,然后再用read 分块读入内存,然后再发送,
处理速度将会大大提高。




来自: real_clq, 时间: 2003-07-09 0:12:00, ID: 2013088
没时间帮你找问题,不过有一个更严重的东东.
不能把TCommBlock = record 当做绶冲区!!!
实在想这样用,就应该是
TCommBlock = Packed Record
否则有可能会有无用字节.



来自: barton, 时间: 2003-07-09 1:35:00, ID: 2013140
怎么又碰到这家伙?到处胡说八道!
在这里使用Record比Packed Record更好,因为系统会为Record分配一个按四字节对齐的结
构。只要收发两端定义一致就毫无问题。反倒是压缩格式读起数据来反而慢。
以后不懂就静悄悄的,别以为自己真的是个专家!

Rocklee认为是文件问题的说法好象也不太对。我用TFileStream扫描过一个100M的文件,用了不到一秒钟。分块读和整块读都试过。应该说TFileStream是可靠的。我建议你测试一下
发送和接收循环的间隔时间比较好,这样很容易找到问题。

来自: lynu, 时间: 2003-07-09 8:24:00, ID: 2013258
barton, 呵呵.
看来我还是不要到处乱答,免得被人扁得毫无面子[:D]



来自: dfw001, 时间: 2003-07-09 8:38:00, ID: 2013312
非常谢谢各位兄弟们的答复
to Rocklee 这样一一对应好象不保险,如果有多人同时聊天,同时发送文件,先发命令,
再发内容我怕缓冲区里的内容次序容易混乱。

to barton 老兄再帮帮我分析原因

此贴我再增加100分,分给上面的兄弟。



来自: yanyandt2, 时间: 2003-07-09 8:48:00, ID: 2013340
Indy组件是组塞模式的,是否与这个有关?
把timeout数值改小点?

来自: real_clq, 时间: 2003-07-09 8:52:00, ID: 2013354
barton
&quot;只要收发两端定义一致就毫无问题&quot;
难道这不是我在提醒的?100m会多出多少个字节?这些字节在cpu中运算快还是在网络中
传输快.
我不答,你也不答,跟在我屁股后面干什么?就因为我指出你老线程中用得不妥的地方?
还有你那两个跟屁X呢?怎么不来?

to dfw001你干嘛不感谢我,我不来的话barton大X又怎么会来?
哈哈,玩笑.别当真.

来自: dfw001, 时间: 2003-07-09 9:11:00, ID: 2013417
to yanyandt2我试试;
to 参宿四 我把Msg改大试一试。
to real_clq 其实我也不想把TCommBlock = record 当做绶冲区!!!
但为了区分缓冲区里的内容是文本,文件,还是声音,所以我不得不用了一个记录类型,我
也很想只定义Msg:array[0..1024] of char,但没有其他好办法。
兄弟们还有没有其它好办法?


来自: yanyandt2, 时间: 2003-07-09 9:17:00, ID: 2013443
其实消息类型你用字符串定义也行吧
command-- name-- text
1个字符 最大20个字符 后面都是内容
然后客户端接收时,处理这样的字符串也很简单。

来自: barton, 时间: 2003-07-09 9:34:00, ID: 2013524
大家看看这个人的嘴脸!还好意思在这混!我是第四个答这个贴的,你把眼睛放亮一点!我
可是没有攻夫和你计较!死瘪三!100m会多出多少字节?倒底是CPU快还是网络传输快?回
去问你老师去!你老师既不教你技术又不教你做人,真是误人子弟!我凭什么跟你讲?

大家不要见怪。大富翁总的来说是个纯净的地方。我也是和大家交流学习,只是容不得个别
人无端破坏气氛。lynn也算是高手一个,我凭什么扁你,只要你不扁我我就高兴得不得了
了。[:D]

dfw001:我也花了些时间好好看你的源码,感觉不出哪儿有问题。我平常遇到这样的问题总
是加入一些计时的代码,然后看看到底是收的问题还是发的问题。有了这个依据,就很快
能够判断出来问题所在了。最简单的处理就是创建一个log文件,记录什么时候开始发送,
什么时候发送完毕;什么时候开始接收,什么时候接收完毕。两个时间表一对照,就能够
判断是哪一边的问题。另外,你不妨在你的记录中加入当前时间这个字段,两边比较更可
靠一些。

来自: real_clq, 时间: 2003-07-09 10:13:00, ID: 2013710
to 我是指回答字节对齐的问题.
to dfw001一般的做法是将record中的内容写入缓冲区再处理.
速度问题我再看看,现在上班很危险.

来自: jiajiajia888, 时间: 2003-07-09 10:13:00, ID: 2013713
你不考虑加密、解密,但是要考虑压缩、解压缩啊!

来自: real_clq, 时间: 2003-07-09 10:22:00, ID: 2013746
//分块接受
if CommBlock.command='a' then //开始传送文件
问题可能在这里,你是不是循环读CommBlock结构,然后找其中的command?
说实话这样做法是比较笨的[别误会,没别的意思].你可以参考smtp,pop3这样
的协议,它们都是先应答,确定对方要接收数据时才发送大块的数据的,而不是每一次都
把这样1k多的东东发过去,然后再做判断.

来自: dfw001, 时间: 2003-07-09 10:37:00, ID: 2013791
现在把msg加到2048速度快了点。但还要是要10分钟左右。
to barton,我发送,接受都有进度条跟踪显示,感觉发送端和接受端速度一样。
我怀疑是不是我不应该定义record类型.


来自: dfw001, 时间: 2003-07-09 11:00:00, ID: 2013901
to real_clq 你说的对,每次读取缓冲区中的内容后我再判断command的值然后分别处理
程序的结构是这样的:
form1.IdTCPClient1.ReadBuffer(CommBlock,sizeof(CommBlock));
if CommBlock。command='a' then
//接受文件
else if CommBlock。command='b' then
//显示聊天内容
else if CommBlock。command='c' then
//其他

来自: real_clq, 时间: 2003-07-09 11:06:00, ID: 2013933
那就是了,不管定不定义record类型,都不应该在只要一个字节的时候发1k过去.
还是建议看一下pop3这样的协议,修改一下变成自己的很快就可以做出来了.

来自: dfw001, 时间: 2003-07-09 11:25:00, ID: 2014053
to real_clq,你说的很对,只要一个字节的时候发1k过去,我也感觉这很不好。
如何修改record,请给点代码行吗?
你的意思和Rocklee一样吗?


来自: barton, 时间: 2003-07-09 11:30:00, ID: 2014075
你的速度慢肯定与结构无关。最多你不要将你的整个结构都发过去。C语言写的程序基本上
都是用结构。我的第一个回复就问你流的长度控制方法。TCP协议都是基于流的。我平时
做流的长度控制是数据块的前四个字节表示流的长度,然后才是控制命令。这样结构是个
可变长的结构。如果你定义缓冲区是4096字节,你就一次发送4096字节,但不是每次都发
送流控制块。接收方在收到第一个块的时候必须保证接收完第一个数据块所指定的长度。

但是据我对indy的了解,indy自己封装了长度控制机制,所以如果你控制好,indy能够对
包进行正确的分离处理。既然你没有看出发送的包与接收的包有什么不同之处,我相信你
一定有办法控制传输块的长度。但是无论如何,我应该导致传输速度下降这么厉害。

发送和接收的速度肯定是一样。但是这中间肯定有一个延迟,你现在最需要找的就是这个
延迟的原因。从你描述的情况看,发送端的问题可能更大一些。

我建议你:
1.将结构的总大小定义为1024的倍数,如果传输实际内容可以填满整个结构则发送整个结
构,否则只发送结构头加实际内容长度;
2.不必每次都发送结构头。如果整个包一次不能发送出去,第二次发送的时候只需要发送
剩余的内容。
3.接收方一定要控制好传输长度逻辑。最好将这一功能交Indy去完成。它好象有一个属性
可以控制是否传输长度信息,你自己找找。

来自: real_clq, 时间: 2003-07-09 12:21:00, ID: 2014284
是,Rocklee基本上我同意.
不过后面读文件的我没研究过.我一直用blockread已经非常快了.

来自: dfw001, 时间: 2003-07-09 12:46:00, ID: 2014355
to barton
1:我现在将总结构长度定为2048速度有所改善。
你的建议我好好研究一下。非常感谢。
to real_clq因为网络上有多人传送文本和文件过来,假设某人先发了一个a命令过来,表示
紧接着发的是b文件,但有时次序不可能都这么好,也许在b到缓冲区之前有人发了一个c过来,那不就错了?



来自: 影 子, 时间: 2003-07-09 12:49:00, ID: 2014398

2048在Internet上传有没问题?


来自: chengjp, 时间: 2003-07-09 12:51:00, ID: 2014409
to 影 子 我有点担心,我还是希望每次发送为1K左右,但我现在先解决测试问题再说。

来自: Rocklee, 时间: 2003-07-09 13:32:00, ID: 2014481
To dfw001:
都说了Indy 是基于Block与线程的了,当然你的工作框架也应该这样。
Indy通常是采用C/S的结构吧,Server中每个连接都是独立的。
如果你认为聊天文本会与文件传输混乱了,那就错了,就算是把两者的功能
都写在同一个TTcpipConnection的OnExecute中去,也不会混乱,因为它是基于
线程的,而且是Block。
可以在OnExecute事件中采用:
with athread.connection do begin
case cmd of
cmd_chat: begin
sChat:=readln;
...
end;
cmd_filetrans: begin
nSize:=readInteger();
sFileName:=readLn();
end;
.....
end;
end;
即使还有很多很多命令加到这里,也不会出现混乱。
不写了,再写就没意思。
Indy的处理方式与FastNet的处理方式很是不同,不但TCPIP,UDP也是。

To barton:
要发送100M的文件,就先把这100M的文件读入内存。好,先撇下
Delphi的Stream处理机制不提,就看Windows的,如果你机子内存真的可以容
纳下这庞大的家伙就算你走运,否之,Windows则非常聪明地用硬盘帮你先搁
下来,听着硬盘吱吱地响,那也只是做从[red]硬盘读出数据再写入硬盘[/red]这愚蠢的操
作,你觉得这样做爽吗?
不要用100M的文件去试了,干脆用200M的吧,哈哈,看你的机子不死翘翘才怪。
你又不是不知道Windows的内存管理有多糟!


来自: barton, 时间: 2003-07-09 13:37:00, ID: 2014561
Rokelee:稍有编程常识的人都会怀疑,怎么能一次将一个100M的文件读入内存?我起初也
这样想。但是我试了,我在一个差不多100M的文本文件中搜索一个1024字节长的串,目的
是测试那个搜索算法的性能。开始我是每次读入32K,第二次必须向前移动1024字节的指针
再读入后面的文本。因为事先故意安排目标串在文件的最后,所以必然要扫描整个文件。
结果时间在300ms左右。然后用GetMem申请100M内存,读入,一次进行搜索,时间还是300
ms左右。我也没太闹明白,事实就是如此。我认为有可能在读入文件的时候,系统只是直
接将文件页面与内存交换页面作个关联而已。我没有对Windows的文件系统做过详细研究。
我的系统是Windows 2000,1G内存。
对于本问题,我只是认为不应该从TFileStream找答案,你不必见怪。

来自: barton, 时间: 2003-07-09 13:41:00, ID: 2014567
其实我也倾向于一次读一部分,如果网络在传输中中断,就是全部读出来又有什么用。不过
我认为不必用到File操作的API罢了。[:D]

来自: j_shen2000, 时间: 2003-07-09 14:09:00, ID: 2014657
to dfw001:
你是不是刚开始很快,后来越来越慢:)。我第一次用INDY的时候遇到过同样的问题,呵呵,其实还是和STREAM有关的。

来自: dfw001, 时间: 2003-07-09 14:30:00, ID: 2014719
to Rocklee:我的服务器端只起转发作用,athread.connection 事件只是根据CommBlock.name的值找到该线程然后将CommBlock发给客户端叫name的。

如果我只是从客户端发到服务器端,有你的方法肯定好。很谢谢你的回答

to j_shen2000那你是如何解决STREAM的?

来自: real_clq, 时间: 2003-07-09 14:47:00, ID: 2014797
&quot;来自:dfw001, 时间:2003-7-9 12:46:00, ID:2014355&quot;
这里的东东没看明白.indy下面肯定是socket,而每个socket都有自己的缓冲区的,怎么可能
冲突呢?

来自: dfw001, 时间: 2003-07-09 14:54:00, ID: 2014835
to real_clq 我客户端接受信息用的是一个线程,接受文本,文件都是在该线程的下根据接收的command处理。对于接收客户端来说肯定只有一个缓冲区了。

来自: real_clq, 时间: 2003-07-09 15:01:00, ID: 2014867
一个线程同时处理两个以上的连接么?

来自: dfw001, 时间: 2003-07-09 15:21:00, ID: 2014967
to real_clq 客户端用一个idtcpclients开一个端口连接服务器。服务器也只开一个端口联结客户端。服务器的作用只是起中转作用。客户端用一个线程循环读取缓冲区里的内容。

如果有a,b,c三个客户端同时向d客户端发送文件或文本,按照先发命令,再发文本或文件的
方法。能够保证d客户端缓冲区的内容为:
a.command,a.msg,b.command,b.msg,c.command,c.msg ?

如果客户端有2个缓冲区就好,一个接文本,一个接文件那就没有这么麻烦。


来自: real_clq, 时间: 2003-07-09 15:40:00, ID: 2015063
哦,是有点麻烦.不过也不是没有办法.
socket的实现一般就是一个整数,你可以在服务器转发时每次同时发这个整数到接收的客户
端,这样客户端就可以确定这一批数据是从那个socket来的了.当然它要为每个&quot;假&quot;的socket
建立缓冲区--这也不难,用list保存各个缓冲区的地址就可以了.

来自: Rocklee, 时间: 2003-07-09 18:42:00, ID: 2015901
To barton:
怪不得你的口气这么牛了,原来有1G作后盾,哈哈。
俺的服务器才2G,自己的电脑才256M,因为俺穷,所以我要省着用[:D]
你认为用API读入块,不好么?嘿嘿,哪个VCL不是最终是调用API的?
如果是繁复的API,俺也不赞成采用,但是这文件读入嘛,简单得要命,
不用白不用。

To dfw001:
这也不一样的做嘛。
对于Indy来说,所谓的Client Side,也应该有TTcpipServer来监听吧?(前提是用
TCPIP协议)
Server Side 也一样,开一个TTCPIPServer作主监听。因为每一个连接,Indy均开一个
Thread进行侍服,所以,建议你每个Connection建立时,开一个Tdatamodule,然后在datamodule中建立一procedure与TTCPIPServer的OnExecute相对接。TdataModule里面建立一个TTCPIPClient来进行中转,连接断开时,则释放此module(Thread无须手动释放)。
这样的处理,很模块化,而且绝对不会造成数据混乱。
Indy 这样的处理方式,非常易用,而且绝对不会造成数据混乱,恰好相反,Fastnet
的组件才容易,因为它是基于事件的,而且自己定义数据包,无形中发送大量的垃圾,如果在对速度要求很高的网络环境下,最不适采用。


来自: Rocklee, 时间: 2003-07-09 18:49:00, ID: 2015924
To dfw001:
客户端用一个idtcpclients开一个端口连接服务器。服务器也只开一个端口联结客户端。服务器的作用只是起中转作用。客户端用一个线程循环读取缓冲区里的内容。

如果有a,b,c三个客户端同时向d客户端发送文件或文本,按照先发命令,再发文本或文件的
方法。能够保证d客户端缓冲区的内容为:
a.command,a.msg,b.command,b.msg,c.command,c.msg ?

如果客户端有2个缓冲区就好,一个接文本,一个接文件那就没有这么麻烦。


用我的方法,就可以完全解决你的问题你的问题。


来自: dfw001, 时间: 2003-07-09 19:24:00, ID: 2016025
来自:Rocklee, 时间:2003-7-9 0:03:00, ID:2013077
to Rocklee 我还是觉得你的方法适合从客户端发到服务器端。 从客户端发到客户端不能
保证次序正确

来自: Rocklee, 时间: 2003-07-10 0:45:00, ID: 2016507
To dfw001:
要看你Client side是如何设计了!
我看你是不是没用过Indy ?
Client Side也放两个组件啊,一个是TCPIPClient 一个是TCPIPServer!!!
Client组件为发送,Server组件为接收!那怎么会出现混乱呢,因为Server
为每个连接均建立一个Thread进行侍服!!
这也是基于线程的网络传输服务的最基本的写法。
我用这种方式写过很多程序了。

来自: 参宿四, 时间: 2003-07-10 5:07:00, ID: 2016576
多线程的话加个序号来识别就行了吧

来自: dfw001, 时间: 2003-07-10 9:33:00, ID: 2016883
to Rocklee 哦,这样啊,我一般客户端只放一个TCPIPClient,服务器端才放一个
tcpserver,你的方法我试试。
我一般数据库做的多点,只是现在要编一个通讯方面的才使用indy,非常感谢你。交个朋友
175140297这是我的qq。
请到这里拿分。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2016878

来自: dfw001, 时间: 2003-07-10 14:06:00, ID: 2017890
Client Side也放两个组件啊,一个是TCPIPClient 一个是TCPIPServer!!!
to Rocklee 我又来了,你的方法我测试好象行不通啊

因为客户端ip不是固定ip,客户端加个TCPIPServer没有固定ip怎么用?


来自: 呆四少, 时间: 2003-07-10 14:18:00, ID: 2017949
看得我的人都乱了。呵呵:)
我用INDY写过一个发送文件的东东。很快啊。10M的局域网上可以达到大概800多K/秒。
在宽带网上传有过100多K。还支持断点续传。支持发送整个目录。支持压缩目录,用它来压缩了FIFA2003。500多兆。一样的啊。大概都是这个速度。要源码的话我可以发给你。呵呵。不过用了好些组件。都发的话太多了。可以把怎么发送文件的关键部分代码给你。

来自: dfw001, 时间: 2003-07-10 14:39:00, ID: 2018029
to 呆四少那太好了,发给我参考一下,我给你加分。
我的email: dfw001@tom.com
关键是发送和接受

来自: 呆四少, 时间: 2003-07-10 14:52:00, ID: 2018074
已发送,请查收。

来自: Rocklee, 时间: 2003-07-10 18:30:00, ID: 2018955
To dfw001 :
不需要用固定IP啊,在TCPIPServer里,你用PeerIP就可以拿到连接的Client Connection 的IP了!
用这个: AThread.Connection.Binding.PeerIP


来自: Rocklee, 时间: 2003-07-10 18:32:00, ID: 2018962
如果你能仔细参考一下Indy的Help就能很容易应用它了,Indy组件写得非常好。
在Delphi5的年代,我已经开始研究Indy了。



来自: dfw001, 时间: 2003-07-10 18:36:00, ID: 2018967
看得出你是个indy高手,我再试试,
我以前一直搞数据库的,搞通讯水平很差,很谢谢你的耐心指导。

来自: dfw001, 时间: 2003-07-11 1:10:00, ID: 2019498
多人接受答案了。

得分大富翁: barton-20,real_clq-20,Rocklee-30,yanyandt2-5,参宿四-5,呆四少-20,
 
多谢两位大侠,我已经搞定,是我大意了,我在收取的函数里
// ProcessReData(stringdd);
测试后忘记屏蔽掉了,ProcessReData处理东西太多导致新开线程也搞不定。
两位各得100分。
不过,顺便问一下,tcppserver的onwork和onstatus的作用呢?
onwork中AWORK怎么用啊?
能不能讲一下呢?
 
后退
顶部