TClientSocket的数据接收问题(100分)

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

kofbee

Unregistered / Unconfirmed
GUEST, unregistred user!
在使用TServerSocket and TClientSocket进行数据通讯时,如果TClientSocket接收的数据
非常巨大,比如几百K,甚至几M,应该在TClientSocket端如何接收呢,我试过用一个1M的
BYTE字节的缓冲去接收,但是只要TClientSocket一接收到数据,程序立即退出,如果用100K的缓冲去接收,一点问题没有,但是会造成数据丢失。我是在TClinetSocket的OnRead事件中接收的。
 
分配空间,把缓冲写到里面去
 
我分配了,其实缓冲就是数组而已。也就是说接收数组太大,程序可能会自动退出。
 
可以分段下载
 
不能这样去收这么巨大的数据。如果客户端缓存很大,服务器端就会一直往里送数据,其他的工作就停顿了,
客户端就会失去这个会话期,失去会话期时,服务器端还来不及通知客户端(它在忙着给你的客户端填数据哩),
实际上连接已经完蛋,客户端没有接到通知,所以仍然拼命希望从这个连接中取到数据,于是就出现非法指针操
作,程序立马死去。
 
不要一次传送完毕嘛!分次传送。
 
昨天 张无忌 兄还给我一个提示,说,如果减小客户端缓存,还会提高响应速度。当时我愣了一下,其实就是这个道理。
 
好象不对,TClinetSocket本身有一个很大的缓冲,如果OnRead事件触发时TClientSocket正在干别的事情,他就会使用本身的缓冲,直到TClintSocket去Read,其实,我讲的死掉的是
TClientSOcket端,TServerSocket一点事都没有。我们定的包一般300k左右。由于数据调用需要,有时TServerSocket会拼命向TClinetSocket发包,有可能一次发N多个包,如果来不及处理,这些包会被保存在TClinetSocket本身的缓冲中,等待处理。如果接收数组太小,会有数据丢失,如果太大,程序退出。
 
你在同一台电脑上,同时打开两个 Delphi ,一个启动服务器,另一个启动客户端,跟踪到
连接里去看看。
 
你的程序设计有问题,一般的话我最多每次用4K的缓冲去读数据,不可能有100K的
 
用indy吧。TServerSocket and TClientSocket有很多问题的。
 
TServerSocket and TClientSocket没有什么什么问题,
要出问题也是写代码的程序员控制的不好,
 
我在TClientSocket端接收数据,用于数据采集,一条小时数据带时间,数据,校验位有30个字节,由于采集需要,一次可能会采集巨大的数据,在TServerClient端经过打包,每个包300个字节左右向我传递,然后我负责解码工作和数据入库,我发现由于解码比较复杂,所以程序在解码过程中TClientSocket也会响应,将数据纳入自己的缓冲,有时会非常巨大,造成数据丢失。
 

其实是楼主没有搞明白异步通信是怎么一回事和 Onread 事件的触发时机,例如你发送啦 100KB 的数据,此时,每次数据包抵客户端并在系统缓存中累计储存到一定大小时都会触发一次FD_READ 网络事件,在TClientSocket中则触发 OnRead 事件,也就是说如果客户端每次累计接受到 5KB 数据时就触发一次 OnRead 事件,那么就要触发 20 次 OnRead 事件,而且由于网络带宽和系统处理延迟的缘故,所以有可能每次触发 ONRead 事件的间隔时间和实际接受的数据的大小也是不一样的。
相关的代码可以看看以前阻塞和与非阻塞的讨论,在 TCP 协议下要想知道是否为完整接受到请求数据包,可以通过两种方式来处理,第一种是通过自定义数据流边界来确定以及接受完服务器端发送来的数据,第二种是服务器发送完毕后,调用断开命令,这样客户端也就知道数据已经接受完毕。
另外至于缓存数组那种定义方式也是有问题的,一般还是使用指针的方式比较好。
例如:
定义
FReceiveBuf: PChar; //接收数据缓存指针
FReceiveSize: integer; //接收数据缓存的大小
FReceiveCount: integer; //接收到的数据字节计数(总共接收多少数据)
初始化:
FReceiveCount := 0;
FReceiveSize := 1024 * 16; // 16KB 的字节
if not Assigned(FReceiveBuf) then
GetMem(FReceiveBuf, FReceiveSize);
释放:
if Assigned(FReceiveBuf) then
begin
FreeMem(FReceiveBuf, FReceiveSize);
FReceiveBuf := nil;
end;
在 OnRead 事件:
NewLen := FReceiveCount + FClientSocket.ReceiveLength;
if NewLen >= FReceiveSize then
begin
if NewLen < (FReceiveSize + (1024 * 16)) then //按照 16 KB 字节递增分配字节
NewLen := FReceiveSize + (1024 * 16);
ReallocMem(FReceiveBuf, NewLen);
FReceiveSize := NewLen;
end;
Len := FClientSocket.ReceiveBuf(FReceiveBuf[FReceiveCount],
FReceiveSize - FReceiveCount - 1);
...相关判断数据边界或者其他处理方式。

 
谢谢大家,散分了,问题解决,这个问题比较古怪,不是问题的问题。和张无忌兄说的比较接近。再次谢谢大家。
 
后退
顶部