用TClientSocket 和TServerSocket 传输大量数据丢包现象

jy2768196 2008-01-29 12:03:45
用TClientSocket 和TServerSocket 传输大量数据丢包现象

我用循环的方式给外网的服务端发送数据(共5000条),但服务器那边接收才700条左右,丢失包现象严重!请问大家应该怎么办!知道的帮我下实在感谢
...全文
899 54 打赏 收藏 转发到动态 举报
写回复
用AI写文章
54 条回复
切换为时间正序
请发表友善的回复…
发表回复
UltraBejing 2008-05-01
  • 打赏
  • 举报
回复
接分先!
knowledge_Is_Life 2008-04-30
  • 打赏
  • 举报
回复
接分先!
僵哥 2008-02-11
  • 打赏
  • 举报
回复
to 50楼,TCP不会丢包,攻击器使用的是UDP,UDP丢包才是正常的。
hujiacheng21 2008-02-07
  • 打赏
  • 举报
回复
网络本来就有延时丢包现象。。。你没写好处理。!
hujiacheng21 2008-02-07
  • 打赏
  • 举报
回复
一次性发5000不丢包才怪??? 有时候 我下了攻击器 直接发5000个包都丢了一大堆。。。
imho888 2008-02-02
  • 打赏
  • 举报
回复
首先一点,服务器不停循环发送,客户端来不及接收或来不及处理那肯定会有丢包现象
你一条数据有多少字节?如果一条数据字节很少,那可以多条数据一起发,1K字节发送一次是没问题的,至于怎么样多条一起发可以设置一个数据结构,接收点和发送点都要一样。
还有就是最好加入客户端接收完成后返回给服务器相关信息。这样服务器可以通过时间控制发送,比如:超过10秒还没接收到客户端返回的信息可以再次发送。如果接收到信息就可以发送下一条了,至少不会出现丢数据的情况。
原则是有效的利用网络。
jy2768196 2008-02-01
  • 打赏
  • 举报
回复
procedure MyThread.SyncProc;
begin
form1.RichEdit1.Lines.Add('['+strTonameLogMsg+']对['+strPhonemessageLogMsg+']+ MessageID: '+strMessageLogMsg); //+' MessageID: '+CWhisper.messageID
sum:=sum+1;
form1.Edit1.Text:=inttostr(sum);
end;

procedure MyThread.Execute; //创建读取数据库线程
var
iSent,iNeedSend,I:Integer;
SWhisperBulletin:TSWhisperBulletin1;
p:PChar;
///
SQL:String;
strTonameTemp,strPhonemessageTemp,strMessageIDTemp:String;
IsNeedSleep :Boolean;
begin
CoInitializeEx(Nil,COINIT_MULTITHREADED); //初始化ADO数据库
AdoConnection := TADOConnection.Create(nil);
AdoQuery := TAdoQuery.Create(nil);
try
AdoConnection.ConnectionString := 'Provider=SQLOLEDB.1;'+
'Password='+FDBPass+';'+
'Persist Security Info=True;'+
'User ID='+FDBLogin+';'+
'Initial Catalog='+FDBName+';'+
'Data Source='+FDBServer;
AdoConnection.Connected:=true;
AdoQuery.Connection := AdoConnection;
while Not Terminated do //判断线程是否中断
begin
IsNeedSleep := false;
Lock;
try
if (strList1.Count = 0) and (strList2.Count=0) and (strList3.Count=0) then
begin
IsNeedSleep := True;
end
else
begin
strTonameTemp:=strList1.Strings[0];
strList1.Delete(0);
strPhonemessageTemp:=strList2.Strings[0];
strList2.Delete(0);
strMessageIDTemp:=strList3.Strings[0];
strList3.Delete(0);
end;
finally
Unlock;
end;
if IsNeedSleep then
begin
Sleep(15);
continue;
end;
AdoQuery.SQL.Clear;
AdoQuery.SQL.add('begin tran');
SQL:='insert into test(phone,message,messageID) values('''+strTonameTemp+''','''+strPhonemessageTemp+''','''+strMessageIDTemp+''')';
('''+strTonameTemp+''','''+strPhonemessageTemp+''','''+strMessageIDTemp+''')');

AdoConnection.Execute(SQL);

strTonameLogMsg:=strTonameTemp;
strPhonemessageLogMsg:=strPhonemessageTemp;
strMessageLogMsg:=strMessageIDTemp;
Synchronize(SyncProc);

{-服务端返回给客户端消息-} //为什么在这里ss.Socket.ActiveConnections-1这里就报错呢~要是给客户端返回信息应该写在哪里?
fillchar(SWhisperBulletin,sizeof(SWhisperBulletin),0);
SWhisperBulletin.msghead.MsgType:=SSBulletin;
strpcopy(SWhisperBulletin.SWBulletin.ReturnMessageID,CWhisper.messageID);
// ss.Socket.Lock;
for i:=0 to ss.Socket.ActiveConnections-1 do
begin
iNeedSend := sizeof(SWhisperBulletin);
p:=@SWhisperBulletin;
while iNeedSend>0 do
begin
iSent := ss.Socket.Connections[i].SendBuf(P^,iNeedSend);
if iSent<=0 then break;
Dec(iNeedSend,iSent);
Inc(P,iSent);
end;
end;
// ss.Socket.Unlock;
{-服务端返回给客户端消息-}

end;
ss.Socket.Unlock;



finally
AdoQuery.Free;
AdoConnection.Free;
CoUninitialize;
end;



先感谢unsigned 哥帮我解决数据粘包的问题! 但这里应该怎么处理呢希望大家指点
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
procedure TDataModule3.csRead(Sender: TObject; Socket: TCustomWinSocket);
var
msgHead:TMsgHead;
mstream:Tmemorystream;
SWhisperBulletin1:TSWhisperBulletin1;
iCount,iNeedCount:Integer;
P:PChar;
begin
while true do
begin
iNeedCount := sizeof(TSWhisperBulletin1);
Socket.Lock;
try
if Socket.ReceiveLength<iNeedCount then Exit;

P := @msgHead;
while iNeedCount > 0 do
begin
iCount := socket.ReceiveBuf(P^, iNeedCount );
if iCount <= 0 then Exit;
Dec(iNeedCount,iCount);
Inc(P,iCount);
end;

case SWhisperBulletin1.msghead.MsgType of
100: MyReadMsgbulletinThread.Create(cs,SWhisperBulletin1);
end;
finally
Socket.Unlock;
end;
end;

unsigned哥我以上代码已经可以执行,主要是 iNeedCount := sizeof(TSWhisperBulletin1);if Socket.ReceiveLength<iNeedCount then Exit;
这俩句.因为我服务端发过来的数据包不只TSWhisperBulletin1这一种包,请问要是多种应该怎么处理??我每种接收对转专门一个SOCKET控件可以吗?
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
楼上可以给出解决相关代码吗?
zhangxuyu1118 2008-01-30
  • 打赏
  • 举报
回复
很正常的粘包现象。我的做法一般是:
假设包中含有多余的数据,那么就把这部分数据放一边(不能扔掉),下次来的包头部与这部分必然能拼成1个有效的包。
以上经验经过多个项目的证实,未有出错。
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
多谢unsigned 哥
ERR0RC0DE 2008-01-30
  • 打赏
  • 举报
回复
Buffer.Memory是Pointer类型,Pointer类型是可以转换任何指针和对象,所以才有各种简化操作,不直接写强制转换语句,我写的代码,能简单的则简单,虽然可能不好看一些。但减少了一些代码量。
再强调:减少数据的COPY:

都有数据了,还创建TMemoryStream,再Write,再SendStream,晕
procedure TDataModule3.WhisperMsg
...
begin
...
RetVal := cs.Socket.SendBuf(MsgcWhisper,sizeof(TMsgCWhisper1));
if RetVal = SOCKET_ERROR then
begin
// TClientSocket发送返回,则不异常,则说明返回10035或用户处理了OnError的errorCode,
// 10035需要再次发送,不是则一般是断开,再处理
end;
end;

2: 每调用SSClientRead就创建一个mStream???
内存操作是费时的,对象能创建一次就别多次,用我那种方法,将对象放到Socket.Data中,保存起来,下次再取出使用。

procedure Tcommonfrm.SSClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
msghead:TMsgHead;
mstream:Tmemorystream;
begin
mstream:=Tmemorystream.Create;

3: 如上unsigned所说,在LoginProc尽量使用指针类型,减少一次数据的COPY,减少一次就是一次,时间一长,就是N多。
ERR0RC0DE 2008-01-30
  • 打赏
  • 举报
回复
楼上都有人说出这个粘包现象了,我那代码就是处理这个问题的,你怎么就不明了?

做TCP程序,粘包就是一简单现象,就是如上所说,将多余的数据保存下来,形成缓冲,你那我那代码,就是先数据全部收到Buffer中,然后进行分包处理。

你那里协议都已经规定每个包是TMsgHead打头,收下来的数据都放在Buffer: TMemoryStream中,则Buffer.Memory的头几个字节肯定就是TMsgHead格式,
所以我才有: hdr := Buffer.Memory;的举动。

另:unsined所说的明显错误应该不是的。我未使用常量来保存Buffer,因为Buffer是保存在Socket.Data,Socket.Data它一个socket实例用来保存Context的变量,由用户控制的。所以OnRead一开始就先取出,看看是否为空,空则create。(少了步:Disconnect则Free)

一般写网关程序,能减少数据的COPY就减少,所以,常用指针表示,而Delphi最常见的就是Pointer来指向任何指针类型。。。

我上面的也是一个简单的逻辑过程,以前写的亦是如此。

if RecvData<=0 then Exit;

while True do
if Buffer.Size > 包的长度 then
[
1: 取包
2: 处理包
3: Buffer.删除包
]
就这么几个动作。
僵哥 2008-01-30
  • 打赏
  • 举报
回复
qq:83039548
僵哥 2008-01-30
  • 打赏
  • 举报
回复
我不认为这种写法会导致丢包,当然是否跟控件相关系,得看你现在使用的控件是哪个版本(即IDE的版本,早期版本确实存在一些问题),另外更重要的是,在这个处理过程当中,你是否有使用过比如Application.ProcessMessage之类的,或者有没有别的线程会访问到相关的Socket资源;是否在程序当中,有存在内存泄露;另外就是防毒软件,呵呵,比如卡巴之类的,我们一开始跟同事还只是开玩笑,一有问题就说让把卡巴关了,后来证明,很多网络问题,只要关了防毒软件就正常了...(这一条仅作为参考,这个并不是要损防毒软件,只是有很大部分防毒软件确实想做好,什么都想管,但是就是没做得个好^_^).
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
俩天了到现在也不确定应该怎么解决最好,unsigned可以申请要您的QQ吗
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
现在是为什么会产生丢包???跟控件有关系???这么写可以解决问题吗?
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
case hdr.MsgType of
3: LoginProc(Buffer.Memory);
end;

这里调用LoginProc和下面的参数也是不一样的啊......
僵哥 2008-01-30
  • 打赏
  • 举报
回复
他的意思只是让你避免复制,使用
procedure Tcommonfrm.LoginProc(Socket: TCustomWinSocket;var MsgCWhisper: TMsgCWhisper1);
...
jy2768196 2008-01-30
  • 打赏
  • 举报
回复
type
PMsgCWhisper1 = ^TMsgCWhisper1;


procedure Tcommonfrm.LoginProc(MsgCWhisper: PMsgCWhisper1);
begin
...
end;

这个方法通不过啊 这是什么意思?
加载更多回复(34)

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧