使用clientsocket接收文件的问题(100分)

  • 主题发起人 主题发起人 kabsiji
  • 开始时间 开始时间
K

kabsiji

Unregistered / Unconfirmed
GUEST, unregistred user!
服务器给我发过来的,格式为 前导码(PR)+命令字(CM)+长度码(LC)+数据(DATA)+校验码(VC)+结束码(EC) ,如:king+1+372+数据(这个是文件的内容)+end;我怎么才能从接收到的内容中,把文件的内容接收到呢!我现在就用clientsocket接收,大家不要说换控件的问题,就是帮我把文件收到就可以了!我的困惑,怎么能把字符串和文件内容区分开呀!以前做的,要么是接收字符串,要么是接受文件,还没有涉及缓冲区内二者同时存在的问题,望高手给个思路,有这方面的代码更好了!
 
在流中移动指针,然后读出来就可以吧,服务器已经给你数据长度了.
 
//Send
var
tempRP: array[0..10] of Byte;
tempCM: array[0..5] of Byte;
tempLC: array[0..10] of Byte;
tempFS: TFileStream;
tempVC: array[0..10] of Byte;
tempEC: array[0..10] of Byte;
tempData: TMemoryStram;
begin
tempData := TMemoryStream.Create;
tempData.Clear; tempData.Position := 0;
tempFS := TFileStream.Create('Your FileName', fmOpenRead);
tempFS.Position := 0;
tempData.WriteBuf(tempRP, SizeOf(tempRP));
tempData.WriteBuf(tempCM, SizeOf(tempCM));
tempData.WriteBuf(tempLC, SizeOf(tempLC));
tempData.CopyFrom(tempFS, tempFS.Size);
tempData.WriteBuf(tempVC, SizeOf(tempVC));
tempData.WriteBuf(tempEC, SizeOf(tempEC));
ClientSocket1.Socket.SendStream(tempData);
end;

//Recive
var
tempBuf: array[0..4095] of Byte;
tempRP: array[0..10] of Byte;
tempCM: array[0..5] of Byte;
tempLC: array[0..10] of Byte;
tempFS: TFileStream;
tempVC: array[0..10] of Byte;
tempEC: array[0..10] of Byte;
tempData: TMemoryStram;
tempRC: Integer;
begin
tempRC := ServerSocket1.Socket.ReceiveBuf(tempBuf, SizeOf(tempBuf));
while tempRC > 0 do
begin
if not Assigned(tempData) then
begin
tempData := TMemoryStream.Create;
tempData.Clear; tempData.Position := 0;
end;
tempData.ReadBuf(tempBuf, SizeOf(tempBuf));
end; //接受完毕;
if tempData.Size <= 0 then Exit;
tempData.Position := 0;
tempData.ReadBuf(tempRP, SizeOf(tempRP)); //...ReadBuf For tempLC;
tempFS := TFileStream.Create('Your SaveFileName', fmCreate or fmOpenWrite);
tempFS.Position := 0;
tempFS.CopyFrom(tempData, tempData.Size - SizeOf(tempRP) - ...SizeOf(EC)));
//Save File tempFS.Position := 0;
end;
 
要原码否?
 
照着楼主说的情况在回答问题的编辑筐中写的。
tempFS.CopyFrom(tempData, tempData.Size - SizeOf(tempRP) - ...SizeOf(EC)));
这是省去的。 应该一看就懂了。是顺序对顺序。
 
TCP 校验码可以不要。数据包不要设计的太复杂。
TCP数据包是没有边界的,粘包拆包是正常。
为数据包建立一个缓冲,在缓里读取相应长度的数据包,就能区分二者同时存在的问题。
也可以走FTP的路,一个命通道,一个数据通道。
 
{
前导码(PR)+命令字(CM)+长度码(LC)+数据(DATA)+校验码(VC)+结束码(EC)

前导码、命令字、长度都是固定长度吧。用ClientSocket的Tag属性作为状态变量,
0表示还没准备好下一步操作
1表示还在接收PR
2表示还在接收CM
3表示还在接收LC
4表示还在接收Data
5表示还在接收VC
6表示还在接收EC

别外用一个全局变量保存还有多少数据(DATA)还没接收
}
var
Form1: TForm1;
LC: Integer;
implementation

{$R *.dfm}

procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
PR, CM, VC, EC: Integer;
Buf: array[0..4095] of Char; //接收文件的缓冲区
rd: Integer;
begin
case (Sender as TClientSocket).Tag of
{首先判断缓冲区里有多少可以接收的数据,注:这里假设PR的长度为4 }
1: if (Socket.ReceiveLength>= 4) then begin
Socket.ReceiveBuf(PR, 4);
if (PR<>0) then begin //这里你可以自己验证PR,
(Sender as TClientSocket).Tag:= 2;
{将状态转为2函数返回,若这个时候Socket缓冲区有>1字节的数据,马上就会
触发TClientSocket的OnRead()事件,所以流程就转到2}
end;
end;
2: if (Socket.ReceiveLength>= 4) then begin //CM和上面的代码差不多
Socket.ReceiveBuf(CM, 4);
if (CM<>0) then begin
(Sender as TClientSocket).Tag:= 3;
end;
end;
3: if (Socket.ReceiveLength>= 4) then begin //LC
Socket.ReceiveBuf(LC, 4);
if (LC<>0) then begin
(Sender as TClientSocket).Tag:= 4;
end;
end;
4: if (Socket.ReceiveLength>0) then begin //DATA
rd:= Socket.ReceiveBuf(Buf, LC);
//将数据写入文件....,这里注意什么时候合建TFileStream的实例
if (LC=0) then begin //接收完文件
Sender as TClientSocket).Tag:= 5; //改变状态
//还可以做一些操作,比如关闭文件
end;
end;
5: if (Socket.ReceiveLength>= 4) then begin //VC
Socket.ReceiveBuf(VC, 4);
if (VC<>0) then begin
(Sender as TClientSocket).Tag:= 6;
end;
end;
6: if (Socket.ReceiveLength>= 4) then begin //EC
Socket.ReceiveBuf(EC, 4);
if (EC<>0) then begin
(Sender as TClientSocket).Tag:= 0;
end;
end;
else
ShowMessage('请将状态置为1!');
end;
end;

满意的话多给点分[:D]
 
我想的方法是以流的形式发送,保证一次数据全部到达。对你的线程拓展有好处,这样避免的了接受难以区分或是不好管理的问题。
 
后退
顶部