Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 开始与客户沟通的好方法?_C++_C_Tcp_Network Programming - Fatal编程技术网

C++ 开始与客户沟通的好方法?

C++ 开始与客户沟通的好方法?,c++,c,tcp,network-programming,C++,C,Tcp,Network Programming,我的游戏和服务器的工作方式如下: typedef struct { uint32_t signature; uint32_t length; uint32_t message_num; } header_t; typedef struct { uint32_t foo; } message13_t; 我发送以我创建的格式编码的消息。它以“p”开头,后跟消息长度的整数,然后是消息 例:p3m15 消息长度为3字节。它对应于信息15。 然后

我的游戏和服务器的工作方式如下:

typedef struct {
    uint32_t    signature;
    uint32_t    length;
    uint32_t    message_num;
} header_t;

typedef struct {
    uint32_t    foo;
} message13_t;
我发送以我创建的格式编码的消息。它以“p”开头,后跟消息长度的整数,然后是消息

例:p3m15 消息长度为3字节。它对应于信息15。 然后解析消息,依此类推

它是为TCP设计的,可能只发送1个字节(因为TCP只需要发送至少8位)

我创建的这个消息协议非常轻量级,工作非常好,这就是为什么我在JSON或其他协议上使用它的原因

我主要关心的是,客户机和服务器应该如何开始对话

服务器希望客户端以我的格式发送消息。游戏总是这样

我遇到的问题是在端口1720上测试服务器时遇到的。有BitTorrent流量,我的服务器正在接收。这导致各种各样的随机“客户端”连接到我的服务器并发送随机垃圾

为了“解决”这个问题,我将其设置为客户机必须发送给我的第一个字符串是“Hello Server”

如果发送的第一个字节是!='H'或者如果他们向我发送了>12个字节,而它是!=“你好服务器”,然后我立即断开它们

这很有效。我只是想知道我是否做了一些有点幼稚的事情,或者是否有更标准的方法来处理:

-开始与服务器通信的客户端 -客户端通过Hello服务器检查,但在某个地方我收到一条无效消息。我可以假设我的应用程序永远不会发送无效消息。如果是这样的话,那将是一个bug。现在,如果我检测到一条无效消息,那么我将断开客户端

我注意到BitTorrent正在发送“!!”!!BitTorrent协议在每条消息之前。我应该那样做吗

任何关于这方面的建议,使它更安全,更安全,都会非常有帮助。
谢谢

也许在您的邮件中嵌入了一个神奇的数字字段

struct Message
{
    ...
    unsigned magic_number = 0xbadbeef3;
    ...
};

因此,在接收到某些内容后,您要做的第一件事是检查magic_number字段是否为0xbadbeef3。

通常,我会设计带有如下标题的协议:

typedef struct {
    uint32_t    signature;
    uint32_t    length;
    uint32_t    message_num;
} header_t;

typedef struct {
    uint32_t    foo;
} message13_t;
发送消息:

message13_t msg;
msg.foo = 0xDEADBEEF;

header_t hdr;
hdr.signature = 0x4F4C494D;         // "MILO"
hdr.length = sizeof(message13_t);
hdr.message_num = 13;

// Send the header
send(s, &hdr, sizeof(hdr), 0);

// Send the message data
send(s, &msg, sizeof(msg), 0);
header_t hdr;
char* buf;

// Read the header - all messages always have this
recv(s, &hdr, sizeof(hdr), 0);

// allocate a buffer for the rest of the message
buf = malloc(hdr.length);

// Read the rest of the message
recv(s, buf, hdr.length, 0);
接收消息:

message13_t msg;
msg.foo = 0xDEADBEEF;

header_t hdr;
hdr.signature = 0x4F4C494D;         // "MILO"
hdr.length = sizeof(message13_t);
hdr.message_num = 13;

// Send the header
send(s, &hdr, sizeof(hdr), 0);

// Send the message data
send(s, &msg, sizeof(msg), 0);
header_t hdr;
char* buf;

// Read the header - all messages always have this
recv(s, &hdr, sizeof(hdr), 0);

// allocate a buffer for the rest of the message
buf = malloc(hdr.length);

// Read the rest of the message
recv(s, buf, hdr.length, 0);

此代码显然没有错误检查或确保所有数据都已发送/接收。

使用ASCII指定消息长度,IMO是一个坏主意。通常,头的长度是固定的,因此您总是可以读取那么多字节。然后从报头获取(可变)长度,并继续读取那么多字节以获取数据包的其余部分。如果是ASCII格式,您如何知道最初要读取多少字节?端口号通常可以被视为procotol的一部分。许多协议通常链接到特定的端口号,如HTTP(80)、SMTP(25)。。。因此,您应该尝试使用其他应用程序未使用的端口号。与其过滤不可接受的端口号,我认为更好的做法是更严格地定义协议,只接受可接受的端口号(即,不要对
!!BitTorrent…
,因为端口冲突总是可能的)。如果这是在TCP之上完成的,那么您已经解释过的接纳协议似乎就可以了。如果您使用UDP(我想您不是在创建新的传输协议),您可能需要进行一些初始化握手。@JonathonReinhart:等待缓冲区包含足够的字节用于消息长度字段(例如,四个字节)没有多大区别或者等待,直到它包含“p”加上一些后跟“m”的数字。在最坏的情况下,在野外有一些协议
X1
,一些客户端
Y
在您自己的端口
Z
上使用,这看起来非常类似于您自己的协议X2,在编程上难以区分两者;只有更高级别的机制(如身份验证)才能过滤掉这一点。i、 e.如果协议
X1
恰好足够接近
X2
而不会破坏您的系统,是否仍然存在问题?否则,您能否改进您的系统,使其不受影响?我的观点是,您不能通过添加哨兵值和头帧来修复所有问题。我希望您的实际代码不会像此示例代码那样缺乏确保特定字节顺序的努力(我希望在某个地方会出现
htonl
调用或类似调用)。;-)