I need send data from Client to Server in a determinated sequence, where the Server can receive these data also on same sequence sent by Client. On code below exists a problem that a data (that is a byte of control, 1) is received like a data of next data.
Ex:
On Client i have the following piece that send 1 (Connection._Input
)
if SendInt(Sock, Ord(Connection._Input)) <= 0 then
Exit;
This byte sent above, on Server the correct is be received on Check
variable, but instead is received on dwC
.
See:
How can solve it?
Here is the complete code:
Client:
program _Client;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
WinSock,
SysUtils;
type
Connection = (Desktop, _Input);
const
SendBuf: array [0 .. 9] of AnsiChar = ('A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', #0);
function SendInt(S: TSocket; I: Integer): Integer;
begin
Result := send(S, I, SizeOf(I), 0);
end;
function ConnectServer: TSocket;
var
Wsa: WSAData;
Client: sockaddr_in;
S: TSocket;
Rslt: Integer;
begin
S := INVALID_SOCKET;
try
Rslt := WSAStartup(MakeWord(2, 2), Wsa);
if Rslt = NO_ERROR then
begin
S := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if S <> INVALID_SOCKET then
begin
Client.sin_family := AF_INET;
Client.sin_addr.s_addr := inet_addr('192.168.15.6');
Client.sin_port := htons(5099);
if connect(S, Client, SizeOf(Client)) <> SOCKET_ERROR then
Writeln('Connected successfully!');
end;
end;
except
Writeln(SysErrorMessage(WSAGetLastError));
end;
Result := S;
end;
function DesktopThread(P: Pointer): DWORD; stdcall;
var
Sock: TSocket;
dwC, dwD, dwE, dwF, dwG: DWORD;
A, B: Integer;
begin
Result := 0;
Sock := ConnectServer;
if send(Sock, SendBuf, SizeOf(SendBuf), 0) <= 0 then
Exit;
if SendInt(Sock, Ord(Connection.Desktop)) <= 0 then
Exit;
dwC := 111;
dwD := 222;
dwE := 333;
dwF := 444;
dwG := 555;
repeat
if recv(Sock, A, SizeOf(A), 0) <= 0 then
Exit;
if recv(Sock, B, SizeOf(B), 0) <= 0 then
Exit;
if SendInt(Sock, Ord(Connection._Input)) <= 0 then
Exit;
if SendInt(Sock, dwC) <= 0 then
Exit;
if SendInt(Sock, dwD) <= 0 then
Exit;
if SendInt(Sock, dwE) <= 0 then
Exit;
if SendInt(Sock, dwF) <= 0 then
Exit;
if SendInt(Sock, dwG) <= 0 then
Exit;
// Writeln(Format('%s', [SysErrorMessage(WSAGetLastError)]));
Writeln(Format('dwC: %d, dwD: %d, dwE: %d, dwF: %d, dwG: %d',
[dwC, dwD, dwE, dwF, dwG]));
until True;
end;
var
ThrId: Cardinal;
begin
try
CreateThread(nil, 0, @DesktopThread, nil, 0, ThrId);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Server:
program _Server;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
WinSock,
SysUtils;
type
Connection = (Desktop, Input, _End);
const
Buffer: array [0 .. 9] of AnsiChar = ('A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', #0);
function SendInt(S: TSocket; I: Integer): Integer;
begin
Result := send(S, I, SizeOf(I), 0);
end;
function ClientThread(P: Pointer): DWORD; stdcall;
var
Buf: array [0 .. SizeOf(Buffer) - 1] of AnsiChar;
Sock: TSocket;
Check: BOOL;
A, B: Integer;
_connection: Connection;
dwC, dwD, dwE, dwF, dwG: DWORD;
begin
Result := 0;
Sock := TSocket(P);
if recv(Sock, Buf, SizeOf(Buffer), 0) <= 0 then
begin
closesocket(Sock);
Result := 0;
Exit;
end;
if not CompareMem(@Buf, @Buffer, SizeOf(Buffer)) then
begin
closesocket(Sock);
Result := 0;
Exit;
end;
if recv(Sock, _connection, SizeOf(_connection), 0) <= 0 then
begin
closesocket(Sock);
Result := 0;
Exit;
end;
if _connection = Connection.Desktop then
begin
A := 666;
B := 777;
repeat
if SendInt(Sock, A) <= 0 then
Exit;
if SendInt(Sock, B) <= 0 then
Exit;
if recv(Sock, Check, SizeOf(Check), 0) <= 0 then
Exit;
Writeln(BoolToStr(Check));
{ if not Check then
continue; }
if recv(Sock, dwC, SizeOf(dwC), 0) <= 0 then
Exit;
if recv(Sock, dwD, SizeOf(dwD), 0) <= 0 then
Exit;
if recv(Sock, dwE, SizeOf(dwE), 0) <= 0 then
Exit;
if recv(Sock, dwF, SizeOf(dwF), 0) <= 0 then
Exit;
if recv(Sock, dwG, SizeOf(dwG), 0) <= 0 then
Exit;
// Writeln(Format('%s', [SysErrorMessage(WSAGetLastError)]));
Writeln(Format('dwC: %d, dwD: %d, dwE: %d, dwF: %d, dwG: %d',
[dwC, dwD, dwE, dwF, dwG]));
until True;
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, [ntohs(_addrIn.sin_port)]));
while True do
begin
S := accept(serverSocket, @_addr, @addrSize);
CreateThread(nil, 0, @ClientThread, Pointer(S), 0, tid);
end;
Result := True;
end;
begin
try
if not StartServer(5099) then
Writeln(SysErrorMessage(WSAGetLastError));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
You have a misalignment of data size in client vs server.
type
Connection = (Desktop, _Input);
Default size of an enumeration in Delphi is byte
. This is in itself OK, but you handle these differently in the client and the server.
You send from the client using your SendInt()
function which converts to integer.
On the server side you receive it as a SizeOf(_connection)
which is only a byte. Because of the byte order, the 1
remains in the buffer and is later read into dwC
.
You can correct the error either by setting Minimum enum size
in project options to doubleword
or by sending as byte.
Edit after comment
Indeed you also have another error, or maybe misunderstanding.
From the client you send
SendInt(Sock, Ord(Connection._Input))
which is received by the server as
var
Check: BOOL;
....
recv(Sock, Check, SizeOf(Check), 0) ,
Then you write it out as
Writeln(BoolToStr(Check));
and the console shows '-1'. But that is not an error, it is documented:
Value of B Value of UseBoolStrs Value of returned string
true false '-1'
Perhaps you want to show it as the enum value instead.