Socket异步非阻塞send error wsaewouldblock 如何解决?

new_yang 2013-08-06 05:41:47
看了些资料
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 继续发送 不知道怎么做?求指点
...全文
433 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
该用户很帅 2013-08-13
  • 打赏
  • 举报
回复
提供个思路:仅供参考 是在收到wsaewouldblock,立即把当前的socket转成缓冲区模式 所有要发出的数据填充到一个缓冲区队列 在收到FD_WRITE之后再从缓冲区开始发送 一直到数据发完才把socket转为实时发送
SQLDebug_Fan 2013-08-12
  • 打赏
  • 举报
回复
FD_WRITE是开始时注册的,需要在主线程中处理消息返回,你参考下《Windows网络编程》,里面有详细的解释。
new_yang 2013-08-08
  • 打赏
  • 举报
回复
引用 5 楼 SQLDebug_Fan 的回复:
FD_WRITE有没有定义消息处理函数?
有 但是不是在sendbuf函数重新注册?
new_yang 2013-08-08
  • 打赏
  • 举报
回复
引用 4 楼 lwm08106542000 的回复:
注册 FD_WRITE 消息
请问是在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;
new_yang 2013-08-08
  • 打赏
  • 举报
回复
求帮忙啊 各位大神 搞几天了没什么结果啊
new_yang 2013-08-07
  • 打赏
  • 举报
回复
引用 1 楼 SQLDebug_Fan 的回复:
调用WSASend试试,这个是异步发送。
版主 看了下说明文档,WSASend的error返回值 也有WSAEWOULDBLOCK
SQLDebug_Fan 2013-08-07
  • 打赏
  • 举报
回复
FD_WRITE有没有定义消息处理函数?
lwm08106542000 2013-08-07
  • 打赏
  • 举报
回复
注册 FD_WRITE 消息
new_yang 2013-08-07
  • 打赏
  • 举报
回复
如何等待 FD_WRITE 继续发送?
SQLDebug_Fan 2013-08-06
  • 打赏
  • 举报
回复
调用WSASend试试,这个是异步发送。

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧