【问题标题】:TCP Socket Send works in Windows, 32bits, but not 64bitsTCP Socket Send 适用于 Windows,32 位,但不适用于 64 位
【发布时间】:2013-09-11 03:16:53
【问题描述】:

EDIT1:我已经在 win7x86 中尝试过它并且它有效。听起来肯定是 x64 问题...如何在 windows x64 机器上发送 TCP 套接字“x86”样式?

EDIT2:按照@RemyLebeau 的要求,附上了 *.pcap 文件而不是屏幕截图。

我有这个要发送到打印机的文本字符串,它不需要换行/CRLF/等来理解代码,这意味着,在每个单词到达另一端后它就会打印出来。

打印机是 RS232,但我使用 Advantech ADAM4577 Ethernet-RS232 网关来转换信号。我要做的就是打开一个到网关的 TCP 连接并吐出字符串,就是这个:

  ^XA~TA000~JSN^LT0^MMT^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3^MD10^JUS^LRN^CI0^XZ
  ^XA^LL0168
  ^PW272
  ^FT61,34^A0N,28,28^FH\^FD2053200863^FS
  ^BY2,3,91^FT47,138^BCN,,Y,N
  ^FD>;9678130580^FS
  ^PQ1,0,1,Y^XZ

我使用的是 Delphi,所以我尝试了 TClientSocket:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ScktComp, Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    ClientSocket1: TClientSocket;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  if not ClientSocket1.Active then
  begin
    ClientSocket1.Port := 9100;
    ClientSocket1.Host := '10.6.2.140';
    ClientSocket1.Address := '10.6.2.140';
    ClientSocket1.ClientType := ctNonBlocking;
    ClientSocket1.Open;
  end;

end;

procedure TForm2.Button2Click(Sender: TObject);
var
  zcode : string;
begin
 zcode :=  '^XA~TA000~JSN^LT0^MMT^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3^MD10^JUS^LRN^CI0^XZ' +
            '^XA^LL0168' +
            '^PW272' +
            '^FT61,34^A0N,28,28^FH\^FD2053200863^FS' +
            '^BY2,3,91^FT47,138^BCN,,Y,N' +
            '^FD>;9678130580^FS' +
            '^PQ1,0,1,Y^XZ';

  ClientSocket1.Socket.SendText(zcode);
end;

procedure TForm2.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
      ShowMessage(IntToStr(ErrorCode));
      ErrorCode := 0;
end;

end.

一段时间后我得到:

Socket Error 10053 (WSAECONNABORTED)

这是 x64 机器中过滤后的 pcap 文件: link

完全相同的程序,x86: link

与 TIdClientSocket 相同的文本: (UsaNagle 默认为 true,IpVersion 为 IPv4

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent,
  IdTCPConnection, IdTCPClient, Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    IdTCPClient1: TIdTCPClient;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  if not IdTCPClient1.Connected then
  begin
    IdTCPClient1.Host := '10.6.2.140';
    IdTCPClient1.Port := 9100;
    idTCPClient1.Connect;
  end;


end;

procedure TForm2.Button2Click(Sender: TObject);
var
  zcode : string;
begin
 zcode :=  '^XA~TA000~JSN^LT0^MMT^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3^MD10^JUS^LRN^CI0^XZ' +
            '^XA^LL0168' +
            '^PW272' +
            '^FT61,34^A0N,28,28^FH\^FD2053200863^FS' +
            '^BY2,3,91^FT47,138^BCN,,Y,N' +
            '^FD>;9678130580^FS' +
            '^PQ1,0,1,Y^XZ';

  IdTCPClient1.IOHandler.WriteLn(zcode);
end;

end.

pcap 文件,x64: link

完全相同的程序,x86: link

【问题讨论】:

  • 你的截图没用,无法阅读。将捕获导出为 .pcap 文件,以便其他人可以实际打开并查看它们。
  • @RemyLebeau 按您的要求编辑。提前致谢!
  • 下次自己预过滤 .pcap 文件。您不必导出捕获的所有内容,您可以导出过滤后的数据。
  • Indy 的 WriteLn() 在文本之后发送一个 CRLF。 TClientSocket 的SendText() 没有。改用 Indy 的 Write() 来匹配 TClientSocket 的行为。
  • 谢谢,尝试使用 Write(),结果相同。无论如何,打印机本身并不关心额外的 CRLF :)

标签: sockets windows-7 tcp windows-xp wireshark


【解决方案1】:

根据 .pcap 文件:

WinXPx86 系统正在执行以下操作:

发送:

^

被确认,然后发送:

XA~TA000~JSN^LT0^MMT^MNW^MTT^PON^PMN^LH0,0^JM

哪个被确认,然后发送:

A^PR3,3^MD10^JUS^LRN^CI0^XZ^XA^LL0168^PW272^FT61,34^A0N,28,28^FH\^FD2053200863^FS^BY2,3,91^FT47,138^BCN,,Y,N^FD>;9678130580^FS^PQ1,0,1,Y^XZ

哪个被确认,然后断开连接。

另一方面,Win7x64系统正在做以下事情:

发送:

^

哪个被确认,然后发送:

XA~TA000~JSN^LT0^MMT^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3^MD10^JUS^LRN^CI0^XZ^XA^LL

但在确认之前断开连接。

直到^LL 部分,他们正在发送准确的数据数据。但是,这项活动向我表明:

  1. 您的 x86 和 x64 代码可能使用也可能不使用相同的代码逻辑,因为它们使用不同的帧发送相同的 TCP 数据(尽管这可能与套接字内部使用的 Nagle 算法有关) .

  2. 在 Win7x64 上,套接字过早断开,这可能是一个编码问题,例如,如果您过早关闭 TClientSocket 以响应您的代码遇到的一些错误。

如果没有看到您的实际代码,就无法进一步解决此问题。否则,您应该在代码中添加一些日志记录,这样您就知道它在每个步骤中实际执行的操作(例如关闭套接字的时间和原因)。

【讨论】:

  • 雷米,感谢您的洞察力!但是,这些转储不是来自 Delphi 程序,而是来自 Hyperterminal 的“发送文本文件”。
  • 如果超级终端在 x64 下有问题,那么它很可能只是一个错误的 x64 实现。你说你在你的 Delphi 代码中遇到了类似的问题,你可以控制它,所以请显示该代码。您说您使用的是TClientSocket,您对其他套接字库(如 Indy、ICS 或 Synapse)有同样的问题吗?我很难相信 WinSock 本身会有这么多错误。
  • 非常感谢您迄今为止的帮助。我永远不会认为它可能是一个有问题的超级终端,哦,好吧!我为 ClientSocket 和 IdTCPClient 附加了新文件和代码。如您所见,它们都可以在 x86 中工作,而在 x64 中则完全不同。我还尝试在 IdTCPClient 上将 UseNagle 设置为 false,但它没有改变。
  • 查看最新的 .pcap 文件,我看到的唯一真正区别是 x64 TCP 标头比 x86 TCP 标头大 12 个字节。 x64 指定了 x86 没有的附加 TCP 选项。也许您的 RS232 网关设备没有正确处理这些额外的字节。我建议您设置一个单独的回显服务器并将您的 x86 和 x64 客户端连接到它。确保它能够正确接收客户端请求。如果是这样,那么您的问题肯定与 RS232 网关设备的问题有关。
  • 有没有办法强制我的系统使用与 x86 机器大小相同的标头?我怎么可能使这个“向后兼容”?问题肯定出在网关上,但如果我不能只切换硬件怎么办?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 2017-06-09
  • 1970-01-01
  • 2018-08-25
相关资源
最近更新 更多