WinSock:服务器未按客户端发送的相同顺序接收数据

时间:2019-04-29 02:39:05

标签: sockets delphi winsock delphi-10-seattle recv

我需要按照确定的顺序从 Client Server 发送数据,服务器也可以按照Client发送的相同顺序接收这些数据。在下面的代码中,存在一个问题,即像下一个数据的数据一样接收数据(即控制字节 1 )。

例如:

客户上,我有以下几封邮件发送 1 $sudo apt-get install php-mbstring $sudo apt-get install php-xml

Connection._Input

上面发送的该字节,在服务器上,正确的变量是在if SendInt(Sock, Ord(Connection._Input)) <= 0 then Exit; 变量上接收的,而在Check变量上却是接收的。

请参阅:

enter image description here

如何解决?

这是完整的代码:

客户:

dwC

服务器:

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.

1 个答案:

答案 0 :(得分:1)

客户端与服务器的数据大小不一致。

type
  Connection = (Desktop, _Input);

Delphi中枚举的默认大小为byte。这样做本身可以,但是您在客户端和服务器中对它们的处理方式不同。

您使用SendInt()函数从客户端发送消息,该函数将转换为整数。

在服务器端,您将以SizeOf(_connection)的形式接收它,它只是一个字节。由于字节顺序,1保留在缓冲区中,随后被读入dwC

您可以通过在项目选项中将Minimum enum size设置为doubleword或作为字节发送来纠正错误。


评论后编辑

实际上,您还有另一个错误或误解。

从您发送的客户端

SendInt(Sock, Ord(Connection._Input))

由服务器作为

接收
var
  Check: BOOL;
....
  recv(Sock, Check, SizeOf(Check), 0) , 

然后将其写为

Writeln(BoolToStr(Check)); 

,控制台显示“ -1”。但这不是错误,已记录在案:

System.SysUtils.BoolToStr

Value of B  Value of UseBoolStrs  Value of returned string  
  true        false                 '-1' 

也许您想将其显示为枚举值。