通过套接字 c++/cli 对 AT 命令的错误响应

Wrong response to AT command via socket c++/cli

我想创建一个简单的套接字,通过 AT 命令与另一个设备通信。

我在 Visual 2017 上使用 C++/CLI。

这是我的代码

#include "stdafx.h"
#include <conio.h>

using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::IO;

int main(array<System::String ^> ^args)
{
    int bufferSize = 1024;
    array<Byte>^ sendBuffer = gcnew array<Byte>(bufferSize);
    array<Byte>^ recvBuffer = gcnew array<Byte>(bufferSize);


    try {
        // Establish the remote endpoint for the socket.  
        IPHostEntry^ ipHostInfo = Dns::Resolve("192.168.1.1");
        IPAddress^ ipAddress = ipHostInfo->AddressList[0];
        IPEndPoint^ remoteEP = gcnew IPEndPoint(ipAddress, 1234);

        // Create a TCP/IP  socket.  
        Socket^ socket = gcnew Socket(AddressFamily::InterNetwork,SocketType::Stream, ProtocolType::Tcp);

        // Connect the socket to the remote endpoint. Catch any errors.  
        try {
            socket->Connect(remoteEP);

            // Encode the data string into a byte array.  
            array<Byte>^ msg = Text::Encoding::ASCII->GetBytes("AT");

            // Send the data through the socket.  
            int bytesSent = socket->Send(msg);

            // Receive the response from the remote device.  
            int bytesRec = socket->Receive(recvBuffer);
            Console::WriteLine("Echoed test = {0}", Text::Encoding::ASCII->GetString(recvBuffer, 0, bytesRec));

            // Release the socket.  
            socket->Shutdown(SocketShutdown::Both);
            socket->Close();

        }
        catch (ArgumentNullException^ ane) {
            Console::WriteLine("ArgumentNullException : {0}", ane->ToString());
        }
        catch (SocketException^ se) {
            Console::WriteLine("SocketException : {0}", se->ToString());
        }
        catch (Exception^ e) {
            Console::WriteLine("Unexpected exception : {0}", e->ToString());
        }

    }
    catch (Exception^ e) {
        Console::WriteLine(e->ToString());
    }

    _getch();
    return 0;
}

那里的命令,响应是:

Echoed test = ????????

在 ASCII 中有奇怪的值:255,251,3,255,251,1,255,254,1,255,253

答案应该是 OK 或 ERROR

我在 192.168.1.1 1234 上通过 Telnet 测试它,它工作正常。

标准警告:虽然可以用 C++/CLI 编写应用程序的主体,但不推荐这样做。 C++/CLI 适用于互操作场景:在 C# 或其他 .Net 代码需要与非托管 C++ 交互的情况下,C++/CLI 可以提供两者之间的转换。初级开发,如果要托管代码,建议使用C#,如果要非托管代码,建议使用C++。


也就是说...

与普遍看法相反,telnet 协议不是原始 TCP 套接字。有一个用于在 telnet 客户端之间通信选项的协议。

您看到的是从服务器发送的 telnet 命令。这些将由您的 telnet 客户端接收,并用于修改它的行为方式。这就是当您使用真正的 telnet 客户端时一切正常的原因:它获取这些字节并正确解释命令。

我阅读了几分钟的 Telnet 规范,这是我能够从您发布的数据中解码出来的内容:

  • 255:IAC,“解释为命令”。这是所有 Telnet 命令的转义字符。
  • 251: WILL: 表明服务器想要to/is执行一个选项。
  • 3: SUPPRESS-GO-AHEAD:显然 Telnet 默认是半双工协议,“Go Ahead”是一方告诉另一方“好的,轮到你了”的标记。此选项将其变成全双工连接。
  • 255:IAC
  • 251:将
  • 1: ECHO: 表示服务器将回显它接收到的字符。
  • 255:IAC
  • 254: DON'T: 表示服务器请求客户端不要做某事。
  • 1: ECHO:表示服务器希望客户端不回显接收到的字符。
  • 255:IAC
  • 253: DO: 表明服务器希望客户端打开一些选项。

好的,现在我们知道发生了什么,我们如何解决这个问题?我看到几个选项:

  • 你说你想使用“AT 命令”与设备对话。 AT 命令是您用来与调制解调器通信的命令。我假设您有一些串行设备,可能是调制解调器,您已经连接到一个将串行端口公开为 TCP 连接的小型转换器设备。如果是这样,那么该转换器设备可能有一些选项可以禁用 Telnet 协议,并将其公开为“原始”或类似的东西。如果这是真的,那么这可能是最好的选择。
  • 您可以在程序中添加代码以查找 IAC 字节,并处理它后面的字节。如果只是连接开始时的几个命令,那么你可以期待那些固定的字节;如果命令是在连接期间发送的,则您需要在任何地方处理它们。这取决于你有多想处理它们。 (例如,如果服务器说 DON'T SUPPRESS-GO-AHEAD,你会发送继续命令吗?理想情况下你会,但如果你的特定连接从未这样说,那么可能不会。)
  • 可能有一个 telnet 库可以为您处理协议内容。我没有搜索过这个。

Telnet 引用: