关于winsock服务端接收数据很频繁时出现的问题。
我用的是阻塞的模式
首先我监听起来
//初始化winsock
socket...
//监听
然后用线程类 TThread创建一个Accept的 线程 线程里面whil循环,作为接受客户端的连接
当接受到客户端进来连接的时候 再创建一个线程(CreateThread)来recv客户端的数据
现在遇到的问题是 有N个客户端,并且客户端非常频繁的,向服务端发送数据的时候 服务端有时候会
漏掉一些数据 接收不到 是不是代码有问题?
我肯定客户端的发送操作是正确的。
//======Accept 线程==============================
TAcceptThread = Class(TThread)
TAcceptThread.Create(sock_Main);
//==============================Accept 线程==============================
constructor TAcceptThread.Create(ListenSock: Cardinal);
begin
F_ListenSock := ListenSock;
inherited Create(False);
end;
procedure TAcceptThread.Execute;
var
chBuffer : array[0..9000] of AnsiChar ; //2K 缓冲区
dwThreadID : DWORD;
PMyPara:PMyParam;
MyPara:MyParam;
begin
while True do
begin
//等待客户端来连接
//OutputDebugString('等待客户端来连接');
F_RecvLogStr := '';
F_cAddrlen := SizeOf(F_sockAddrClient);
ZeroMemory(@F_sockAddrClient, F_cAddrlen);
F_AcceptSock := accept(F_ListenSock, PSockAddr(@F_sockAddrClient), @F_cAddrlen);
if INVALID_SOCKET = F_AcceptSock then
begin
F_RecvLogStr := 'accept error!';
F_RecvLogStr := F_RecvLogStr + ' Error Code: ' + IntToStr(GetLastError) + FormatDateTime('yyyy-mm-dd hh:mm:ss:zzz',now);
Sleep(500);;
Continue;
end;
//客户端连接进入
//保存IP地址
F_ClienIPAddr := string(inet_ntoa(F_sockAddrClient.sin_addr));
F_ClientSockStr := IntToStr(F_AcceptSock);
F_RecvLogStr := F_RecvLogStr + '-----接收到一个连接-----' + #13#10 + F_ClienIPAddr + ' ' + FormatDateTime('yyyy-mm-dd hh:mm:ss:zzz',now) + #13#10;
//显示日志
Form1.mmo1.Lines.Add(F_RecvLogStr);
new(PMyPara);
PMyPara.MySock := F_AcceptSock;
CloseHandle(CreateThread(nil, 0, @MyRecvThread, PMyPara, 0, dwThreadID));
end;
end;
function MyRecvThread(lParam :PMyParam):DWORD;
var
chBuffer : array[0..9000] of AnsiChar ; //2K 缓冲 足够矣
cRecvBuffer : string;
cRecvLogStr : string;
cOrderStr : string;
//Buff: String[100];
addrIP : sockaddr_in;
nLen : Integer;
F_IP : string;
begin
//接收数据过程
ZeroMemory(@chBuffer[0], 9000);
//GetMem(chBuffer[1],2047);
try
if recv(lParam.MySock, chBuffer, 9000, 0) > 0 then
begin
cRecvBuffer := string(chBuffer);
cRecvLogStr := string(cRecvBuffer);
cOrderStr := cRecvLogStr;
//===========保存接收数据到日志==============================
cRecvLogStr := '-----START------------接收的数据------------------------'
+#13#10+cRecvLogStr+' '+#13#10+
' -----END--------------接收的数据------------------------'
+FormatDateTime('yyyy-mm-dd hh:mm:ss:zzz',now)+#13#10;
//cRecvLogStr := 'aaa' + cRecvLogStr + #13#10;
//cRecvLogStr := '-----START------------接收的数据------------------------' + #13#10 + cRecvLogStr;
//获取对方的IP地址
try
nLen := SizeOf(sockaddr_in);
if getpeername(lParam.MySock, addrIP, nLen) = 0 then
begin
F_IP := inet_ntoa(addrIP.sin_addr);
end
else
begin
F_IP := 'IP有错误!';
end;
except
end;
TSaveClienData.Create(lParam.MySock, cRecvBuffer, F_IP);
end
else
begin
//接收发生错误
cRecvLogStr:='---------------Error Recv-----------------'+FormatDateTime('yyyy-mm-dd hh:mm:ss:zzz',now)+#13#10;
end;
finally
//处理异常错误
//显示日志
Form1.mmo1.Lines.Add(cRecvLogStr);
end;
Result := 0;
end;
[解决办法]
请做以下检查:
1)客户端发送有没有检查是否成功?(如:发1k,实际只发出900)
2)服务器端接收,缓冲区是否足够?溢出有没有检查?
3)客户/服务器端,有没有应用层协议?如果没有,应该定义应用层协议。
4)如果不是处理海量客户端,应该使用长连接模式。
附:建议使用早期Delphi自带的Winsocket组件,很好用。需要特殊处理时,使用THackWinsocket.