WinSock:10038 - WSAENOTSOCK尝试对非套接字的操作进行操作

问题描述 投票:1回答:1

好吧,我有这个代码,我正在尝试从客户端接收数据但发生GetLastError()正在返回:

10038 - WSAENOTSOCK尝试对非套接字的操作进行操作。

我怀疑这个问题与向Pointer施放TSocket有关,已经下面的ClientThread()函数通过你的参数接收套接字。

怎么解决这个问题?

const
 Buffer: array [0 .. 9] of AnsiChar = ('A', 'B', 'C', 'D', 'E', 'F', 'G',
    'H', 'I', #0);

function ClientThread(P: Pointer): Integer;
var
  Buf: array [0 .. SizeOf(Buffer) - 1] of AnsiChar;
  Sock: TSocket;
begin
  Result := 0;
  Writeln('New thread started.' + #13#10);

  Sock := TSocket(P);

  if recv(Sock, Buf, SizeOf(Buffer), 0) <= 0 then //My trouble is here.
  begin
    Writeln(GetLastError);
    closesocket(Sock);
    Result := 0;
    Exit;
  end;

  if not CompareMem(@Buf, @Buffer, SizeOf(Buffer)) then
  begin
    closesocket(Sock);
    Result := 0;
    Exit;
  end;

 end;

function StartServer(Port: Integer): Boolean;
var
  _wsdata: WSAData;
  serverSocket, S: TSocket;
  _addrIn, _addr: sockaddr_in;
  addrSize: Integer;
  tid: Cardinal;
begin
  Result := False;

  if WSAStartup(MakeWord(2, 2), _wsdata) <> 0 then
    Exit;

  serverSocket := socket(AF_INET, SOCK_STREAM, 0);

  if serverSocket = INVALID_SOCKET then
    Exit;

  _addrIn.sin_family := AF_INET;
  _addrIn.sin_addr.S_addr := INADDR_ANY;
  _addrIn.sin_port := htons(Port);

  if bind(serverSocket, _addrIn, SizeOf(_addrIn)) = SOCKET_ERROR then
    Exit;

  if listen(serverSocket, SOMAXCONN) = SOCKET_ERROR then
    Exit;

  addrSize := SizeOf(_addrIn);
  getsockname(serverSocket, _addrIn, addrSize);

  Writeln(Format('Listening on port %d' + #13#10, [ntohs(_addrIn.sin_port)]));

  while True do
  begin
    S := accept(serverSocket, @_addr, @addrSize);
    CreateThread(nil, 0, @ClientThread, @S, 0, tid);
  end;

  Result := True;
end;

用法:

StartServer(1234);
delphi winsock delphi-10-seattle
1个回答
4
投票

你犯了几个错误。

  • 你的ClientThread()的签名是错误的。它必须像这样定义: function ClientThread(P: Pointer): DWORD; stdcall; 如果没有stdcallP参数将无法正确传递。
  • 您正在向您的线程传递指向本地TSocket变量的指针。在您的ClientThread()中,您没有取消引用该指针来访问原始TSocket,这是导致您的错误消息的原因。 但更重要的是,您正在为多个客户端线程重用相同的TSocket变量。你所有的线程都指向相同的物理TSocket。不要使用@运算符,将TSocket的副本传递给每个客户端线程。幸运的是,TSocket只是一个UINT,它的值将适合在指针内部。 而且你需要在线程退出之前关闭TSocket。如果closesocket()返回true,你不会调用CompareMem()
  • 你正在泄漏线程,因为你永远不会关闭THandle返回的CreateThread()

话虽如此,试试这个:

const
  Buffer: array [0 .. 9] of AnsiChar = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', #0);

function ClientThread(P: Pointer): DWORD; stdcall;
var
  Buf: array [0 .. SizeOf(Buffer) - 1] of AnsiChar;
  Sock: TSocket;
  Ret, NumRead: integer;
begin
  Result := 0;
  Sock := TSocket(P);
  try
    WriteLn('New thread started.');
    NumRead := 0;
    repeat
      Ret := recv(Sock, @Buf[NumRead], SizeOf(Buffer)-NumRead, 0);
      if Ret <= 0 then
      begin
        if Ret = SOCKET_ERROR then
        begin
          Ret := WSAGetLastError;
          Writeln('recv error: ', Ret);
        end;
        Exit;
      end;
      Inc(NumRead, Ret);
    until NumRead = Sizeof(Buffer);

    if not CompareMem(@Buf, @Buffer, SizeOf(Buffer)) then
    begin
      WriteLn('Buf does not match Buffer');
      Exit;
    end;

    WriteLn('Buf matches Buffer');
  finally
    closesocket(Sock);
  end;
end;

function StartServer(Port: Integer): Boolean;
var
  _wsdata: WSAData;
  serverSocket, S: TSocket;
  _addrIn, _addr: sockaddr_in;
  addrSize, Ret: Integer;
  tid: Cardinal;
  h: THandle;
begin
  Result := False;

  Ret := WSAStartup(MakeWord(2, 2), _wsdata);
  if Ret <> 0 then
  begin
    WriteLn('WSAStartup error: ', Ret);
    Exit;
  end;

  try
    serverSocket := socket(AF_INET, SOCK_STREAM, 0);
    if serverSocket = INVALID_SOCKET then
    begin
      Ret := WSAGetLastError;
      WriteLn('socket error: ', Ret);
      Exit;
    end;

    try
      _addrIn.sin_family := AF_INET;
      _addrIn.sin_addr.S_addr := INADDR_ANY;
      _addrIn.sin_port := htons(Port);

      if bind(serverSocket, _addrIn, SizeOf(_addrIn)) = SOCKET_ERROR then
      begin
        Ret := WSAGetLastError;
        WriteLn('bind error: ', Ret);
        Exit;
      end;

      if listen(serverSocket, SOMAXCONN) = SOCKET_ERROR then
      begin
        Ret := WSAGetLastError;
        WriteLn('listen error: ', Ret);
        Exit;
      end;

      addrSize := SizeOf(_addrIn);
      getsockname(serverSocket, _addrIn, addrSize);
      WriteLn('Listening on port ', ntohs(_addrIn.sin_port));

      while True do
      begin
        addrSize := SizeOf(_addr);
        S := accept(serverSocket, @_addr, @addrSize);
        if S <> INVALID_SOCKET then
        begin
          WriteLn('Client connected.');
          h := CreateThread(nil, 0, @ClientThread, Pointer(S), 0, tid);
          if h = 0 then
          begin
            Ret := GetLastError;
            closesocket(S);
            WriteLn('CreateThread error: ', Ret);
          end;
        end;
      end;
    finally
      closesocket(serverSocket);
    end;
  finally
    WSACleanup;
  end;

  Result := True;
end;
© www.soinside.com 2019 - 2024. All rights reserved.