学习TServerSocket 和 TClientSocket进行文件传输,为什么多个Client同时向Server传时,出现如下错误: (30分)

B

Boblee

Unregistered / Unconfirmed
GUEST, unregistred user!
情况如下:
如果有两个以上的客户端向Server端传文件,只要其中有一个客户完成,有时一个也没完成,
服务端就出现I/O错误,错误编号是:103. 出错的行我已在下面的服务器代码中标出。
哪位网络编程高手知道其中原因? 一个客户端传文件没问题。

代码如下:
客户端:
unit main2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls, ComCtrls;

type
TForm1 = class(TForm)
nmg_objClientSocket: TClientSocket;
Button2: TButton;
Edit1: TEdit;
StatusBar1: TStatusBar;
OpenDialog1: TOpenDialog;
procedure Button2Click(Sender: TObject);
procedure nmg_objClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure nmg_objClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure nmg_objClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
private
stream : TMemoryStream; //定义内存流,其实用文件流也可以
size,count : integer; //文件大小
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
nmg_blnServerReady:boolean;

implementation

{$R *.dfm}

procedure TForm1.nmg_objClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected to '+Socket.RemoteAddress;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
nmg_objClientSocket.Address := Edit1.Text;
//nmg_objClientSocket.Port:=2000;
nmg_objClientSocket.open;
end;

procedure TForm1.nmg_objClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
rcvtxt : string;
buf : array [1..2048] of char;
left : integer;
begin
rcvtxt := Socket.ReceiveText;
left := size - count; //未读字节数
if AnsiPos('go',rcvtxt)=1 then //收到响应则发
begin
StatusBar1.SimpleText := '正在传文件。'+Format('%3.0f',[count/size * 100]);
if sizeof(buf)<left then //若满一块则读一块
begin
stream.Read(buf,sizeof(buf));
Socket.SendBuf(buf,sizeof(buf));
count := count + sizeof(buf);
end
else //不满则发剩余的
begin
stream.Read(buf,left);
Socket.SendBuf(buf,left);
socket.Close;
end;
end;

if AnsiPos('yesReady',rcvtxt)=1 then //收到响应则发
begin
stream := TMemoryStream.Create;
//if OpenDialog1.Execute then
//begin
stream.LoadFromFile('I:/a.exe');
size := stream.Size; //获得文件大小
StatusBar1.SimpleText := '准备传文件。文件大小:'+inttostr(size);
count := 0;
//nmg_objClientSocket.Socket.SendText(); //先发送大小
Socket.SendText(inttostr(size));
//end;
end;

if AnsiPos('noReady',rcvtxt)=1 then //收到响应则发
begin
showmessage('noready');
nmg_blnServerReady := false;
Socket.Close;
end;
end;

procedure TForm1.nmg_objClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'disconnect';
end;
end.

服务器端:
unit server2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, ComCtrls, StdCtrls;

type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
StatusBar1: TStatusBar;
SaveDialog1: TSaveDialog;
nmg_txtMonitorDir: TEdit;
procedure CutFirst(denstr: string;scrstr: string);
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
Tof : file;
size,count :integer;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.CutFirst(denstr: string;scrstr: string);
var
len :integer;
begin
len := length(scrstr);
denstr := copy(scrstr,2,(len-1));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
//ServerSocket1.Port := 2000;
ServerSocket1.Active := true;
StatusBar1.SimpleText := 'Listening...';
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Connected from '+ Socket.RemoteAddress;
if nmg_txtMonitorDir.Text = '' then
Socket.SendText('noReady')
else
Socket.SendText('yesReady');
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
buf : array [1..2048] of char;
rcvtxt : string;
left,len : integer;
fileName:string;
begin
len := Socket.ReceiveLength;
if len<10 then //若长度小于10则认为是文件长度
begin
rcvtxt := Socket.ReceiveText;
size := strtoint(rcvtxt);
count := 0;
//if SaveDialog1.Execute then
//begin
Repeat
fileName := 'c:/temp/'+IntToStr(Random(10000))+'.exe';
Until not FileExists(fileName);
AssignFile(ToF, fileName);
Rewrite(ToF, 1);
//end;
Socket.SendText('go'); //响应一块
end
else
begin
left := size - count; //未写的字节数
if sizeof(buf)<left then //满一块则写一块
begin
Socket.ReceiveBuf(buf,sizeof(buf));
BlockWrite(Tof,buf,sizeof(buf));
count := count + sizeof(buf);
Socket.SendText('go');
end
else //否则写剩余字节数
begin
Socket.ReceiveBuf(buf,left);
[red] BlockWrite(Tof,buf,left); //就是这行出错[/red]
CloseFile(Tof);
//Socket.Close;
end;
end;
end;
end.
 
好象分少了点,代码多了点!

对于serversocket端的发送应改为
serversocket1.socket.connection.sendbuf(buf,sizeof(buf));
这样对于不同的连接能区别对待并处理,在我机器上调试通过!
不过,好象误码率高,传送后的文件打不开哟,估计跟判定条件不当有关
 
呵呵,对啦,你同时接受两个要做判断的!接收的到底是哪个的!
 
这个问题我已自已解决了,传送成功后的文件都能打开:)。
 
呵呵,我想如果你的代码上了internet要出多问题,在本机上可能没问题,在局网上
也不太稳定
 
那有什么好的解决方案。如果到时不能用,那可就头大了。如果觉得分不够,我还有25分,
有好的解决方案,我全给你。
 
顶部