看了些资料
An FD_WRITE message is posted when a socket is first connected with connect or WSAConnect (after FD_CONNECT, if also registered) or accepted with accept or WSAAccept, and then after a send operation fails with WSAEWOULDBLOCK and buffer space becomes available.function TMyTcpClient.SendBuf(var buf; const iLen: Integer): integer;
var
  ss: string;
  iErr: Integer;
begin
  Result := Socket_error;
  if (FSocket <> Invalid_socket) and FActive then
  begin
    Result := winsock2.send(FSocket, buf, iLen, 0);
    if (Result = Socket_error) or (Result <> iLen) then
    begin
      iErr := WSAGetLastError();
      ss := 'Send data error: ' + IntToStr(iErr);
      DoError(self, seSend, PChar(ss), iErr);
      if iErr <> WSAEWOULDBLOCK then
      begin
        DoClose;
      end      end;
  end;
end;
请问我要怎么改?网上看了 说要
等待 FD_WRITE 继续发送 不知道怎么做?求指点

解决方案 »

  1.   

    调用WSASend试试,这个是异步发送。
      

  2.   

    版主 看了下说明文档,WSASend的error返回值 也有WSAEWOULDBLOCK
      

  3.   

    如何等待 FD_WRITE 继续发送?
      

  4.   

    注册 FD_WRITE 消息
      

  5.   

    FD_WRITE有没有定义消息处理函数?
      

  6.   

    请问是在SendBuf函数后面重新注册吗?我在创建TCP之前有一个线程中监测TCP事件发生事件
    procedure DoProc(Sender: TObject);
    var
      iLocalIdx, iStartIdx, iWaitNum, idx: integer;
      NetwEvt: TWSANetworkEvents;
      j: Cardinal;
      i: Integer;
      Evt: WSAEVENT;
      Skt: TSocket;
      
      tcpClt: TMyTcpClient;
      ss: string;
      iErr: Integer; 
    begin
      try
        if TMythread(Sender).WaitNum <= 0 then
        begin
          if not TMythread(Sender).IsPause then
            TMythread(Sender).Suspend;
          Exit;
        end;    Evt := 0;
        Skt := -1;    //对事件对象数组进行检查网络事件(即等待某个事件的触发)
        idx := WSAWaitForMultipleEvents(TMythread(Sender).WaitNum, TMythread(Sender).GetFirstEvtAddr, False, I_MaxWaitTime, False);    if (idx >= I_WaitMaxEvt) or (idx < 0)then    
        begin
          if idx = Socket_error then
          begin
            Sleep(I_MaxFreeWaitTime);
            //应该要调整,去掉Evt=0,或者Socket=-1的
          end;
          Exit;
        end;
            idx := idx - wsa_wait_event_0;    if TMythread(Sender).SktEvtItems[idx] = nil then Exit;
        skt := TMythread(Sender).SktEvtItems[idx].SockID;
        Evt := TMythread(Sender).SktEvtItems[idx].EventId;    FillChar(NetwEvt.lNetworkEvents, sizeof(NetwEvt), 0);    WSAEnumNetworkEvents(Skt, Evt, @NetwEvt);    j := NetwEvt.lNetworkEvents;
        if ((j and FD_Read) > 0) or ((j and FD_OOB) > 0) then
        begin
          if (j and FD_Read) > 0 then
          begin
            iErr := NetwEvt.iErrorCode[FD_Read_BIT];
            if iErr = 0 then
              ProcSockEvt(sender, FD_Read, skt)
            else
            begin 
              tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(skt));
              if tcpClt <> nil then
              begin
                ss := 'Receive data error, ' + IntToStr(iErr);
                if Assigned(tcpClt.OnErrorMsg) then
                  tcpClt.OnErrorMsg(tcpClt, seReceive, PChar(ss), iErr);
                  
                if (iErr >= 10050) and (iErr <= 10058) then 
     
                begin //严重错误要关闭Socket
                  if iErr <> 10056 then
                    ProcSockEvt(sender, FD_Close, skt);
                end;
              end;
            end;//end of 
          end;
          if (j and FD_OOB) > 0 then //暂时没用到
          begin
            iErr := NetwEvt.iErrorCode[FD_OOB_BIT];
            if NetwEvt.iErrorCode[FD_OOB_BIT] = 0 then
            begin
              ProcSockEvt(sender, FD_OOB, skt); //OK去掉注释可用
              //Exit;//  带外的不做处理
            end
            else
            begin 
              tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(skt));
              if tcpClt <> nil then
              begin
                ss := 'Receive OOB data error, ' + IntToStr(iErr);
                if Assigned(tcpClt.OnErrorMsg) then
                  tcpClt.OnErrorMsg(tcpClt, seReceive, PChar(ss), iErr);
              end;
            end;//end of 
          end;
        end
        else
        if (j and FD_Close) > 0 then
        begin
          iErr := NetwEvt.iErrorCode[FD_Close_BIT];
          if iErr <> 0 then
          begin 
            tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(skt));
            if tcpClt <> nil then
            begin
              ss := 'Close Socket error, ' + IntToStr(iErr);
              if Assigned(tcpClt.OnErrorMsg) then
                tcpClt.OnErrorMsg(tcpClt, seClose, PChar(ss), iErr);
            end;
          end;//end of 
          ProcSockEvt(sender, FD_Close, skt);
        end
        else
        if (j and FD_Write) > 0 then
        begin
          iErr := NetwEvt.iErrorCode[FD_Write_BIT];
          if iErr = 0 then
            ProcSockEvt(sender, FD_Write, skt)//这里没做处理,是个空的,不知道要怎么处理?
          else
          begin 
            tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(skt));
            if tcpClt <> nil then
            begin
              ss := 'Write data error, ' + IntToStr(iErr);
              if Assigned(tcpClt.OnErrorMsg) then
                tcpClt.OnErrorMsg(tcpClt, seSend, PChar(ss), iErr);
            end;
          end;//end of 
        end;
     //一下是ProcSockEvt的FD_wrie消息,
    procedure ProcSockEvt(Sender: TObject; const iOpt, iSocket: Integer);
    var
      AccAddr: TSockAddrIn;
      err, i, j, iLen, lenAddr: Integer;
      PNetwEvt: PWSANetworkEvents;
      evt: wsaevent;
      SktEvt: TMySktEvtItem;
      tcpClt: TMyTcpClient;
      ss: String;
      P: Pointer;begin
      case iOpt of
        Fd_read:
        begin
          iLen := TMyTcpBase.GetRecLength(iSocket);
          if iLen <= 0 then
            Exit;
          P := GlobalAllocPtr(GPTR, iLen * SizeOf(Byte));
          tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(iSocket));
          if p = nil then
          begin
            if tcpClt <> nil then
            begin
              err := GetLastError;
              ss := 'Receive data error, alloc global memory failed: ' + IntToStr(err);
              if Assigned(tcpClt.OnErrorMsg) then
                tcpClt.OnErrorMsg(tcpClt, seReceive, PChar(ss), err);
              tcpClt.Close;
            end;
            Exit;
          end;
          try
            try
              J := recv(iSocket, TMyArrByte(P)[0], iLen, 0);
              if tcpClt = nil then Exit;
              if (J <= 0) or (J <> iLen) then
              begin
                if tcpClt <> nil then
                begin
                  if Assigned(tcpClt.OnErrorMsg) then
                  begin
                    err := WSAGetLastError;
                    //ss := '接收数据出错: ' + IntToStr(err);
                    ss := 'Receive data error: ' + IntToStr(err);
                    if Assigned(tcpClt.OnErrorMsg) then
                      tcpClt.OnErrorMsg(tcpClt, seReceive, PChar(ss), err);
                  end;
                end;
                Exit;
              end
              else
              begin // J > 0 and J = iLen
                if Assigned(tcpClt.OnReceiveMsg) then
                begin
                  tcpClt.OnReceiveMsg(tcpClt, Cardinal(P), J); //OK 事件处理 ,这是线程事件
                end;
              end; //end of // J > 0 and J = iLen
            finally
              if P <> nil then
                GlobalFreePtr(P);
            end;
          except
            on E: Exception do
            begin
              if tcpClt <> nil then
              begin
                err := WSAGetLastError;
                ss := 'Receive data exception.' + IntToStr(err);
                if Assigned(tcpClt.OnErrorMsg) then
                  tcpClt.OnErrorMsg(tcpClt, seReceive, PChar(ss), err);
              end;
            end;
          end; // end of try except
        end; //FD_Read
        fd_close:
        begin
          tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(iSocket));
          if tcpClt <> nil then
          begin
            
            PostMessage(tcpClt.Handle, WM_MYSOCKETMSG, iSocket, FD_CLOSE);
            // end of 
          end;  
        end;
        Fd_oob:
        begin
          iLen := 1; //MSG_oob只有一个
          P := GlobalAllocPtr(GPTR, iLen * SizeOf(Byte));
          try
            J := recv(iSocket, TMyArrByte(P)[0], iLen, MSG_OOB);
            tcpClt := TMyTcpClient(TMythread(Sender).GetTcpclientBySkt(iSocket));
            if tcpClt = nil then Exit;
            if (J > 0) then
            begin
              if Assigned(tcpClt.OnReceiveMsg) then
                tcpClt.OnReceiveMsg(tcpClt, Cardinal(P), J);
            end;
          finally
            GlobalFreePtr(P);
          end;
          
        end;//end of FD_OOB
        
        FD_WRITE://不知道要怎么处理?
        begin        end;
      end;//end of case 
    end;
      

  7.   

     有 但是不是在sendbuf函数重新注册?
      

  8.   

    FD_WRITE是开始时注册的,需要在主线程中处理消息返回,你参考下《Windows网络编程》,里面有详细的解释。
      

  9.   

    提供个思路:仅供参考
    是在收到wsaewouldblock,立即把当前的socket转成缓冲区模式
    所有要发出的数据填充到一个缓冲区队列
    在收到FD_WRITE之后再从缓冲区开始发送
    一直到数据发完才把socket转为实时发送