1

在我的客户端服务器应用程序中,我想知道如何制作一个数据包并通过客户端将其发送到服务器

然后在服务器上我识别出这是哪个数据包并发送正确的重播

但是突然间我遇到了这个话题,这让我担心我是否会陷入这个问题

问题

对于为 TCP/IP 设计协议的人来说,最常见的初学者错误之一是他们假设消息边界被保留。例如,他们假设单个“发送”将导致单个“接收”。

部分 TCP/IP 文档应归咎于此。许多人读到 TCP/IP 如何保存数据包——在必要时将它们拆分,并在接收端重新排序和重新组装它们。这是完全正确的;但是,单个“发送”不会发送单个数据包。

本地机器(环回)测试证实了这种误解,因为通常当客户端和服务器在同一台机器上时,它们的通信速度足够快,以至于单个“发送”实际上对应于单个“接收”。不幸的是,这只是一个巧合。

当尝试将解决方案部署到 Internet(增加客户端和服务器之间的延迟)或尝试发送大量数据(需要分段)时,通常会出现此问题。不幸的是,此时项目通常处于最后阶段,有时甚至已经发布了应用协议!

真实故事:我曾经在一家开发定制客户端/服务器软件的公司工作。最初的通信代码犯了这个常见的错误。但是,它们都在具有高端硬件的专用网络上,因此根本问题很少发生。当它发生时,运营商只会将其归结为“那个有问题的 Windows 操作系统”或“另一个网络故障”并重新启动。我在这家公司的一项任务是改变沟通方式以包含更多信息;当然,这导致问题经常出现,并且必须更改整个应用程序协议才能解决它。真正令人惊奇的是,这个软件已经在无数的 24x7 自动化系统中使用了 20 年;它从根本上被破坏了,没有人注意到。

那么我怎么能发送类似 AUTH_CALC,VALUE1=10,VALUE2=12 的数据包并以安全的方式从服务器接收它......

如果你想要一个我在这里做的例子,它在下面

[客户]

Send(Encoding.ASCII.GetBytes("1001:UN=user123&PW=123456")) //1001 is the ID

[服务器]

private void OnReceivePacket(byte[] arg1, Wrapper Client)
{
    try
    {
        int ID;
        string V = Encoding.ASCII.GetString(arg1).Split(':')[0];
        int.TryParse(V, out ID);

        switch (ID)
        {
            case 1001://Login Packet
                AppendToRichEditControl("LOGIN PACKET RECEIVED");
                break;

            case 1002:
                //OTHER IDs
                break;

            default:
                break;
        }
    }
    catch { }         
}

那么这是构造消息并在服务器上处理它的好方法吗?

另外,使用 ASCII 或 UTF8 哪种编码更好?

4

1 回答 1

1

最好的方法是使用长度指示器。假设你正在发送一个 10000 字节的文件,首先发送文件的长度并从另一端接收 ack 即“OK”字符串,然后继续逐块发送 10,000 字节(可能你可以占用 4096 字节)。每次发送 4096 个字节,分两次发送,最后一个块发送 2000 个奇数字节。在接收方,无法保证一次发送您将收到整个 4096 字节,因此您需要等到您获得 4096 字节,然后继续下一个 4096 字节。

于 2012-09-10T05:54:56.633 回答