TCP 套接字 - 发送控制字符

TCP socket - sending control characters

我正在尝试通过 TCP/IP 协议连接到不是 Delphi 中制作的程序,但我没有关于如何操作的文档。

使用 Delphi 中创建的服务,我监视了程序的两个客户端之间的通信,并将 sendt 文本写入文件,因此我可以在我的 Delphi 程序中播放它。

我设法发送了一些东西,但问题是我必须提供以下文本:

SOH NUL ÜÜ NUL ENQ NUL Data ENQ NUL NUL NUL SOH NUL NUL NUL NUL 557

我看到字符串部分有特殊字符,发送这些数据时遇到问题。

我尝试将其作为字符串发送并放入 ASCII 值,但特殊字符不起作用。

这是我的部分代码:

TCPClient := TIdTCPClient.Create(nil);
TCPClient.Host := edtIP.Text;
Memo1.Lines.Clear;

TCPClient.Port := PORT;
TCPClient.ConnectTimeout := 20000;
TCPCliente.Connect;
Memo1.Lines.Add('Conectado con el Sevidor');

TCPClient.Socket.ReadTimeout := 20000;

edtTextoEnvio.Text := edtVersion.Text+' '+edtIP.Text+' '+
      edtAlias.Text+' '+edtFuncion.Text+' 'edtPassword.Text;

TCPClient.Socket.WriteLnRFC(edtTextoEnvio.Text, IndyTextEncoding_8Bit);
Memo1.Lines.Add('Mensaje Enviado: '+edtTextoEnvio.Text);
TextoRecibido := TCPCliente.Socket.ReadLn(IndyTextEncoding_8Bit);
Memo1.Lines.Add('Mensaje Recibido: '+TextoRecibido);
TCPCliente.Socket.WriteLnRFC(NUNProc, IndyTextEncoding_8Bit);
Memo1.Lines.Add('Mensaje Enviado: '+NUNProc);

envioMensaje:= Char(1)+ Char(0)+'ÜÜ'+ Char(0)+ Char(5)+Char(0)+'Data'+Char()5)+Char(0)+Char(0)+Char(0)+Char(1)+CHar(0)+Char(0)+Char(0)+Char(0)+'557';
TCPCliente.Socket.WriteLnRFC(envioMensaje, IndyTextEncoding_8Bit); //here is the problem
TextoRecibido := TCPCliente.Socket.ReadLn(IndyTextEncoding_8Bit);
Memo1.Lines.Add('Mensaje Recibido: '+TextoRecibido);

您要发送的某些字符串值中包含非ASCII 字符,但套接字没有文本概念,只有字节。您必须使用适当的字符集将字符串编码为字节,然后您可以根据需要发送字节。 Indy 具有内置功能来为您处理这些问题(例如 TIdIOHandler.DefStringEncoding 属性,以及基于字符串的 TIdIOHandler.Write...()TIdIOHandler.Read...() 方法的 AByteEncoding 参数).您正在尝试考虑到这一点,但是您使用了错误的 Indy 编码来做到这一点。 IndyTextEncoding_8bit 并不是真正的字符集,它主要用作在基于文本的协议中处理 8 位二进制数据的变通方法,不应在一般代码中使用。您需要做的是确定对方希望您使用的实际字符集。不同的字符集以不同的方式(如果有的话)对相同的非 ASCII 字符进行编码,因此您和另一方必须同意使用相同的字符集来对字符串进行编码和解码,否则您将丢失数据。

话虽如此,在 Indy 中有不同的方法可以完成您的尝试。鉴于您显示的数据(如果您显示的数据是由您的监控服务实际捕获的,或者来自像 Wireshark 这样的数据包嗅探器的数据会更好),至少我会建议更像以下内容:

TCPClient := TIdTCPClient.Create(nil);
TCPClient.Host := edtIP.Text;
TCPClient.Port := PORT;
TCPClient.ConnectTimeout := 20000;
TCPClient.ReadTimeout := 20000;

Memo1.Lines.Clear;

TCPClient.Connect;
TCPClient.IOHandler.DefStringEncoding := CharsetToEncoding('ISO-8859-1'); // <-- this is just a guess!

Memo1.Lines.Add('Conectado con el Sevidor');

edtTextoEnvio.Text := edtVersion.Text + ' ' + edtIP.Text + ' ' + edtAlias.Text + ' ' + edtFuncion.Text + ' ' + edtPassword.Text;

TCPClient.IOHandler.WriteLn(edtTextoEnvio.Text);
Memo1.Lines.Add('Mensaje Enviado: ' + edtTextoEnvio.Text);
TextoRecibido := TCPClient.IOHandler.ReadLn;
Memo1.Lines.Add('Mensaje Recibido: ' + TextoRecibido);
TCPClient.IOHandler.WriteLn(NUNProc);
Memo1.Lines.Add('Mensaje Enviado: ' + NUNProc);

TCPClient.IOHandler.WriteBufferOpen;
try
  TCPClient.IOHandler.Write(Byte(1));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write('ÜÜ');
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(5));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write('Data');
  TCPClient.IOHandler.Write(Byte(5));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(1));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write('557');
  TCPClient.IOHandler.WriteLn;
  TCPClient.IOHandler.WriteBufferClose;
except
  TCPClient.IOHandler.WriteBufferCancel;
  raise;
end;

TextoRecibido := TCPClient.IOHandler.ReadLn;
Memo1.Lines.Add('Mensaje Recibido: ' + TextoRecibido);

也就是说,所有这些 nul 字节更有可能是多字节二进制整数的一部分,您可以使用 TIdIOHandler.Write(Int16)TIdIOHandler.Write(Int32) 等发送它们:

TCPClient.IOHandler.WriteBufferOpen;
try
  {
  TCPClient.IOHandler.Write(Byte(1));
  TCPClient.IOHandler.Write(Byte(0));
  }
  TCPClient.IOHandler.Write(Int16(1), False);

  TCPClient.IOHandler.Write('ÜÜ');
  TCPClient.IOHandler.Write(Byte(0));

  {
  TCPClient.IOHandler.Write(Byte(5));
  TCPClient.IOHandler.Write(Byte(0));
  }
  TCPClient.IOHandler.Write(Int16(5), False);

  TCPClient.IOHandler.Write('Data');

  {
  TCPClient.IOHandler.Write(Byte(5));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  }
  TCPClient.IOHandler.Write(Int32(5), False);

  {
  TCPClient.IOHandler.Write(Byte(1));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write(Byte(0));
  }
  TCPClient.IOHandler.Write(Int32(1), False);

  TCPClient.IOHandler.Write(Byte(0));
  TCPClient.IOHandler.Write('557');
  TCPClient.IOHandler.WriteLn;
  TCPClient.IOHandler.WriteBufferClose;
except
  TCPClient.IOHandler.WriteBufferCancel;
  raise;
end;

ÜÜ也很可疑。它很可能实际上不是 ÜÜ 字符串,而更可能只是字节 $DC $DC、2 个 8 位 220 值、一个 16 位 56540 值等。

没有关于实际通信协议的明确文档,您只是在猜测,有时您很可能会猜错。所以我强烈建议您联系其他客户端应用程序的作者并索取文档。或者在线搜索并查看第 3 方是否已经为该应用程序编写了此类文档。否则你只是盲目编码,这不是好的选择。