wsock API编写文件传输遇到的问题(大家来看看)(100分)

  • 主题发起人 主题发起人 阿伟~
  • 开始时间 开始时间

阿伟~

Unregistered / Unconfirmed
GUEST, unregistred user!
写了个简单的例子,没用多线程处理,但始终存在2个问题:
发送端,发送代码:
procedure Tf_main.TransFile(filename: string);
var
Ftrans: file of Byte;
Flen: Integer;
BlockNum, RemainLen: Integer;
BlockBuf: array[0..BlockLen - 1] of Byte;
i: Integer;
SendLen: Integer;
begin
AssignFile(Ftrans, filename);
Reset(Ftrans);
Flen := FileSize(Ftrans);
BlockNum := Flen div BlockLen;
ProgressBar.Max := 1 + BlockNum;
RemainLen := Flen mod BlockLen;
StopTrans := False;
InTrans := True;
SendLen := 1;
for i := 0 to BlockNum - 1 do
begin
if (StopTrans) or (SendLen <= 0) then Break;
BlockRead(Ftrans, BlockBuf[0], BlockLen);
SendLen := send(Client, BlockBuf, BlockLen, 0);//问题1
ProgressBar.Position := i;
Application.ProcessMessages;
end;
if StopTrans then
begin
CloseFile(Ftrans);
InTrans := False;
StatusBar.SimpleText := '';
MessageBox(Handle, '停止传输!', '提示', MB_OK);
ProgressBar.Position := 0;
Exit;
end;
if (SendLen <= 0) then
begin
CloseFile(Ftrans);
InTrans := False;
StatusBar.SimpleText := '';
MessageBox(Handle, '传输异常终止!', '提示', MB_OK);
ProgressBar.Position := 0;
Exit;
end;
if RemainLen > 0 then //剩下不到4096长度的数据发送
begin
BlockRead(Ftrans, BlockBuf[0], RemainLen);
SendLen := send(Client, BlockBuf, RemainLen, 0);
if (SendLen <= 0) then
begin
CloseFile(Ftrans);
InTrans := False;
StatusBar.SimpleText := '';
MessageBox(Handle, '传输异常终止!', '提示', MB_OK);
ProgressBar.Position := 0;
Exit;
end;
end;
ProgressBar.Position := ProgressBar.Max;
CloseFile(Ftrans);
InTrans := False;
StatusBar.SimpleText := '';
MessageBox(Handle, '传输完成!', '提示', MB_OK);
ProgressBar.Position := 0;
end;
接收端代码:
procedure Tf_main.RecvFile(filename: string);
var
Ftrans: file of Byte;
Recelen, i: Integer;
BlockBuf: array[0..4096 * 10] of Byte;
RecvSocket: TSocket;
ra: SOCKADDR_IN;
ra_len: Integer;
Rece_Max: Integer;
begin
Rece_Max := 0;
Ra_len := sizeof(Ra);
//等待连接的客户端Socket
RecvSocket := accept(Server, @ra, @ra_len);
//创建一个保存的文件
AssignFile(Ftrans, filename);
ReWrite(Ftrans);
//设置状态变量
StopTrans := False;
InTrans := True;
//接收数据
Recelen := recv(RecvSocket, BlockBuf, BlockLen, 0);
while (Recelen > 0) and (not StopTrans) and (Rece_Max <> 15195) do
begin
i := 15195 - Rece_Max;
if i >= BlockLen then
i := BlockLen;
BlockWrite(Ftrans, BlockBuf[0], Recelen);
Application.ProcessMessages;
Recelen := recv(RecvSocket, BlockBuf, i, 0);//问题2
Rece_Max := Rece_Max + Recelen;
//当停止接收时,停止传输
if StopTrans then
begin
CloseFile(Ftrans);
closesocket(RecvSocket);
InTrans := False;
MessageBox(Handle, '停止传输!', '提示', MB_OK);
Exit;
end;
end;
//关闭文件,接收的Socket
CloseFile(Ftrans);
closesocket(RecvSocket);
InTrans := False;
if (Recelen = SOCKET_ERROR) then
MessageBox(Handle, '传输异常终止!', '提示', MB_OK)
else
MessageBox(Handle, '客户端已经关闭连接!文件可能已经传送完毕!', '提示', MB_OK);
end;
发送端有问题1,接收端有问题2
问题1:是当我在发送大容量的文件时,在发送端SEND处(也就是问题1的地方)按事先划好的文件块发到一定大小的时候会停在那,无法动弹,也没任何返回值包括错误的,而且我是规定文件块每次发送的大小为4K,但我发送较小的文件时却没这样的情况,我分别试发了16K和50K的文件,16K的没问题,50K的有问题,为什么会这样呢?
问题2:在接收文件时,我按4K一次的容量接收,在剩余接受数据大小小于4K时,用剩余实际大小接受,但为什么总在接受文件最后一块的时候,在RECV处(也就是问题2)处挂的那里,什么返回值也没有,就跟程序死了一样,但当我强行终止程序时,发现接受的文件却是对的而且可以打开,这又是为什么呢?
请各位大佬帮忙看看
 
没人解答吗,各位富翁人捏?
 
难道就没有人能帮帮我分析下问题么
 
Send和Recv的调用分为同步阻塞模式和异步模式两种
 
我知道我现在写的是阻塞试的发送接受模式,如果不涉及到多线呈的处理,能否有办法改改上面的代码?

望给予指点,我是个新手
 
在阻塞模式下,最好使用线程来工作,否则连进程的主循环都会被阻塞,最终的效果就是界面被freeze,跟死机一样。

在Windows下你可以把接收和发送写到线程里,在linux下把收发部分单独fork子进程处理。
 
意思就是如果在这种阻塞的模式下,我把发送和接收分成2个线程来完成是吗?
我现在也在看多线程的资料,但我想能否把上面的代码改成非阻塞模式的呢?正如您上面所说:SOCKET通讯分阻塞和非阻塞2种方式(我用的系统是WINDOWS2000)
 
我在接收端创建完SOCKET后加入了如下代码:
if (ioctlsocket(Server, FIONBIO, vl)) = 0 then
ShowMessage('非阻塞模式转换成功')
else
ShowMessage('非阻塞模式转换失败');
则接收端以前的那个问题就不存在了,但又有个新问题出现,采用了非阻塞模式接收后,RECV完文件的最后一块时,RECV会返回一个SOCKET_ERROR的值,但并未妨碍实际的接收工作,我想知道为什么?由始到终我都没用到多线程的处理方法
 
不过发送端的问题并未解决,也就是问题1
 
接受答案了.
 
我曾尝试做过winsock api方式下的SOCKET收发,一直没有成功,你现在是否调通,如果通过给我发一份好吗?gz_wz@126.com,不胜感谢.
 
后退
顶部