我用的是阻塞的模式首先我监听起来 //初始化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.   

    楼主这样的封装还不如用INDY。
      

  2.   

    但是客户端不是DELPHI写的 也可以用吗?
      

  3.   


    没关系的不过,自己用socket api,感觉好过indy,尤其做服务端
      

  4.   

    楼主accept用的是D的VCL线程类,接收客户端的数据也统一改成VCL线程类,recv方式应该是阻塞接收,在没有数据接收或接收的数据小于你指定的大小时这个线程应该是不会结束,在线程中用select处理吧,这个方便楼主断开客户端连接及退出线程。
      

  5.   

    请做以下检查:
      1)客户端发送有没有检查是否成功?(如:发1k,实际只发出900)
      2)服务器端接收,缓冲区是否足够?溢出有没有检查?
      3)客户/服务器端,有没有应用层协议?如果没有,应该定义应用层协议。 
      4)如果不是处理海量客户端,应该使用长连接模式。
      
     附:建议使用早期Delphi自带的Winsocket组件,很好用。需要特殊处理时,使用THackWinsocket.
      

  6.   

    以下视作楼主采用TCP通讯协议分析:1. 从接收客户端连接数据的服务端线程代码看,只调用了一次recv,在频繁的数据交互过程当中,一次recv并不一定能够收全客户端发来的数据。
    2. 只有一次接收,后续该连接就已经被遗弃,且无相关资源回收操作,由于数据没有被完全收取到应用层,如果客户端有多余(包括多次发送产生的)数据未被接收而填充满该连接的缓冲区时,客户端后续的发送就会失败。
    3. TCP为流协议,在连续发送数据后在接收端可能会产生粘包现象,需要定义有效的应用层协议以方便数据分离。
      

  7.   

    多用Select吧,判断是否有数据待接收