使用indytcpserver/indytcpclient在局域网内测试发送4M文件竟然用了20分钟,请看代码(100分)

  • 主题发起人 主题发起人 dfw001
  • 开始时间 开始时间
那就是了,不管定不定义record类型,都不应该在只要一个字节的时候发1k过去.
还是建议看一下pop3这样的协议,修改一下变成自己的很快就可以做出来了.
 
to real_clq,你说的很对,只要一个字节的时候发1k过去,我也感觉这很不好。
如何修改record,请给点代码行吗?
你的意思和Rocklee一样吗?
 
你的速度慢肯定与结构无关。最多你不要将你的整个结构都发过去。C语言写的程序基本上
都是用结构。我的第一个回复就问你流的长度控制方法。TCP协议都是基于流的。我平时
做流的长度控制是数据块的前四个字节表示流的长度,然后才是控制命令。这样结构是个
可变长的结构。如果你定义缓冲区是4096字节,你就一次发送4096字节,但不是每次都发
送流控制块。接收方在收到第一个块的时候必须保证接收完第一个数据块所指定的长度。

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

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

我建议你:
1.将结构的总大小定义为1024的倍数,如果传输实际内容可以填满整个结构则发送整个结
构,否则只发送结构头加实际内容长度;
2.不必每次都发送结构头。如果整个包一次不能发送出去,第二次发送的时候只需要发送
剩余的内容。
3.接收方一定要控制好传输长度逻辑。最好将这一功能交Indy去完成。它好象有一个属性
可以控制是否传输长度信息,你自己找找。
 
是,Rocklee基本上我同意.
不过后面读文件的我没研究过.我一直用blockread已经非常快了.
 
to barton
1:我现在将总结构长度定为2048速度有所改善。
你的建议我好好研究一下。非常感谢。
to real_clq因为网络上有多人传送文本和文件过来,假设某人先发了一个a命令过来,表示
紧接着发的是b文件,但有时次序不可能都这么好,也许在b到缓冲区之前有人发了一个c过来,那不就错了?

 

2048在Internet上传有没问题?
 
to 影 子 我有点担心,我还是希望每次发送为1K左右,但我现在先解决测试问题再说。
 
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的内存管理有多糟!
 
Rokelee:稍有编程常识的人都会怀疑,怎么能一次将一个100M的文件读入内存?我起初也
这样想。但是我试了,我在一个差不多100M的文本文件中搜索一个1024字节长的串,目的
是测试那个搜索算法的性能。开始我是每次读入32K,第二次必须向前移动1024字节的指针
再读入后面的文本。因为事先故意安排目标串在文件的最后,所以必然要扫描整个文件。
结果时间在300ms左右。然后用GetMem申请100M内存,读入,一次进行搜索,时间还是300
ms左右。我也没太闹明白,事实就是如此。我认为有可能在读入文件的时候,系统只是直
接将文件页面与内存交换页面作个关联而已。我没有对Windows的文件系统做过详细研究。
我的系统是Windows 2000,1G内存。
对于本问题,我只是认为不应该从TFileStream找答案,你不必见怪。
 
其实我也倾向于一次读一部分,如果网络在传输中中断,就是全部读出来又有什么用。不过
我认为不必用到File操作的API罢了。[:D]
 
to dfw001:
你是不是刚开始很快,后来越来越慢:)。我第一次用INDY的时候遇到过同样的问题,呵呵,其实还是和STREAM有关的。
 
to Rocklee:我的服务器端只起转发作用,athread.connection 事件只是根据CommBlock.name的值找到该线程然后将CommBlock发给客户端叫name的。

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

to j_shen2000那你是如何解决STREAM的?
 
"来自:dfw001, 时间:2003-7-9 12:46:00, ID:2014355"
这里的东东没看明白.indy下面肯定是socket,而每个socket都有自己的缓冲区的,怎么可能
冲突呢?
 
to real_clq 我客户端接受信息用的是一个线程,接受文本,文件都是在该线程的下根据接收的command处理。对于接收客户端来说肯定只有一个缓冲区了。
 
一个线程同时处理两个以上的连接么?
 
to real_clq 客户端用一个idtcpclients开一个端口连接服务器。服务器也只开一个端口联结客户端。服务器的作用只是起中转作用。客户端用一个线程循环读取缓冲区里的内容。

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

如果客户端有2个缓冲区就好,一个接文本,一个接文件那就没有这么麻烦。
 
哦,是有点麻烦.不过也不是没有办法.
socket的实现一般就是一个整数,你可以在服务器转发时每次同时发这个整数到接收的客户
端,这样客户端就可以确定这一批数据是从那个socket来的了.当然它要为每个"假"的socket
建立缓冲区--这也不难,用list保存各个缓冲区的地址就可以了.
 
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
的组件才容易,因为它是基于事件的,而且自己定义数据包,无形中发送大量的垃圾,如果在对速度要求很高的网络环境下,最不适采用。
 
To dfw001:
客户端用一个idtcpclients开一个端口连接服务器。服务器也只开一个端口联结客户端。服务器的作用只是起中转作用。客户端用一个线程循环读取缓冲区里的内容。

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

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


用我的方法,就可以完全解决你的问题你的问题。
 
来自:Rocklee, 时间:2003-7-9 0:03:00, ID:2013077
to Rocklee 我还是觉得你的方法适合从客户端发到服务器端。 从客户端发到客户端不能
保证次序正确
 
后退
顶部