中国程序员联盟 正在重新改版中ing 不便之处还请见谅 改版后将内容涉及java delphi .net php
 
  首页 | 数据库开发 | 网络通讯 | 多线程 | 多媒体开发 | 图像处理 | 程序人生 | 系统函数 | 控件开发 | Web服务
 
  当前位置:笨鱼delphi技术网>多线程>文章内容

delphi Winsock的传输的API封装

来源:网络 关于:bill 发布时间:2007-07-09   [收藏] [推荐]

{***************************************************************}
{ Vcl blocking mode                                             }
{ stNonBlocking    = 非阻塞模式                                 }
{ stThreadBlocking = 利用线程阻塞模式                           }
{ TServerType = (stNonBlocking, stThreadBlocking);              }
{***************************************************************}
unit XWinSock2;
interface
uses
  Windows, Messages, WinSock2;
const
  //Messagebox 错误ICON
  MB_Error       = MB_OK + MB_ICONERROR;
  //Messagebox 通知消息ICON
  MB_Information = MB_OK + MB_ICONINFORMATION;
  //Messagebox 警告消息ICON
  MB_Warning     = MB_OK + MB_ICONWARNING;
 
const
  SocketErrorFormat = 'Windows socket error: %s, on API ''%s''';
 
const
  CHAR0 = #0;
  BACKSPACE = #8;
  LF = #10;
  CR = #13;
  EOL = CR + LF;
  TAB = #9;
  CHAR32 = #32;
  sLineBreak = EOL;
  LWS = [TAB, CHAR32];
  FetchDelimDefault = ' ';
  wdays: array[1..7] of string = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
  monthnames: array[1..12] of string = ('Jan', 'Feb', 'Mar', 'Apr', 'May',
   'Jun',  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
  IdHexDigits: array [0..15] of Char = '0123456789ABCDEF';

type
  //Socket 执行结果, 在1.1中是利用ShowMessage弹出错误信息,这样有点不好,
  //就是在不想它弹对话框时也弹出,所以这里函数统一返回TSockRet类型,让用户定义是否要给出提示信息
  //TSockRet类型,记录错误码,错误信息,Result为函数执行结果.
  PSockRet = ^TSockRet;
  TSockRet = record
    Socket: TSocket;                    //Socket 标识
    Result: BOOL;                       //结果
    ErrorCode: Integer;                 //错误码
    ErrorMsg:  array[0..255] of Char;   //错误信息
  end;

//初始化Dll
function W2Startup(const SocketVersion: WORD = $2020): TSockRet;
//清除Dll
function W2Cleanup: TSockRet;
//读取数据 
function ReceiveBuf(const FSocket: TSocket; var Buf; const Count: Integer = -1): Integer;
//发送数据
function SendBuf(const FSocket: TSocket; var Buf; Count: Integer): Integer;
//检查Socket是否有异常
function SocketInExcept(const S: TSocket): BOOL;
//检查Socket是否可写
function SocketInSend(const S: TSocket): BOOL;
//检查Socket是否可读
function SocketInRecv(const S: TSocket): BOOL;
//检查Socket是否可写并发送数据
function CheckInSendBuf(const S: TSocket; var Buf; count: Integer): Integer;
//检测Socket是否有效
function W2ValidSock(const S: TSocket): BOOL;
//关闭Socket
function W2CloseSock(var S: TSocket): TSockRet;
//网络事件选择
function W2EventSelect(const S: TSocket; const hEvent: WSAEvent;
  const lNetworkEvents: u_long): TSockRet;
//枚举网络事件
function W2EnumNetwrokEvents(const S: TSocket; const hEvent: WSAEvent;
  lpNetworkEvents: PWSANETWORKEVENTS): TSockRet;
//初始化Socket
function W2InitSock(var S: TSocket; const SockType: u_int = SOCK_STREAM;
  const protocol: u_int = IPPROTO_IP; const lpProtocolInfo: PWSAPROTOCOL_INFOA = nil;
  const g: TGroup = 0; const dwFlags: Dword = 0): TSockRet;
//挷定Socket
function W2Bind(var S: TSocket; const IP, Name, Server: PChar; const Port: WORD): TSockRet;
//监听Socket
function W2Listen(var S: TSocket; const IP, Name, Server: PChar; Port: Integer;
  const Block: BOOL = True; const QueueSize: Integer = 5): TSockRet; overload;
//监听Socket
function W2Listen(var S: TSocket; QueueSize: Integer = 5): TSockRet; overload;
//接受客户端连接
function W2Accept(const ServerSocket: TSocket; var ClientSocket: TSocket; var lpAddr: TSockAddr;
  const lpfnCondition: PCONDITIONPROC = nil; const dwCallbackData: DWORD = 0): TSockRet;
//连接服务Socket
function W2Connect(var ClinetSocket: TSocket; const Name: PChar; const Address: PChar;
  Port: WORD; lpCalleeData: PWSABUF; const lpCallerData: PWSABUF = nil; const lpSQOS: PQOS = nil;
  const lpGQOS: PQOS = nil): TSockRet;
//发送数据缓冲,发送长度由TSockRet.Socket返回
function W2SendBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    const lpNumberOfBytesSent: PDWORD = nil; const dwFlags: DWORD = 0;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
//发送数据缓冲SendTo,送长度由TSockRet.Socket返回
function W2SendToBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    lpTo: psockaddr; iTolen: u_int;
    const lpNumberOfBytesSent: PDWORD = nil; const dwFlags: DWORD = 0;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;

//接收数据缓冲,接收度由TSockRet.Socket返回
function W2RecvBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    const lpNumberOfBytesRecvd: PDWORD = nil; const lpFlags: PDWORD = nil;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
//接收数据缓冲RecvFrom,接收度由TSockRet.Socket返回
function W2RecvFromBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    lpFrom: psockaddr; lpFromlen: PInt;
    const lpNumberOfBytesRecvd: PDWORD = nil; const lpFlags: PDWORD = nil;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
//关联完成端口
function W2ConIOCP(S: DWORD; hIOCP: THandle; PKey: DWORD): TSockRet;
 
//查找指定主机IP组
function LookupName(const Name: PChar): TInAddr;
//查找指定服务的端口
function LookupService(const Service: PChar): Integer;
function GetIpByHostName(Host: PChar): PChar;
function GetLocalIP: PChar;
function GetRemoteAddr(const FSocket: TSocket): TSockAddrIn;
function GetRemotePort(const FSocket: TSocket): Integer;
function GetRemoteHost(const FSocket: TSocket): PChar;
function GetRemoteAddress(const FSocket: TSocket): PChar;
 
//===============================================================================
//MessageBox  default 是Error ICON
function MsgBox(const OwnerHwnd: HWND; const lpText: PChar;
  const BtnType: DWORD = MB_Error): BOOL;
//Windows格式化字符串
function FormatChar(OutPut: PChar; const Format: PChar; arglist: array of Integer): Integer;
//格化Socket error number
function SocketError(const ErrorCode : Longint; const Format: PChar = nil): PChar;
// System error messages, from Sysutils unit
function SysErrorMessage(ErrorCode: Integer): PChar;

implementation
var
  WSData: TWSAData;
//初始化Dll 
function W2Startup(const SocketVersion: WORD): TSockRet;
begin //MakeWord(2, 0)
  //填充结构
  FillChar(Result, SizeOf(Result), 0);
  Result.ErrorCode := WinSock2.WSAStartup(SocketVersion, WSData);
  Result.Result := Result.ErrorCode = 0;
  if not Result.Result then begin
    FormatChar(Result.ErrorMsg, 'Windows socket error: %s (%d), on API ''WSAStartup''',
      [Integer(SysErrorMessage(Result.ErrorCode )), Result.ErrorCode ]);
  end else Result.ErrorMsg := 'WSAStartup Ok.';
end;
//清除Dll
function W2Cleanup: TSockRet;
begin
  //填充结构
  FillChar(Result, SizeOf(Result), 0);
  Result.ErrorCode := WinSock2.WSACleanup;
  Result.Result := Result.ErrorCode = 0;
  if not Result.Result then begin
    FormatChar(Result.ErrorMsg, 'Windows socket error: %s (%d), on API ''WSACleanup''',
      [Integer(SysErrorMessage(Result.ErrorCode )), Result.ErrorCode ]);
  end else Result.ErrorMsg := 'WSACleanup Ok.';
end;
//发送数据
function SendBuf(const FSocket: TSocket; var Buf; Count: Integer): Integer;
begin
  if W2ValidSock(FSocket) then
    Result := send(FSocket, Buf, Count, 0)
  else begin
    Result := -1;
  end;
end;
function ReceiveBuf(const FSocket: TSocket; var Buf; const Count: Integer = -1): Integer;
begin
  Result := -1;
  if Count = -1 then
    ioctlsocket(FSocket, FIONREAD, Longint(Result))
  else
    Result := recv(FSocket, Buf, Count, 0);
end;
//检查Socket是否可写并发送数据
function CheckInSendBuf(const S: TSocket; var Buf; count: Integer): Integer;
var
  ErrorCode: Integer;
begin
  Result := SOCKET_ERROR;
  while True do begin
    if not SocketInSend(S) then begin
      ErrorCode := WinSock2.WSAGetLastError;
      case ErrorCode of
        WSAENETDOWN, WSAENOTSOCK, WSAECONNABORTED,
        WSAECONNRESET,WSAENOTCONN, WSAESHUTDOWN, WSAEHOSTDOWN:
        begin
          CloseSocket(S);
          Break;
        end;
      end;
      System.Continue;
    end; //if not then
    Result := Send(S, Buf, Count, 0);
    if Result <> SOCKET_ERROR then Break;
  end;
end;
//检查Socket是否可写, 可写返回True,否则相反
function SocketInSend(const S: TSocket): BOOL;
var
  FDSet: TFDSet;
  TimeVal: TTimeVal;
begin
  FD_ZERO(FDSet);
  FD_SET(S, FDSet);
  TimeVal.tv_sec := 0;
  TimeVal.tv_usec := 500;
  Result := (select(0, nil, @FDSet, nil, @TimeVal) > 0);
end;
//检查Socket是否可读, 可读返回True,否则相反
function SocketInRecv(const S: TSocket): BOOL;
var
  FDSet: TFDSet;
  TimeVal: TTimeVal;
  ErrorCode: Integer;
begin
  FD_ZERO(FDSet);
  FD_SET(S, FDSet);
  TimeVal.tv_sec := 0;
  TimeVal.tv_usec := 500;
  Result := (select(0, @FDSet, nil, nil, @TimeVal) > 0);
  ErrorCode := WSAGetLastError;
  if Result then Result := ReceiveBuf(S, FDSet) > 0;
  if ErrorCode <> 0 then WinSock2.WSASetLastError(ErrorCode);
end;
//检查Socket是否有异常
function SocketInExcept(const S: TSocket): BOOL;
var
  FDSet: TFDSet;
  TimeVal: TTimeVal;
begin
  FD_ZERO(FDSet);
  FD_SET(S, FDSet);
  TimeVal.tv_sec := 0;
  TimeVal.tv_usec := 500;
  Result := (select(0, nil, nil, @FDSet, @TimeVal) > 0);
end;
//检测Socket是否有效
function W2ValidSock(const S: TSocket): BOOL;
begin
  Result := S <> WinSock2.INVALID_SOCKET;
end;
function W2CloseSock(var S: TSocket): TSockRet;
begin
  //填充结构
  FillChar(Result, SizeOf(Result), #0);
  Result.Result := W2ValidSock(S);
  if Result.Result then
  begin
    Result.Result := WinSock2.closesocket(S) = 0;
    if not Result.Result then
    begin
      //无效则检查错误码
      Result.ErrorCode := WinSock2.WSAGetLastError;
      //格式化错误信息
      FormatChar(Result.ErrorMsg, SocketErrorFormat,
      [Integer(SocketError(Result.ErrorCode)),
      Integer(PChar('closesocket'))])
    end
    else begin
      //将Socket置为INVALID_SOCKET
      //S := WinSock2.INVALID_SOCKET;
      Result.ErrorMsg := 'Close socket Ok.';
    end;
    //不管是否有错误都将Socket置为INVALID_SOCKET
    S := INVALID_SOCKET;
  end
  else Result.ErrorMsg := 'Not a valid Socket';
end;
//网络事件选择
function W2EventSelect(const S: TSocket; const hEvent: WSAEvent;
  const lNetworkEvents: u_long): TSockRet;
begin
  //填充结构
  FillChar(Result, SizeOf(Result), #0);
  //事件选择
  Result.Socket := WinSock2.WSAEventSelect(S, hEvent, lNetworkEvents);
  Result.Result := Result.Socket = 0;
  if not Result.Result then
  begin
    //无效则检查错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSAEventSelect'))]);
    case Result.ErrorCode of
      WSAENETDOWN:;// 网络子系统失效。
    end;
  end
  else //否则Socket事件选择成功
    Result.ErrorMsg := 'WSAEventSelect Ok.';
end;
//枚举网络事件
function W2EnumNetwrokEvents(const S: TSocket; const hEvent: WSAEvent;
  lpNetworkEvents: PWSANETWORKEVENTS): TSockRet;
begin
  //填充结构
  FillChar(Result, SizeOf(Result), #0);
  //事件选择
  Result.Socket := WinSock2.WSAEnumNetworkEvents(S, hEvent, lpNetworkEvents);
  Result.Result := Result.Socket = 0;
  if not Result.Result then
  begin
    //无效则检查错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSAEnumNetworkEvents'))]);
    case Result.ErrorCode of
      WSAENETDOWN:;// 网络子系统失效。
    end;
  end
  else //否则Socket事件选择成功
    Result.ErrorMsg := 'WSAEnumNetworkEvents Ok.';
end;
//初始化Socket
function W2InitSock(var S: TSocket; const SockType: u_int = SOCK_STREAM;
  const protocol: u_int = IPPROTO_IP; const lpProtocolInfo: PWSAPROTOCOL_INFOA = nil;
  const g: TGroup = 0; const dwFlags: Dword = 0): TSockRet;
begin
  ////填充结构
  FillChar(Result, SizeOf(Result), #0);
  //申请Socket
  S := WinSock2.WSASocket(PF_INET, SockType, protocol, lpProtocolInfo, g, dwFlags);
  Result.Socket := S;
  //检查Socket是否有效
  Result.Result := W2ValidSock(S);
  if not Result.Result then begin
    //无效则检查错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSASocket'))])
  end //否则申请Socket成功
  else Result.ErrorMsg := 'InitSocket Ok.';
end;

function W2Bind(var S: TSocket; const IP, Name, Server: PChar; const Port: WORD): TSockRet;
var
  Addr: TSockAddr;
begin
  //填充结构
  FillChar(Addr, SizeOf(Addr), 0);
  FillChar(Result, SizeOf(Result), 0);
  Result.Socket := S;
  //指定协议族
  Addr.sin_family := PF_INET;
  //Lookup a Server   这里指定一个知名的协议服务的端口
  if Server <> nil then
    WinSock2.WSAHtons(S, LookupService(Server), @Addr.sin_port)
    //Addr.sin_port := WinSock2.Htons(LookupService(Server))
  else  //指定端口
    WinSock2.WSAHtons(S, Port, @Addr.sin_port);
    //Addr.sin_port := WinSock2.WSAHtons(Port);
  // Lookup Name
  if Name <> nil then
    Addr.sin_addr := LookupName(Name)
  else if IP <> nil then   //指定IP
    Addr.sin_addr.S_addr := WinSock2.inet_addr(IP)
  else  Addr.sin_addr.S_addr := WinSock2.INADDR_ANY; //挷定所有IP
  //挷定Socket
  Result.Result := WinSock2.bind(S, @Addr, SizeOf(Addr)) = 0;
  if not Result.Result then begin try
      //取得挷定错误码
      Result.ErrorCode := WinSock2.WSAGetLastError;
      //格式化错误信息
      FormatChar(Result.ErrorMsg, SocketErrorFormat,
      [Integer(SocketError(Result.ErrorCode)),
      Integer(PChar('Bind'))])
    finally
      //挷定错误关闭Socket
      W2CloseSock(S);
    end;
  end  //挷定成功
  else Result.ErrorMsg := 'Bind Ok';
end;
//监听Socket
function W2Listen(var S: TSocket; QueueSize: Integer = 5): TSockRet;
begin
  //监听Socket
  Result.Result := WinSock2.listen(S, QueueSize) = 0;
  if not Result.Result then begin try
      //取得监听错误码
      Result.ErrorCode := WinSock2.WSAGetLastError;
      //格式化错误信息
      FormatChar(Result.ErrorMsg, SocketErrorFormat,
      [Integer(SocketError(Result.ErrorCode)),
      Integer(PChar('listen'))]);
    finally
      //监听关闭Socket
      W2CloseSock(S);
    end;
  end
  else Result.ErrorMsg := 'Listen OK.';
end;
//监听Socket
function W2Listen(var S: TSocket; const IP, Name, Server: PChar; Port: Integer;
  const Block: BOOL = True; const QueueSize: Integer = 5): TSockRet;
begin
  //初始化Socket
  Result := W2InitSock(S);
  if Result.Result then
  begin
    //挷定Socket
    Result := W2Bind(S, IP, Name, Server, Port);
    if Result.Result then
    begin
      //监听Socket
      Result.Result := WinSock2.listen(S, QueueSize) = 0;
      if not Result.Result then begin try
          //取得监听错误码
          Result.ErrorCode := WinSock2.WSAGetLastError;
          //格式化错误信息
          FormatChar(Result.ErrorMsg, SocketErrorFormat,
          [Integer(SocketError(Result.ErrorCode)),
          Integer(PChar('listen'))]);
        finally
          //监听关闭Socket
          W2CloseSock(S);
        end;
      end
      else Result.ErrorMsg := 'Listen OK.';
    end;
  end;
end;
//接受客户端连接
function W2Accept(const ServerSocket: TSocket; var ClientSocket: TSocket; var lpAddr: TSockAddr;
  const lpfnCondition: PCONDITIONPROC = nil; const dwCallbackData: DWORD = 0): TSockRet;
var
  AddrLen: Integer;
begin
  //填充Socket地址结构
  FillChar(lpAddr, SizeOf(lpAddr), 0);
  //Socket地址长度指针
  AddrLen := SizeOf(lpAddr);
  ClientSocket := WinSock2.WSAAccept(ServerSocket, @lpAddr, @AddrLen, lpfnCondition, dwCallbackData);
  //检查ClientSocket是否有效,这里可能不会出错,Accept接受的Socket 应该没有问题的
  Result.Result := W2ValidSock(ClientSocket);
  Result.Socket := ClientSocket;
  if not Result.Result then begin
    //取得监听错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSAAccept'))]);
  end
  else FormatChar(Result.ErrorMsg, 'WSAAccept Client IP[%s], Port: [%d] Ok.',
    [Integer(WinSOck2.inet_ntoa(lpAddr.sin_addr)), WinSock2.ntohs(lpAddr.sin_port)]);
end;
//连接服务Socket
function W2Connect(var ClinetSocket: TSocket; const Name: PChar; const Address: PChar;
  Port: WORD; lpCalleeData: PWSABUF; const lpCallerData: PWSABUF = nil; const lpSQOS: PQOS = nil;
  const lpGQOS: PQOS = nil): TSockRet;
var
  ToAddr: TSockAddr;
begin
  //初始化ClientSocket
  Result := W2InitSock(ClinetSocket);
  if Result.Result then begin
     (*
         如果无错误发生,WSAConnect()返回0。否则的话,将返回INVALID_SOCKET错误,
      应用程序可通过WSAGetLastError()来获取相应的错误代码。
         对于阻塞套接口来说,返回值表示连接试图是否成功。
      对于非阻塞套接口来说,连接试图不一定马上完成。在这种情况下,WSAConnect()
      返回SOCKET_ERROR,且WSAGetLastError()返回WSAEWOULDBLOCK. 此时应用程序可以:
         1。利用select()函数,通过检查套接口是否可写来判断连接请求是否完成。或者,
         2。如果应用程序已使用WSAAsyncSelect()函数来确定对连接事件的兴趣,则当连
            接操作完成时应用程序将收到FD _CONNECT通知。或者,
         3。如果应用程序已使用WSAEventSelect()函数来确定对连接事件的兴趣,则当连
            接操作完成时相应的事件对象将设置信号。
         对于一个非阻塞套接口来说,在连接试图完成之前,任何对该套接口的WSAConnect()
      调用都将以WSAEALREADY错误失败。
        如果返回值指出连接试图失败(例如WSAECONNREFUSED, WSAENETUNREACH,WSAETIMEDOUT)
      则应用程序可对该套接口再次调用WSAConnect()函数。
     *)
       //填充Socket地址结构
    FillChar(ToAddr, SizeOf(ToAddr), 0);
    ToAddr.sin_family := PF_INET;
    //ToAddr.sin_port := htons(Port);
    WinSock2.WSAHtons(ClinetSocket, Port, @ToAddr.sin_port);
   // Lookup Name
    if Name <> nil then
      ToAddr.sin_addr := LookupName(Name)
    else if Address <> nil then   //指定IP
      ToAddr.sin_addr.S_addr := WinSock2.inet_addr(Address);
     //连接到服务Socket
     Result.Result := WinSock2.WSAConnect(ClinetSocket, @ToAddr, SizeOf(ToAddr), lpCallerData, lpCalleeData, lpSQOS, lpGQOS) = 0;
     if not Result.Result then
     begin
       //取得监听错误码
       Result.ErrorCode := WinSock2.WSAGetLastError;
       //格式化错误信息
       FormatChar(Result.ErrorMsg, SocketErrorFormat,
       [Integer(SocketError(Result.ErrorCode)),
       Integer(PChar('WSAConnect'))]);
       //对于非阻塞套接口来说,连接试图不一定马上完成。在这种情况下,WSAConnect()
       //返回SOCKET_ERROR,且WSAGetLastError()返回WSAEWOULDBLOCK. 此时应用程序可以
       case Result.ErrorCode of
         WSAEWOULDBLOCK: Result.Result := True;//
         WSAECONNREFUSED: W2CloseSock(ClinetSocket);//连接试图被拒绝
         WSAETIMEDOUT: W2CloseSock(ClinetSocket);//连接超时
       end;
     end
     else FormatChar(Result.ErrorMsg, 'WSAConnect Client IP[%s], Port: [%d] Ok.',
    [Integer(WinSOck2.inet_ntoa(ToAddr.sin_addr)), WinSock2.ntohs(ToAddr.sin_port)]);
  end;
end;
//发送数据缓冲
function W2SendBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    const lpNumberOfBytesSent: PDWORD = nil; const dwFlags: DWORD = 0;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
begin
  //发送数据长度由TSockRet.Socket返回
  Result.Socket := WinSock2.WSASend(S, lpBuffers, dwBufferCount, lpNumberOfBytesSent,
                             dwFlags, lpOverlapped, lpCompletionRoutine);
  Result.Result := Result.Socket <> SOCKET_ERROR;
  if not Result.Result then
  begin
    //取得发送信人错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSASend'))]);
    case Result.ErrorCode of
      WSA_IO_PENDING: Result.Result := True;//错误代码WSA_IO_PENDING表示重叠操作成功启动,过后将有完成指示
      WSAEWOULDBLOCK: ;//W2CloseSock();
    end;
  end
  else Result.ErrorMsg := 'WSASend Ok.';
end;
//发送数据缓冲From
function W2SendToBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    lpTo: psockaddr; iTolen: u_int;
    const lpNumberOfBytesSent: PDWORD = nil; const dwFlags: DWORD = 0;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
begin
  Result.Socket := WinSock2.WSASendTo(S, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
                                      lpTo, iTolen, lpOverlapped, lpCompletionRoutine);
  Result.Result := Result.Socket <> SOCKET_ERROR;
  if not Result.Result then
  begin
    //取得发送信人错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSASendTo'))]);
    case Result.ErrorCode of
      WSA_IO_PENDING: Result.Result := True;//错误代码WSA_IO_PENDING表示重叠操作成功启动,过后将有完成指示
      WSAEWOULDBLOCK: ;//W2CloseSock();
    end;
  end
  else Result.ErrorMsg := 'WSASendTo Ok.';
end;

//接收数据缓冲
function W2RecvBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    const lpNumberOfBytesRecvd: PDWORD = nil; const lpFlags: PDWORD = nil;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
begin
  //接收数据长度由TSockRet.Socket返回
  Result.Socket := WinSock2.WSARecv(S, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd,
                             lpFlags, lpOverlapped, lpCompletionRoutine);
  Result.Result := Result.Socket <> SOCKET_ERROR;
  if not Result.Result then
  begin
    //取得发送信人错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSARecv'))]);
    case Result.ErrorCode of
      WSA_IO_PENDING: Result.Result := True;//错误代码WSA_IO_PENDING表示重叠操作成功启动,过后将有完成指示
      WSAEWOULDBLOCK: ;//W2CloseSock();
    end;
  end
  else Result.ErrorMsg := 'WSARecv Ok.';
end;

//接收数据缓冲RecvFrom
function W2RecvFromBuf(const S: TSocket; lpBuffers: PWSABUF; dwBufferCount: DWORD;
    lpFrom: psockaddr; lpFromlen: PInt;
    const lpNumberOfBytesRecvd: PDWORD = nil; const lpFlags: PDWORD = nil;
    const lpOverlapped: LPWSAOVERLAPPED = nil;
    const lpCompletionRoutine: PWSAOVERLAPPED_COMPLETION_ROUTINE = nil): TSockRet;
begin
  //接收数据长度由TSockRet.Socket返回
  Result.Socket := WinSock2.WSARecvFrom(S, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd,
                             lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine);
  Result.Result := Result.Socket <> SOCKET_ERROR;
  if not Result.Result then
  begin
    //取得发送信人错误码
    Result.ErrorCode := WinSock2.WSAGetLastError;
    //格式化错误信息
    FormatChar(Result.ErrorMsg, SocketErrorFormat,
    [Integer(SocketError(Result.ErrorCode)),
    Integer(PChar('WSARecvFrom'))]);
    case Result.ErrorCode of
      WSA_IO_PENDING: Result.Result := True;//错误代码WSA_IO_PENDING表示重叠操作成功启动,过后将有完成指示
      WSAEWOULDBLOCK: ;//W2CloseSock();
    end;
  end
  else Result.ErrorMsg := 'WSARecvFrom Ok.';
end;
//关联完成端口
function W2ConIOCP(S: DWORD; hIOCP: THandle; PKey: DWORD): TSockRet;
begin
  //创建完成端口或关联Socket //初始化完成端口:Windows.CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
  Result.Socket := Windows.CreateIoCompletionPort(S, hIOCP, PKey, 0);
  Result.Result := Result.Socket <> 0;
  //失败的
  if not Result.Result then
  begin
    //取得Windows Lasterror
    Result.ErrorCode := Windows.GetLastError;
    FormatChar(Result.ErrorMsg, 'Windows Api error: %s (%d), on API ''CreateIoCompletionPort''',
      [Integer(SysErrorMessage(Result.ErrorCode )), Result.ErrorCode ]);
  end
  else
    Result.ErrorMsg := 'CreateIoCompletionPort Ok.';
end;
//查找指定服务的端口
function LookupService(const Service: PChar): Integer;
var
  ServEnt: PServEnt;
begin   //返回本机上一个存在服务类型所开启的端口
  ServEnt := getservbyname(Service, 'tcp');
  if ServEnt <> nil then
    Result := ntohs(ServEnt.s_port)
  else Result := 0;
end;
//查找指定主机IP组
function LookupName(const Name: PChar): TInAddr;
var
  HostEnt: PHostEnt;
  InAddr: TInAddr;
begin
  HostEnt := gethostbyname(Name);
  FillChar(InAddr, SizeOf(InAddr), 0);
  if HostEnt <> nil then
  begin
    with InAddr, HostEnt^ do
    begin
      S_un_b.s_b1 := h_addr^.S_un_b.s_b1;
      S_un_b.s_b2 := h_addr^.S_un_b.s_b2;
      S_un_b.s_b3 := h_addr^.S_un_b.s_b3;
      S_un_b.s_b4 := h_addr^.S_un_b.s_b4;
    end;
    {with InAddr, HostEnt^ do
    begin
      S_un_b.s_b1 := h_addr^[0];
      S_un_b.s_b2 := h_addr^[1];
      S_un_b.s_b3 := h_addr^[2];
      S_un_b.s_b4 := h_addr^[3];
    end;
    }
  end;
  Result := InAddr;
end;
//MessageBox  default 是Error ICON
function MsgBox(const OwnerHwnd: HWND; const lpText: PChar;
  const BtnType: DWORD = MB_Error): BOOL;
var
  lpTitle: PChar;
  H: HWND;
  Len: Integer;
  YESOK: Integer;
begin
  YESOK := 0;
  if (BtnType and MB_OKCANCEL = MB_OKCANCEL) then YESOK := IDOK
  else if (BtnType and MB_YESNO = MB_YESNO) then YESOK  := IDYES;
  H := GetActiveWindow;
  if OwnerHwnd <> 0 then H := OwnerHwnd;
  Len := Windows.GetWindowTextLength(H) + 1;
  GetMem(lpTitle, Len);
  SendMessage(H, WM_GETTEXT, Len, Longint(lpTitle));
  Result := Windows.MessageBox(H, lpText, lpTitle, BtnType) = YESOK;
  FreeMem(lpTitle, Len);
end;
//Windows格式化字符串
function FormatChar(OutPut: PChar; const Format: PChar; arglist: array of Integer): Integer;
// Example: var OutPut: array[0..1024] of Char; //Wvsprintf format最长是1kb 1024字节,大于1024会被截断
// FormatChar(OutPut, 'A[%s] - %d', [Integer(PChar('test')), 10]); OutPut := 'A[test] - 10'
begin
  Result := Windows.wvsprintf(OutPut, Format, @arglist[Low(arglist)])
end;
// this function from Internet delphibbs
function SocketError(const ErrorCode : Longint; const Format: PChar): PChar;
{ returns an error string for }
{ the winsock error number    }
var
  S, Temp: array [0..64] of Char;
begin
  S := #0;
  case ErrorCode of
    WSAEINTR   : s := 'WSAEintr';
    WSAEBADF   : s := 'WSAEbadf';
    WSAEACCES  : s := 'WSAEacces';
    WSAEFAULT  : s := 'WSAEfault';
    WSAEINVAL  : s := 'WSAEinval';
    WSAEMFILE  : s := 'WSAEmfile';
  { windows sockets definitions of regular berkeley error constants }
    WSAEWOULDBLOCK      : s := 'WouldBlock';
    WSAEINPROGRESS      : s := 'InProgress';
    WSAEALREADY         : s := 'Already';
    WSAENOTSOCK         : s := 'NotSock';
    WSAEDESTADDRREQ     : s := 'DestAddrReq';
    WSAEMSGSIZE         : s := 'MsgSize';
    WSAEPROTOTYPE       : s := 'ProtoType';
    WSAENOPROTOOPT      : s := 'NoProtoOpt';
    WSAEPROTONOSUPPORT  : s := 'ProtoNoSupport';
    WSAESOCKTNOSUPPORT  : s := 'SocktNoSupport';
    WSAEOPNOTSUPP       : s := 'OpNotSupp';
    WSAEPFNOSUPPORT     : s := 'PFNoSupport';
    WSAEAFNOSUPPORT     : s := 'AFNoSupport';
    WSAEADDRINUSE       : s := 'AddrInUse';
    WSAEADDRNOTAVAIL    : s := 'AddrNotAvail';
    WSAENETDOWN         : s := 'NetDown';
    WSAENETUNREACH      : s := 'NetUnreach';
    WSAENETRESET        : s := 'NetReset';
    WSAECONNABORTED     : s := 'ConnAborted';
    WSAECONNRESET       : s := 'ConnReset';
    WSAENOBUFS          : s := 'NoBuffs';
    WSAEISCONN          : s := 'IsConn';
    WSAENOTCONN         : s := 'NotConn';
    WSAESHUTDOWN        : s := 'ShutDown';
    WSAETOOMANYREFS     : s := 'TooManyRefs';
    WSAETIMEDOUT        : s := 'TimedOut';
    WSAECONNREFUSED     : s := 'ConnRefused';
    WSAELOOP            : s := 'Loop';
    WSAENAMETOOLONG     : s := 'NameNotLong';
    WSAEHOSTDOWN        : s := 'HostDown';
    WSAEHOSTUNREACH     : s := 'HostUnreach';
    WSAENOTEMPTY        : s := 'NotEmpty';
    WSAEPROCLIM         : s := 'Proclim';
    WSAEUSERS           : s := 'Users';
    WSAEDQUOT           : s := 'DQuot';
    WSAESTALE           : s := 'Stale';
    WSAEREMOTE          : s := 'Remote';
    { extended windows sockets error constant definitions }
    WSASYSNOTREADY      : s := 'SysNotReady';
    WSAVERNOTSUPPORTED  : s := 'VerNotSupported';
    WSANOTINITIALISED   : s := 'NotInitialised';
  { error return codes from gethostbyname() and gethostbyaddr() }
  { (when using the resolver). note that these errors are       }
  { retrieved via WSAGetLastError() and must therefore follow   }
  { the rules for avoiding clashes with error numbers from      }
  { specific implementations or language run-time systems. for  }
  { this reason the codes are based at WSABASEERR+1001. note    }
  { also that [WSA]NO_ADDRESS is defined only for compatibility }
  { purposes.                                                   }
  { authoritative answer: Host not found }
  WSAHOST_NOT_FOUND     : s := 'Host Not Found';
  { non-authoritative: Host not found, or SERVERFAIL }
  WSATRY_AGAIN          : s := 'Host not found - try again';
  { non-recoverable errors, FORMERR, REFUSED, NOTIMP }
  WSANO_RECOVERY        : s := 'Unrecoverable error';
  { valid name, no data record of requested type }
  WSANO_DATA            : s := 'Valid name but no data';
 // WSANO_ADDRESS         : s := 'No address, look for MX record';
  else
    s := #0;
  end;
  Result := nil;
  if lstrlen(S) > 0 then begin
    FillChar(Temp, SizeOf(Temp), #0);
    if Format <> nil then
      FormatChar(Temp, Format, [ErrorCode, Integer(@S)])
    else
      FormatChar(Temp, 'Error: [%d] - [%s]', [ErrorCode, Integer(@S)]);
    GetMem(Result, lstrlen(Temp) + 1);
    lstrcpy(Result, Temp);
  end;
end;

function SysErrorMessage(ErrorCode: Integer): PChar;
var
  Buffer: array[0..255] of Char;
  Len: Integer;
begin
  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS or
    FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, ErrorCode, 0, Buffer,
    SizeOf(Buffer), nil);
  while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
  Result := nil;
  if Len > 0 then begin
    GetMem(Result, Len + 1);
    lstrcpyn(Result, Buffer, Len);
  end;
end;
function GetRemoteHost(const FSocket: TSocket): PChar;
var
  SockAddrIn: TSockAddrIn;
  Size: Integer;
  HostEnt: PHostEnt;
  ret: BOOL;
begin
  Size := SizeOf(SockAddrIn);
  ret := getpeername(FSocket, SockAddrIn, Size) = 0;
  if ret then  begin
    HostEnt := gethostbyaddr(@SockAddrIn.sin_addr.s_addr, 4, PF_INET);
    Result := HostEnt.h_name;
  end else Result := nil;
end;
function GetRemoteAddress(const FSocket: TSocket): PChar;
var
  SockAddrIn: TSockAddrIn;
  Size: Integer;
begin
  Size := SizeOf(SockAddrIn);
  if getpeername(FSocket, SockAddrIn, Size) = 0 then
    Result := inet_ntoa(SockAddrIn.sin_addr)
  else Result := '127.0.0.1'; 
end;
function GetRemotePort(const FSocket: TSocket): Integer;
var
  SockAddrIn: TSockAddrIn;
  Size: Integer;
begin
  Size := SizeOf(SockAddrIn);
  getpeername(FSocket, SockAddrIn, Size);
  Result := ntohs(SockAddrIn.sin_port);
end;

function GetIpByHostName(Host: PChar): PChar;
type
  TIPinAddr = array[0..10] of PInAddr;
  PIPinAddr =^ TIPinAddr;
var
  phe: PHostEnt;
  PIP: PIPinAddr;
  I: Integer;
begin
  Result := nil;
  Phe := WinSock2.gethostbyname(Host);
  if Phe <> nil then
  begin
    I := 0;
    PIP := PIPinAddr(phe^.h_addr_list);
    while PIP^[I] <> nil do
    begin
      if I = 0 then  Result := WinSock2.inet_ntoa(PIP^[I]^);
      Inc(I);
    end; 
  end;
end;
function GetLocalIP: PChar;
type
  TaPInAddr = array [0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe  : PHostEnt;
  pptr : PaPInAddr;
  Buffer : array [0..63] of char;
  I    : Integer;
begin
  Result := nil;
  FillChar(Buffer, SizeOf(Buffer), #0);
  GetHostName(Buffer, SizeOf(Buffer));
  phe :=GetHostByName(buffer);
  if phe = nil then Exit;
  pptr := PaPInAddr(Phe^.h_addr_list);
  I := 0;
  while pptr^[I] <> nil do begin
    Result :=  (inet_ntoa(pptr^[I]^));
    Inc(I);
  end;
end;

function GetRemoteAddr(const FSocket: TSocket): TSockAddrIn;
var
  Size: Integer;
begin
    FillChar(Result, SizeOf(Result), 0);
    Size := SizeOf(Result);
    if getpeername(FSocket, Result, Size) <> 0 then
      FillChar(Result, SizeOf(Result), 0);
end;
end.

[浏览: 次]   
上一篇:delphi 利用线程FTP上传上个目录指定的后缀文件   下一篇:delphi winsock2 网络编程(上)
[收藏] [推荐] [返回顶部] [打印本页] [关闭窗口]  
    评论加载中…
google adsense热点文章
·delphi winsock2 网络编程(下下)
·delphi winsock2 网络编程(上)
·delphi 多线程技术在Delphi数据库编程
·delphi winsock2 网络编程(中)
·delphi winsock2 网络编程(下)
·delphi Delphi_转载:TThread类剖析
·delphi Delphi_进程间传递消息(发送和
·delphi 利用线程FTP上传上个目录指定的
·delphi Delphi_获取其他线程的光标句柄
·delphi Smart threads with a central
     delphi技术网 | firefox 下载 | Avant Browser下载 | dedecms 技术网 | drupal 爱好者 | php 技术网
  Copyright@www.delphichm.com,2006-2009.All Rights Reserved.
 
程序员联盟 | delphi Java .net|QQ:707102932