构建和发送网络上的二进制数据 [英] Constructing and sending binary data over network

查看:134
本文介绍了构建和发送网络上的二进制数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建的Minecraft一个命令行客户端。有对协议的全面规范,可以在这里找到: http://mc.kev009.com/Protocol。事先回答你的问题,是的,我有点C ++的小白。

I am creating a command-line client for minecraft. There is a full spec on the protocol that can be found here: http://mc.kev009.com/Protocol. To answer your question beforehand, yes I am a bit of a C++ noob.

我已经在执行这一协议,各种问题,其中每一个关键。

I have various issues in implementing this protocol, of which each critical.


  1. 的协议说,所有类型是大端。我不知道我应该怎么检查我的数据是否是小端,如果是如何转换为大端。

  2. 的字符串数据类型是有点不可思议的。这是一个UTF-8修改字符串,它是包含字符串的长度短pceded $ P $。我不知道我应该怎么收拾这个成一个简单的char []数组也没怎么我的简单的字符串转换为UTF-8修改的。

  3. 就算我知道怎么我的数据转换为big-endian和创建UTF-8修改字符串,我还是不知道如何收拾这个成一个char []数组,并发送此作为一个包。所有我以前做的是简单的HTTP网络这是纯ASCII。

解释,链接,相关函数名称和简短片段多少AP preciated!

Explanations, links, related function names and short snippets much appreciated!

修改

1和3现在回答。 1由user470379如下回答。 3由该真棒线程解释了我想要做的非常好回答:<一href=\"http://cboard.cprogramming.com/networking-device-communication/68196-sending-non-char%2a-data.html\" rel=\"nofollow\">http://cboard.cprogramming.com/networking-device-communication/68196-sending-non-char*-data.html我不知道对UTF-8修改尚未虽然。

1 and 3 is answered now. 1 is answered below by user470379. 3 is answered by this AWESOME thread that explains what I want to do very well: http://cboard.cprogramming.com/networking-device-communication/68196-sending-non-char*-data.html I'm not sure about the modified UTF-8 yet though.

推荐答案

一个传统的方法是定义为每个协议消息的C ++消息结构和实现序列化和反序列化功能了。例如登录请求可以重新psented这样的$ P $:

A traditional approach is to define a C++ message structure for each protocol message and implement serialization and deserialization functions for it. For example Login Request can be represented like this:

#include <string>
#include <stdint.h>

struct LoginRequest
{
    int32_t protocol_version;
    std::string username;
    std::string password;
    int64_t map_seed;
    int8_t dimension;
};

现在序列化功能是必需的。首先它需要整数和字符串系列化的功能,因为这些成员在 LoginRequest 的类型。

Now serialization functions are required. First it needs serialization functions for integers and strings, since these are the types of members in LoginRequest.

整数序列化功能,需要做的转换和从大端再presentation。由于消息的成员被复制到和从缓冲器,字节顺序的逆转可以做复制时:

Integer serialization functions need to do conversions to and from big-endian representation. Since members of the message are copied to and from the buffer, the reversal of the byte order can be done while copying:

#include <boost/detail/endian.hpp>
#include <algorithm>

#ifdef BOOST_LITTLE_ENDIAN

    inline void xcopy(void* dst, void const* src, size_t n)
    {
        char const* csrc = static_cast<char const*>(src);
        std::reverse_copy(csrc, csrc + n, static_cast<char*>(dst));
    }

#elif defined(BOOST_BIG_ENDIAN)

    inline void xcopy(void* dst, void const* src, size_t n)
    {
        char const* csrc = static_cast<char const*>(src);
        std::copy(csrc, csrc + n, static_cast<char*>(dst));
    }

#endif

// serialize an integer in big-endian format
// returns one past the last written byte, or >buf_end if would overflow
template<class T>
typename boost::enable_if<boost::is_integral<T>, char*>::type serialize(T val, char* buf_beg, char* buf_end)
{
    char* p = buf_beg + sizeof(T);
    if(p <= buf_end)
        xcopy(buf_beg, &val, sizeof(T));
    return p;
}

// deserialize an integer from big-endian format
// returns one past the last written byte, or >buf_end if would underflow (incomplete message)
template<class T>
typename boost::enable_if<boost::is_integral<T>, char const*>::type deserialize(T& val, char const* buf_beg, char const* buf_end)
{
    char const* p = buf_beg + sizeof(T);
    if(p <= buf_end)
        xcopy(&val, buf_beg, sizeof(T));
    return p;
}

和字符串(处理 UTF-8修改为ASCIIZ字符串的方法相同):

And for strings (handling modified UTF-8 the same way as asciiz strings):

// serialize a UTF-8 string
// returns one past the last written byte, or >buf_end if would overflow
char* serialize(std::string const& val, char* buf_beg, char* buf_end)
{
    int16_t len = val.size();
    buf_beg = serialize(len, buf_beg, buf_end);
    char* p = buf_beg + len;
    if(p <= buf_end)
        memcpy(buf_beg, val.data(), len);
    return p;
}

// deserialize a UTF-8 string
// returns one past the last written byte, or >buf_end if would underflow (incomplete message)
char const* deserialize(std::string& val, char const* buf_beg, char const* buf_end)
{
    int16_t len;
    buf_beg = deserialize(len, buf_beg, buf_end);
    if(buf_beg > buf_end)
        return buf_beg; // incomplete message
    char const* p = buf_beg + len;
    if(p <= buf_end)
        val.assign(buf_beg, p);
    return p;
}

和几个帮手函子的:

struct Serializer
{
    template<class T>
    char* operator()(T const& val, char* buf_beg, char* buf_end)
    {
        return serialize(val, buf_beg, buf_end);
    }
};

struct Deserializer
{
    template<class T>
    char const* operator()(T& val, char const* buf_beg, char const* buf_end)
    {
        return deserialize(val, buf_beg, buf_end);
    }
};

现在使用这些原始函数,我们可以很容易地序列化和反序列化 LoginRequest 消息:

Now using these primitive functions we can readily serialize and deserialize LoginRequest message:

template<class Iterator, class Functor>
Iterator do_io(LoginRequest& msg, Iterator buf_beg, Iterator buf_end, Functor f)
{
    buf_beg = f(msg.protocol_version, buf_beg, buf_end);
    buf_beg = f(msg.username, buf_beg, buf_end);
    buf_beg = f(msg.password, buf_beg, buf_end);
    buf_beg = f(msg.map_seed, buf_beg, buf_end);
    buf_beg = f(msg.dimension, buf_beg, buf_end);
    return buf_beg;
}

char* serialize(LoginRequest const& msg, char* buf_beg, char* buf_end)
{
    return do_io(const_cast<LoginRequest&>(msg), buf_beg, buf_end, Serializer());
}

char const* deserialize(LoginRequest& msg, char const* buf_beg, char const* buf_end)
{
    return do_io(msg, buf_beg, buf_end, Deserializer());
}

使用上面并重新presenting输入/输出缓冲器为字符中的iterator范围只需要一个函数模板做的序列化和反序列化消息的帮手函子

Using the helper functors above and representing input/output buffers as char iterator ranges only one function template is required to do both serialization and deserialization of the message.

和把所有在一起,用法:

And putting all together, usage:

int main()
{
    char buf[0x100];
    char* buf_beg = buf;
    char* buf_end = buf + sizeof buf;

    LoginRequest msg;

    char* msg_end_1 = serialize(msg, buf, buf_end);
    if(msg_end_1 > buf_end)
        ; // more buffer space required to serialize the message

    char const* msg_end_2 = deserialize(msg, buf_beg, buf_end);
    if(msg_end_2 > buf_end)
        ; // incomplete message, more data required
}

这篇关于构建和发送网络上的二进制数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆