怎样处理Socket传送大于4096的数据问题. ( 积分: 40 )

  • 主题发起人 主题发起人 hjp0214
  • 开始时间 开始时间
H

hjp0214

Unregistered / Unconfirmed
GUEST, unregistred user!
怎样处理Socket传送大于4096的数据问题.
现在客户端是这样处理的:
procedure TfrmClient.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
iPackageSize: Integer;
TempBuf: ByteArray;
begin
while socket.ReceiveLength>0 do
begin
iPackageSize := socket.ReceiveLength;
FillChar(TempBuf,length(TempBuf),0);
Socket.ReceiveBuf(TempBuf,iPackageSize);

TranMemBuf(TempBuf,iPackageSize);//解析报文过程
end;
end;

socket.ReceiveLength>8192
服务端是多线程的非阻塞发送,不断向客户端发送数据.
感觉到socket.ReceiveLength=0后才能处理报文解析.这样很容易缓存区溢出.
不知道有什么好办法处理???分数不多,但急需解决啊.
 
怎样处理Socket传送大于4096的数据问题.
现在客户端是这样处理的:
procedure TfrmClient.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
iPackageSize: Integer;
TempBuf: ByteArray;
begin
while socket.ReceiveLength>0 do
begin
iPackageSize := socket.ReceiveLength;
FillChar(TempBuf,length(TempBuf),0);
Socket.ReceiveBuf(TempBuf,iPackageSize);

TranMemBuf(TempBuf,iPackageSize);//解析报文过程
end;
end;

socket.ReceiveLength>8192
服务端是多线程的非阻塞发送,不断向客户端发送数据.
感觉到socket.ReceiveLength=0后才能处理报文解析.这样很容易缓存区溢出.
不知道有什么好办法处理???分数不多,但急需解决啊.
 
加个中间处理:
比如发包时固定包长(接收就不定长了);
另开一个动态数组,收到长度合计达到要求(最后一个包后),
再统一解包;
另一种思路是解包用另处的线程;
下面是我通讯的部分:
const
LenPack=115;//包长
type
TOneFrame=array[0..LenPack-1] of byte;//单个包
TMultiFrame=array[0..LenPack*15-1] of byte;//多包暂存
TPackData=record
packnum:Byte;
AllPack:array of TOneFrame;
end;
***********
if (not QXHasSaved)and(TmpFrame[12]=1)and(TmpFrame[4]=$72)
and(CmdType in [57,65])and(TmpFrame[5]>7)and(TmpFrame[11]>1) then
begin
QXHasSaved:=True;
packCnt:=TmpFrame[11];
SetLength(QXdata.AllPack,packCnt);
QXSavedLen:=0;
QXdata.packnum:=packCnt;
QXline:=ReceieveLine;
label1.Caption:='Õý½ÓÊÕºÍÔÝ´æÊý¾Ý...¹²'+inttoStr(QXdata.packnum)+'¸ö°ü';
label1.Repaint;
end;
if (QXHasSaved)and(ReceieveLine<>QXline)and(TmpFrame[5]<>6) then
begin
if DispError then
Showmessage('&amp;Ccedil;ú&amp;Iuml;&amp;szlig;&amp;Ecirc;&amp;yacute;&amp;frac34;&amp;Yacute;&amp;Oacute;&amp;Aring;&amp;Iuml;&amp;Egrave;&amp;pound;&amp;not;&amp;Atilde;&amp;raquo;&amp;sup3;&amp;shy;&amp;Iacute;ê&amp;Ccedil;°&amp;sup2;&amp;raquo;&amp;frac12;&amp;Oacute;&amp;Ecirc;&amp;Otilde;&amp;AElig;&amp;auml;&amp;Euml;&amp;ucirc;&amp;Iuml;&amp;szlig;&amp;micro;&amp;Auml;&amp;ETH;&amp;Aring;&amp;ordm;&amp;Aring;');
exit;
end
else if (QXHasSaved)and(ReceieveLine=QXline)and(CmdType in [57,65]) then
begin
if QXSavedLen+lentmp>packCnt*LenPack then
lentmp:=packCnt*LenPack-QXSavedLen;
copymemory(@QXdata.AllPack[QXSavedLen div LenPack,QXSavedLen mod LenPack],@TmpFrame[0],lentmp);
QXSavedLen:=QXSavedLen+lentmp;
QXHasSaved:=QXSavedLen<packCnt*115;
if not QXHasSaved then
begin
for j:=0 to QXdata.packnum-1 do
begin
copymemory(@TmpFrame[0],@QXdata.AllPack[j,0],LenPack);
unpackcmd;//解包
end;
QXdata.packnum:=0;
SetLength(QXdata.AllPack,0);
end;
exit;
end;
 
另一种思路是解包用另处的线程;提供能否详细的思路呢,或者提供一些代码参考
 
只是想法,我也没用过;
就是解包用专用的线程,但数据可否公用,或当参数传是否太大。。。

我用的是一对多通讯,单线程也没出什么问题;
按你所说的只是在包前发送文件总字节就可,
接收到的东东填足长度就行;

不过多包发送完(一个文件?)后,要稍等一会才发下一个文件;
//接收过程供参考:
itemcount:=ServerSocket1.Socket.ActiveConnections;
if LinkCount<>itemcount then
begin
if DispError then
Showmessage('LinkCount='+IntToStr(LinkCount)+',ActiveConnections='+IntToStr(itemcount));
LinkCount:=itemcount;
end;
for i:=0 to linkcount-1 do//多线连接,供你参考
begin
lentmp:=ServerSocket1.Socket.Connections.ReceiveLength;
if lentmp>0 then break;
end;
ReceieveLine:=i;
if lentmp>LenPack*15 then
begin
if DispError then
Showmessage('&amp;frac12;&amp;Oacute;&amp;Ecirc;&amp;Otilde;&amp;Ecirc;&amp;yacute;&amp;frac34;&amp;Yacute;&amp;sup3;&amp;not;&amp;sup3;¤&amp;pound;&amp;ordm;'+IntToStr(lentmp));
exit;
end;
i:=ServerSocket1.Socket.Connections[ReceieveLine].ReceiveBuf(TmpFrame,lentmp);
//也有人一次不将lentmp(全部长度)读完,后面收到的会接到此BUFFER后面吗?我没试过,不提倡,
if i<>lentmp then//这个判断有用吧,通常会正确
begin
if DispError then
Showmessage('&amp;frac12;&amp;Oacute;&amp;Ecirc;&amp;Otilde;&amp;Ecirc;&amp;yacute;&amp;frac34;&amp;Yacute;&amp;sup3;¤&amp;para;&amp;Egrave;&amp;Ograve;ì&amp;sup3;&amp;pound;');
exit;
end;
 
我需要客户端接收,采用线程解析报文的方式啊。客户端接收服务端的数据,可能很大,
我想边解析报文,边空出部分空间,继续接收数据。
 
还是要有协议:
比如前面带报文长度;收完后回答一下,才发下一个报文;

否则,因为SOCKET的接收与串口不一样,
分不清是分几个包发的;连续发报文接收总会出错;

如果内容不重要,改用UDP方式?
 
可惜,服务端是另外一家公司开发的,也是采用非阻塞的方式发送,在测试过程中,服务端可能一下发送8196个字节,而客户端接收字节数组只设为array [0..1023] of byte.
所以很容易溢出的。
 
总有结束字符或长度吧,要不怎会知道收完了呢?
客户端解包可array [0..1023] of byte;
接收或暂存你可改为array [0..1024*8-1] of byte;

然后再处理。。。。
效果应比收一个解一个好
 
服务端是不断发送报文的,可能是一个报文也可能是一个报文多一些,开始符“<”,结束符“>”,比如:接收到这样的报文.&quot;<346346346346346436><34634634&quot;,下一个可能是&quot;sdgdsgdgdsfgddfgdf><46456456456456ddfgdfgfdg>&quot;两个包合起来就是三个报文了,也就是解析这样三个报文了。
 
设计一个接收数组如:
const
LenPack=1024*8;
type
TOneFrame=array [0..LenPack-1] of byte;
TPackData=record
packnum:Byte;
AllPack:array of TOneFrame;
end;
从接收中去读,如果'<',PACKnum+1;
存到一个新的ALLPACK(记得Setlength(...+1)!);

然后
var
TmpFrame:TOneFrame;
begin
for j:=0 to QXdata.packnum-1 do
begin
copymemory(@TmpFrame[0],@QXdata.AllPack[j,0],LenPack);//这个不对,我的是定长包!
unpackcmd;//解包
end;
前面告诉你参考了吗?你自己要试试啊;
TPackData同时写和读,处理是否跟得上,难说,你想法,不行就多线程;
你的包不定长,不一定有8192有点浪费空间不要紧吧;反正有结束字符后面不处理就行了
(至少比你收一个半或半个开始解要好)

//我处理的是定长包,我看你还是收到的就直接写文件吧,一直向内加;
到于到多大时才解,存另一个文件,你自己分配吧;
总之一直不停的发和接收,总是来不及处理,想你这样的情况;
//最好是发个文件稍等一下啊!
你这样的通讯协议(起止字符)只适应于单字节接收处理(如单片机的串口),
不适合于SOCKET通讯;
还是改协议吧,如收到一个文件,答复后再收下一个;


到此为止吧。。。
 
非常谢谢jlyin一直跟踪回答.
 
在clientsocket的read事件中,你是怎么处理的.难道一定要等到接受完所有的包,然后才去解析报文吗
 
没有:我有两种包:
一种是单包,另一种是多包(称为曲线数据);
(这样说吧,作抄表:曲线数据指5分钟存一次,数据量大可作曲线);
要据命令类型来区分,接收也是这样;

如果单包直接解包,ONEFRAME;
如果多包我有包总数、包序号字节(定长包),
先转存(可以算出长度=包总数*包长);最后按包解;

协议改自串口通讯,串口通讯不存在这个问题;
因有发下个包/重发当前包命令,用SOCKET或短信就没必要这样来回答了
******************************************************
冲突:服务器跟多个GPRS终端通讯;
一。在收多包过程中,如果插入有其他包不处理;
除非是心跳信号,自动答:
二。接收,尽管发送方是一次发多个包(实际上是了一个包接发下个包);
接收方通常一次收到5个/10个不确定的包,我只管第一个包的命令,总包数,后面就不管了,收够为止)
 
接受答案了.
 
后退
顶部