关于Socket接收大文件的问题~(100分)

  • 主题发起人 主题发起人 DELPHI.X
  • 开始时间 开始时间
D

DELPHI.X

Unregistered / Unconfirmed
GUEST, unregistred user!
Socket服务器接收大文件的时候,主程序变得很卡,我已经把接收文件的部分放在多线程里了,为什么还会出现主程序卡的情况,大哥们帮我分析一下~~
 
是不是可以考虑一下UDP呢?
 
没有程序代码不好说,
不过主程序卡可能有几个问题:
1.接受虽然是用线程做的,但是线程和主线程经常同步,就会影响主线程。建议减少同步次数,或干脆做到不同步。
2.文件系统写入非常耗费资源,导致主线程被系统阻塞,从而导致卡。建议文件写入按块写入,每次写入多一些,减少IO访问次数。
 
另外,一个猜想:就是线程在接受Socket数据的时候,当数据包被拆成多个的时候,
循环接受数据的结束判断,不要加入TimeOut。
 
线程部分是这个样子的:
线程创建用的是FreeOnTerminate:=False;因为我想手动释放.
动态创建的ServerSocket,线程中Execute函数部分没有执行命令.主要是用ServerSocket的onclientread做监听,并接收数据,Buffer设置的1024.这样的反复循环做接收并写文件,可能是引起CPU占用特别厉害的主要原因.
我该怎么做呢`
 
1.唉,又是一个线程问题,不要把多线程作为编写程序的超级武器;
2.既然用ServerSocket、OnClientRead, 还要线程做什么, 既没有必要, 还可能会误事;
3.buffer设置太小, 传输文件, 用TCP的话,每个数据块大小可以设定为16K~64K, 局域网可以偏大一些;
4.程序应该自己判断一个文件传输的开始和结束, 没有必要用线程解决问题;
 
前几天刚碰到过的问题,卡的原因是因为磁盘的频繁写入造成的。
解决方式就是 将接收到的数据写到一个队列
由另外一个线程判断队列内的数据超过多少或者传送完毕再写一次磁盘。
我这样写出来以后效果很不错 支持并发多任务,在局域网速度能到10M左右/s
无论同时多少个并发传输CUP使用率保持在20以下。
贴小段代码以做参考:)
=============
try
lUserbuff.ConnToFile(LOpter.FileName);
LRecBuff := GetMemory(1024 * 8);
LRecSize := Lbuff.EndPos - Lbuff.StartPos;
{总共要读取的大小}
LCurrRec := 0;
{已经读取的大小}
LTrueSize := Min(1024 * 8, LRecSize - LCurrRec);
while (LCurrRec < LRecSize) and (ClientThread.Socket.Connected)do
begin
LTrueSize := ClientThread.Socket.ReceiveBuf(LRecBuff^, LTrueSize);
lUserbuff.AddToQueue(LRecBuff, LTrueSize);
inc(LCurrRec, LTrueSize);
LTrueSize := Min(1024 * 8, LRecSize - LCurrRec);
{注意接收太快的时候必须限制速度否则写入磁盘的速度是没有接收速度快的内存很快就用光光了}
while lUserbuff.CurrBuffSize > CMissonRecBuffdo
sleep(10);
end;
// while
Shower.AddShow('LCurrRec : %d LRecSize:%d ClientThread.Socket.Connected:%s', [LCurrRec, LRecSize, BoolToStr(ClientThread.Socket.Connected)]);
if LCurrRec = LRecSize then
LOpter.FinishAnThread(Lbuff);
ClientThread.fpSessionData := nil;
{传输完成后 只释放连接 不释放对象因为也许还有数据未写入文件}
except
on e: Exceptiondo
Shower.AddShow('接收数据时异常原因 :%s 将结束此用户上传的所有相关线程', [e.Message]);
end;
 
多人接受答案了。
 
后退
顶部