1. 程式人生 > >SOCKET UDP 通訊過程中 10022 和 10014 偶爾出現問題

SOCKET UDP 通訊過程中 10022 和 10014 偶爾出現問題

這個問題纏繞了我很長一段時間,現在問題解決了,總結一下,在SOCKET API呼叫時,一些需要注意的問題。

WINSOCK2 裡面跟 SOCKADDR 相關的呼叫都需要使用指標形式,並且這個SOCKADDR的長度也需要一個指向Integer的指標引數。

通常情況下在呼叫 recvfrom 時(下面是原型宣告),如果 SOCKADDR 引數的長度資訊(fromlen)沒有指定長度的話(未初始化),會偶發性地產生10022(提供了一個無效的引數)和 10014 錯誤。

function recvfrom( const s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; fromlen: PInteger ): Integer; stdcall;

下面貼一段接收處理的程式碼:

var
  sa: PSockAddr;
  iLen: integer;
  t1: integer;
  fd_read : PFDSet;
  timeout : PTimeVal;
  strTmp: string;
begin
  Result := 0;
  t1 := GetTickCount;
  new(fd_read);
  new(timeout);
  try
  FD_ZERO(fd_read^);
  FD_SET(FHandle, fd_read^);
  timeout^.tv_sec := aTimeOut div 1000;
  timeout^.tv_usec := 1000 * (aTimeOut mod 1000);
  if select(FHandle + 1, fd_read, nil, nil, timeout) > 0 then
  begin
    if FD_ISSET(FHandle, fd_read^) then
    begin
      new(sa);
      /// 長度必須指定,初始化正確的值否則的話就容易出現 10022 和 10014 的錯誤
      iLen := SizeOf(sa^);
      FillChar(sa^, iLen, 0);
      try
      Result := idWinSock2.recvfrom(FHandle, oBuffer, aBufferSize, 0, sa, @iLen);
      if Result <> SOCKET_ERROR then
      begin
        fromIP := string(inet_ntoa(sa^.sin_addr));
        fromPort := ntohs(sa^.sin_port);
      end else
      begin
        Result := 0;
      end;
      finally Dispose(sa); end;
    end;

    FD_CLR(FHandle, fd_read^);
  end;
  finally Dispose(fd_read); Dispose(timeout); end;
end;