RT ... 现在要做一个上传的模块,打算用这两个组件来实现..可是从来没用过这两个东东,也没搞过网络编程这方面的东西....
现在有些问题问下.各位达人帮帮忙...
1.客户端要求是每个文件支持多线程上传,要求线程数可配置.(即如果有多个用户同时上传,则为每个用户单独开一线程来接收)
2.客户端要求能支持断点续传功能,客户端再连接到网络的时候自动把还没传完的文件传完.
3.客户端连接到服务器端的时候会进行身份认证而且客户端的登录帐号和密码是加密.
4.客户端发到服务端的文件需要进行文件数据完整较验.如果失败通知客户端重新发送文件,服务器端会把不完整文件删除.
5.服务器接收的并发数可配置,最高要求1000个.
6.服务端要做好统计数量的接口,统计项目如下:上传/下载速度(KB/S),已上传的文件大小(KB),登录上传的用户名,上传的文件路径.文件传输完共用的时间,上传文件的日期和时间
7.端口监听和释放,即其中一个用户传输完毕,则释放相应的端口.
-------------------------------------------------------------
真诚的请教各位....如果有实现过,麻烦帮忙说一下其中的原理,比如多线程的创建和调用,当有用户发出请求时就要创建一个线程.都要注意些什么,具体的代码我想自己实现
分不够再加.....
现在有些问题问下.各位达人帮帮忙...
1.客户端要求是每个文件支持多线程上传,要求线程数可配置.(即如果有多个用户同时上传,则为每个用户单独开一线程来接收)
2.客户端要求能支持断点续传功能,客户端再连接到网络的时候自动把还没传完的文件传完.
3.客户端连接到服务器端的时候会进行身份认证而且客户端的登录帐号和密码是加密.
4.客户端发到服务端的文件需要进行文件数据完整较验.如果失败通知客户端重新发送文件,服务器端会把不完整文件删除.
5.服务器接收的并发数可配置,最高要求1000个.
6.服务端要做好统计数量的接口,统计项目如下:上传/下载速度(KB/S),已上传的文件大小(KB),登录上传的用户名,上传的文件路径.文件传输完共用的时间,上传文件的日期和时间
7.端口监听和释放,即其中一个用户传输完毕,则释放相应的端口.
-------------------------------------------------------------
真诚的请教各位....如果有实现过,麻烦帮忙说一下其中的原理,比如多线程的创建和调用,当有用户发出请求时就要创建一个线程.都要注意些什么,具体的代码我想自己实现
分不够再加.....
解决方案 »
- 一打开dpr文件就出错Access violation at address 4000586A in module ‘rtl60.bpl’. Read of address 400A1004
- D7怎样处理以前在D5里面做的QReport?
- 扩展了controls.pas的一些功能,但是我编译不了!!!!
- sql语句错误,大家看看。
- 这个select怎么写?
- 在sql 裡如何實現呢?用什麼命令可以實現?
- 各位老大,烦死我了,被电信追欠缴话费。
- 辞职报告怎么写?
- 一个关于日期的问题!
- 请教控件安装问题
- DBGrid 如何使点击表头就自动按表头字段排序
- Delphi 2009中的新语法?有没有谁能帮我解释下。
2.可以这样,如果只有一个线程的话,从文件的开始下载,下载长度为文件的长度,如果已经存在一个线程的话,从文件的中间下载,然后把前一个线程要读取的长度告诉给第一个线程,即第一个文件要下载的长度为文件长度除2,依次类推,这是动态的。不过一般不这样进行。
3.预先定义好要创建的线程数,然后把要下载的文件分成几部分,分别下载,下载完成后把分别下载的部分合并
4.如果断点续传的话,首先判断有几个线程,方法是查找有几个文件即可,然后把要下载的文件分成几个部分,判断各个线程文件的长度,即得要要下载的起始位置,然后每个线程关联一个文件,从起始位置开始下载指定的长度即可,最后合并
第一步:把ServerSocket1.ServerType设成stThreadBlocking
第二步,在主线程中循环接收命令数据
第三步,如果有客户发过来请求下载文件命令,则根据Socket: TCustomWinSocket创建该用户的线程,然后处理文件即可,这个Socket负责这个线程的接收和发送
那idTCPServer 这两个控件能否实现我要的那些功能?
具体的实现步骤能否讲一下?谢谢!
这个是客户端的
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient;type
TForm1 = class(TForm)
btnSend: TButton;
Edit1: TEdit;
Memo1: TMemo;
btnConnect: TButton;
IdTCPClient1: TIdTCPClient;
btn001: TButton;
btn002: TButton;
procedure btnConnectClick(Sender: TObject);
procedure btnSendClick(Sender: TObject);
procedure btn001Click(Sender: TObject);
procedure btn002Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TClientHandleThread = class(TThread)
private
cmdstr:string;
procedure HandleInput;
protected
procedure Execute; override;
end;
var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.btnConnectClick(Sender: TObject);
begin
try
IdTCPClient1.Host:='127.0.0.1';
IdTCPClient1.Port:=5000;
IdTCPClient1.Connect;
showmessage('连接成功');
except
showmessage('连接失败');
end;
end;procedure TForm1.btnSendClick(Sender: TObject);
begin
IdTCPClient1.WriteLn('003');
IdTCPClient1.WriteLn(edit1.Text);
end;{ TClientHandleThread }procedure TClientHandleThread.Execute;
begin
inherited;
while not Terminated do
begin
if not form1.IdTCPClient1.Connected then
Terminate
else
try
cmdstr:=form1.IdTCPClient1.Readln;
Synchronize(HandleInput);
except
end;
end;
end;procedure TClientHandleThread.HandleInput;
begin
if cmdstr='001' then
begin
form1.Memo1.Lines.Add('I am 001');
end;
if cmdstr='002' then
begin
form1.Memo1.Lines.Add('I am 002');
end;
end;procedure TForm1.btn001Click(Sender: TObject);
begin
IdTCPClient1.WriteLn('001');
end;procedure TForm1.btn002Click(Sender: TObject);
begin
IdTCPClient1.WriteLn('002');
end;
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;type
TForm1 = class(TForm)
btnlogin: TButton;
Memo1: TMemo;
Edit1: TEdit;
btnSend: TButton;
IdTCPServer1: TIdTCPServer;
procedure btnloginClick(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.btnloginClick(Sender: TObject);
begin
IdTCPServer1.DefaultPort:=5000;
IdTCPServer1.Active:=true;
end;procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
str:string;
begin
str:=AThread.Connection.ReadLn;
if str='001' then
begin
showmessage('001 cmd');
AThread.Connection.WriteLn('001');
exit;
end;
if str='002' then
begin
showmessage('002 cmd');
AThread.Connection.WriteLn('002');
exit;
end;
if str='003' then
begin
memo1.Lines.Add(athread.Connection.ReadLn);
exit;
end;
end;end.
最大允许数;如果超出就给客户机返回一个状态告诉客户机已经不能连了,同时结束其它操作.我想用户名和密码的验证应该很容易就搞定了吧?! 至于连接还是断开,只是给客户机返回两种不同的状态而已。
断点续传,其实可以简单的实现: 客户机每次发文件数据包给服务器的时候,带上数据体的大小和在文件中位置的信息,服务器在接收时,
以这个数据体的大小及位置信息写到相应的接收文件中就可以了。注:再实现的时候用Indy的idTcpServer和idTcpClient控件来作,这样在服务器返回要好实现一点(直接在idTcpServer.OnExecute
事件里就要实现)。
次处理好一个用户的验证就好了,但是要注意处理可能存在的资源冲突
在传文件时,客户端大概过程如下,服务端就接收返回相应状态就可以了:procedure TXXXThread.OnExecute(Sender: TObject);
type
TFileBlock = record
FileName: string[225];
Start: Integer;
Size: Integer;
BlockData: array[1..1024] of byte;
end;
var
ABlock: TFileBlock;
Remain: Integer;
AFile: TFileStream;
Flag: Integer;
begin
//.....
ABlock.Start := XXX//从传输日志取已经传完的位置信息;
ABlock.FileName := YourFileName;
repeat;
AFile.Position := ABlock.Start;
ABlock.Size := AFile.Read(ABlock.BlockData, SizeOf(ABlock.BlockData));
ABlock.Start := AFile.Position; IdTCPClient.WriteBuffer(ABlock, SizeOf(ABlock));
IdTcpClient.ReadBuffer(Flag, SizeOf(Flag));//由服务器接收返回
if Flag = 成功 then
begin
记录当前传输的日志
Remain := AFile.Size - ABlock.Start;
end
else
begin
Self.Terminate;
Break;
end;
until Remain <=0;
end;注:楼主还先在网上下载一些示例代码,再学一下控件。然后再看看考虑考虑说不定问题就解决了
第一步实现简单上传,一个用户对应一个连接,同时一个文件,并做好相应的其它功能,包括日志等等。对于客户端来讲,多线程,其实就是多个连接,也就是需要多个TClientSocket来参与。这个只是把原来单一的一个,复制成了多份,然后放在不同的线程里。第二步,断点,也就是分段。第三步,对多个连接增加一个登录标识,就好象是原来多个连接的一个客户,进行了一个统一地计划,而划分到一个连接组当中,当然最方便的方法就是为同时在传输同一个文件的多个连接划分在一起。
服务器有一个公开端口用来监听请求,比如5000.客户端连接都往5000这个端口发送连接请求.服务器端验证并且通过后,创建线程,线程里bind一个新的空闲端口,比如40000,并给客户端回消息让客户端更改服务器通讯端口.线程启动后,客户端实际是与服务器的40000端口在通讯,而主线程继续监听5000端口.
linux下socket通讯很多都是这样做的,只不过linux下是fork出一个进程来处理,而delphi里一般创建线程来处理.
端口冲突你不用担心,可以让系统自动分配可用端口.实际上你应该不用担心要在服务器维护一个庞大的客户端列表.idtcpserver本身就可以支持与多个客户端通讯,所以你可以给每个客户端创建一个idtcpserver,这样每个客户端的多线程也可以解决.
当然,这些仅限于当初的方案设计。当时考虑的主要是负载问题,我们的方案设想在负载较大时可能要创建进程而不是线程,因为创建进程可以更好的抢占系统资源。后来因为一些原因项目还没正式启动就搁置了,只有个java写的服务器端的最初测试程序,但后来弄丢了。
服务器开多线程主要是方便管理,因为你有多用户且每个用户还有多线程,所以干脆给每个用户创建个idtcpserver并分配独立端口通讯比较好一些.
2.分块传输,这不应该是服务器干的活,而是客户端干的,客户端只要指明了文件是哪一个,当前传上来了多少数据,是从文件哪一个位置(Position)开始的就可以了。
3.就是CreateFileMapping就可以,这样子一个线程控制一个文件的句柄,可以随意地移动文件的位置指针,而不影响其它线程。
我觉得这种方法也行,只是操作起来太复杂和繁琐了...
to :unsigned
如你所说客户端用多线程发送文件块,那在服务端它怎么将这些写入文件?在 IdTCPServer1Execute 这里进行写文件就可以了吗?
还有就是,你是采用什么方式来断点续传的?也是用记录文件写入的信息吗?