讨论:局域网,小连接数(10个左右),长连接,大数据量用什么方式比较好呀 ( 积分: 100 )

  • 主题发起人 主题发起人 dearwolf
  • 开始时间 开始时间
D

dearwolf

Unregistered / Unconfirmed
GUEST, unregistred user!
我是第一次做网络通讯这块,没什么经验,也潜在坛子里看了一段时间老贴,可是还是有些地方不太清楚,希望大家都来讨论一下
项目主要应用于局域网,连接数在十个左右,可是要求长连接,并且数据量也很大,数据包不定长,SERVERSOCKET和CLIENTSOCKET,SENDSTREAM发送数据,服务器和客户端都是异步。
现在的问题是运行一段时间后(一到两个小时),就会出现问题,或者是服务接收不到数据,或者是客户端接收不到数据。不知道是怎么回事?
另:用SendStream发送数据
Socket.SendStream(SDataStream);后,SDataStream是不是不需要再释放呀,我写的释放程序报错,跟了一下DELPHI的源码,好像已经释放了,谁能给解释一下。

晕 怎么给不了300分了呀。

声明:为此问题准备了300分
 
10个连接最好用INDY来做,它在做少数量的连接时很好用,收发数据也很方便。尽量不要用ServerSocket和ClientSock,它们真的不是很稳定,而且包装的太少。
 
改用INDY就没事了吗?
我看以前的贴子,好多人用ServerSocket和ClientSocket呀,都说没问题呀
我现在的问题是运行一段时间后总会有一个接收不到数据的(服务器或客户端),但是可以发送数据,比如是a工作站出问题,一种情况是它收不到服务器发送的数据,但是服务器可以收到它发送的数据。另一种情况是它能收到服务器发送的数据,可是服务器收不到它发送的数据。真是莫明其妙。弄的我头大了好几天了,希望有经验的高手给帮帮忙。

我怀疑是不是跟系统的接收缓冲区有关系。或者是我没需要清系统的缓冲区?还是跟我用SendStream有关系(看以前的贴子好像没有几个人用SendStream)
 
改为SendBuf已经运行将近5个小时,没有出问题
难道问题就这样解决了吗?
谁能给解决一下?
 
晕呀 问题没有解决 昨天晚上又出问题了 3号工作站在20:40分停止工作 服务器接收不到它上传的数据,可是它能收到服务器发送给它的指令。
有谁遇到过这种情况呀,帮帮忙好吗 谢谢了
 
ServerSocket和ClientSocket我是不会去用它,用它还不如直接调API来的直接一些,如果你对异步方式不是很熟悉,我还是建议你用INDY的同步模式,简单明了。
如果可能,请你把关键运行代码发到我邮箱,我抽空帮你看看,虽然我怎么样,但也写了几年的普通网络程序。
我的邮箱:dangergy2006@yahoo.com.cn
 
如果是长连接的话
最好发一下心跳包
不然是有可能出现楼主所说的这种情况的
 
我测试的时候是一直在发送数据的 大概1-3秒就会发一次
可是发着发着 服务器就收不到了。。。
 
自定义数据报头格式
TDataHeader = packed record
PackHeader: array[0..5] of Char; //数据包头
CommandID: Byte; //数据包命令码
DataLen: Integer; //数据内容长度
end;
服务器端代码
procedure TfrmMain.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
I,Count,nDataLen,RecvLen,RecvDataLen: Integer;
SendPauseFlag,IsSendFlag: Boolean;
DataLen, ReadLen, ReadCount, C: Integer;
Buf: PChar;
RDataStream,SDataStream: TMemoryStream;
RDataHeader,SDataHeader: TDataHeader;
begin
RecvLen := Socket.ReceiveLength;
ReadLen := 0;
if RecvLen < DataHeaderSize then Exit;
while ReadLen < RecvLen do
begin
ZeroMemory(@RDataHeader,DataHeaderSize);
RecvDataLen := Socket.ReceiveBuf(RDataHeader,DataHeaderSize);
if RecvDataLen = -1 then
begin
Continue;
end;
ReadLen := ReadLen + RecvDatalen;
GetMem(Buf,RDataHeader.DataLen);
try
RDataStream := TMemoryStream.Create;
try
ReadCount := 0; //读取缓冲区
while ReadCount < RDataHeader.DataLen do
begin
RecvDataLen := Socket.ReceiveBuf(Buf^,RDataHeader.DataLen);
if RecvDataLen = -1 then
begin
Sleep(1);
Continue;
end;
ReadCount := ReadCount + RecvDataLen;
RDataStream.Write(Buf^,RecvDataLen);
end;
ReadLen := ReadLen + ReadCount; //读取数据完成
RDataStream.Position:=0;
if RDataHeader.PackHeader = Header then
begin
//{进行数据处理,并向客户端发送处理完毕应答}
end
finally
RDataStream.Free;
end;
finally
FreeMem(Buf,RDataHeader.DataLen);
end;
end;
end;

客户端代码
procedure TSendWaterThread.Execute;
var
RecordCount,Count:Integer;
ThreadDataHeader: TDataHeader;
SendDataBuffer: array of TDataInfo; //注:TDataInfo为数据内容的记录体,不列出
begin
FreeOnTerminate:=True;
while SystemInfo.ServerConnected do //连接状态
begin
if SystemInfo.CanTransmitFlag then //此值为真则表示已经收到上一次发送数据的应答
begin
//读到要发送的数据
share.SelectSQL(frmDM.adqryNetThread,'select top 64 * from WaterInfo where not TransmitBj order by ID');
RecordCount:=frmDM.adqryNetThread.RecordCount;
if RecordCount>0 then
begin
with ThreadDataHeader do //TDataHeader类型的数据报头
begin
PackHeader:=HeaderStr;
CommandID:=08;
DataLen:=RecordCount*DataInfoSize;
end;
SetLength(SendDataBuffer,ThreadDataHeader.DataLen div DataInfoSize); //
Count:=0;
while not frmDM.adqryNetThread.Eof do
begin
//{将检索出来的数据写入动态记录数组SendDataBuffer}
end;
SystemInfo.CanTransmitFlag:=False;
if frmDM.ClientSocket.Socket.SendBuf(ThreadDataHeader,SizeOf(TDataHeader))=SizeOf(TDataHeader) then
frmMain.Memo1.Lines.Add('thread发送'+IntToStr(Count)+'条记录头成功!'+' '+TimeToStr(Time))
else
frmMain.Memo1.Lines.Add('thread发送'+IntToStr(Count)+'条记录头失败!'+' '+TimeToStr(Time));

if frmDM.ClientSocket.Socket.SendBuf(SendDataBuffer[0],ThreadDataHeader.DataLen)=ThreadDataHeader.DataLen then
frmMain.Memo1.Lines.Add('thread发送'+IntToStr(Count)+'条记录成功!'+' '+TimeToStr(Time))
else
frmMain.Memo1.Lines.Add('thread发送'+IntToStr(Count)+'条记录失败!'+' '+TimeToStr(Time));
end;
end;
end;
end;

大致代码就是这样
客户端的接收代码与服务器类似,接到服务器的应答后就更改 SystemInfo.CanTransmitFlag(可以继续传输标志) 这里就不贴出来了。
虽然我的客户端发送代码没有加重发,可是并没有出现发送记录失败的情况(我在MEMO里面记录了)。
出问题的时候 客户端的MEMO显示发送成功,可服务器的READ就是反应 可这时如果从服务器主动向客户端发送数据,客户端可以正常接收到。
请各位高手帮帮忙 抽点时间给看一下,谢谢了
 
我也有这方面的问题想就此问一下
ClientSocket 如何发送一串(96 01 72 4A BD)这样的十六进制值?
 
你可以把它当作文本来发送呀
 
不知道有没有什么办法能跟踪到ClientSocket 发送出来的数据是否正确
 
只要发送成功,发送的数据就一定是正确的
发送的时候要判断SENDBUF的返回值,那个才是真正放到缓冲区的字节数
 
看了你的服务器设计,我觉得有一点你使用不当,你在一个数据到来事件里做了太多的事情,主要的是你在接收缓冲数据失败时还SLEEP了,这与事件通知模型是不相配的,极有可能在你循环或SLEEP时忽略了新来的事件消息。
我建议你在收到包头后,设定一个标志成收包数据状态,然后再用一个足够的缓冲区在触发事件里进行接收,接收到指定大小的数据后,进行数据处理,同时改变标志成收包头状态。
 
在实际环境中条件比较苛刻,我建议分段发!
最好学习UNIX的风格,发送的报文短小精干.

我也遇到过类似问题!报文或控制字编码并CRC.大一点的数据就直接生成文件靠WEBSERVER
提供通讯,用WINDOWS API接受再转成流
有点脱了裤子放屁的感觉不过肯定不出问题!
我毕竟不是高手!只有这样的方法了!不过实用,
 
普通應用沒必要去用API,封裝好的東西當然有它的好處,開發起來快捷方便,只是掌握它要一點時間。
 
TO guanyueguan
我是几个工作站同时向服务器发送数据,如果包头和包数据分成两次接收的话会乱的,比如,我收完了1号站的包头,应该等着收1号站的数据了,可是这时候2号站的包头来了。处理起来太复杂了。
 
接收一个请求开启一个线程,对立完成数据交互哦,
 
你说的是阻塞式的 我用的是非阻塞式的
 
不好意思,我沒有完全說明白,其實處理每個客戶端包數據狀態很容易,就是定義一個簡單結構,只有TCustomWinSocket Socket的Handle或SocketHandle,狀態標識,和已讀數據統計,然後把它加在一個TList裡,每次讀事件先找到該Sokcet的狀態再確認該讀多少。
可能會麻煩一點,在你沒有找到更好的方法前,你可以試試看。

另外你原來的做法實際上是用了同步方式的思想去處理異步操作才出問題,如果圖簡單,還是那句話,用阻塞式做。或者你可以用更好的組件ICS去做,它封裝的比IDE自帶的要強多了,我也是看了它不少代碼受益的,地址:http://www.overbyte.be/。
 
后退
顶部