Reputation: 294
Well i have this code where i'm trying receive data from client but happens that GetLastError()
is returning:
10038 -
WSAENOTSOCK
An operation was attempted on something that is not a socket.
I suspect that this trouble is related with the casting Pointer
to TSocket
, already that ClientThread()
function below receives the socket througth your parameter.
How this can be solved?
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;
Usage:
StartServer(1234);
Upvotes: 1
Views: 703
Reputation: 595402
You are making several mistakes.
The signature of your ClientThread()
is wrong. It must be defined like this instead:
function ClientThread(P: Pointer): DWORD; stdcall;
Without the stdcall
, the P
parameter will not be passed in correctly.
you are passing a pointer to a local TSocket
variable to your threads. In your ClientThread()
, you are not dereferencing that pointer to access the original TSocket
, which is what is causing your error message.
But more importantly, you are reusing the same TSocket
variable for multiple client threads. All of your threads are pointing to the same physical TSocket
. Don't use the @
operator, pass a copy of the TSocket
to each client thread. Fortunately, TSocket
is just a UINT
, its value will fit as-is inside of a pointer.
And you need to close that TSocket
before the thread exits. You are not calling closesocket()
if CompareMem()
returns true.
you are leaking threads, as you never close the THandle
returned by CreateThread()
.
With that said, try this instead:
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;
Upvotes: 5