1

更新:私はそれを理解しました!種類...これでどのように修正されたかはわかりませんが、修正されました。使用する代わりに:

NetworkMessage msg;
msg.AddByte(0x01);
sendmessage(msg);

私はこれを試しましたが、うまくいきました(一部の機能にほとんど変更はありません)

NetworkMessage* msg = new NetworkMessage();
msg.AddByte(0x01);
sendmessage(msg);

これで修正されましたが、そもそもなぜこれが起こったのかについての説明をいただければ幸いです。マークを付けることができるように、回答として投稿してください。ありがとうございました。

私はTCPサーバーに取り組んできましたが、少し問題がありました。

約600を送信するループがありますか?メッセージ、一度に1つ送信(キューに入れられたメッセージリストから読み取る)。

何らかの理由で、約200がエラーなしでクライアントに到達すると、System.10014エラーが発生します。メッセージは毎回同じですが、毎回異なるメッセージで。また、System.10014エラーの後にメッセージを再送信するだけでも、正常に機能します。したがって、メッセージが問題ではないことは明らかです。しかし、私には何がわからない。私は昨日一日中それを理解しようとして過ごしましたが、それでも運がありません。だからここにいます。また。

void outputMessage(NetworkMessage& msg, bool forceTrue = false)
{
    if(!connectionLocked || forceTrue) {
        connectionLocked = true;

        std::cout << "Message: ";
        char* buf = msg.getOutputBuffer();
        for (int i = 0; i < msg.size(); i++){
            std::cout << (buf[i] + 0) << ":"; //Never any errors
        }

        boost::asio::async_write(socket_, boost::asio::buffer(msg.getOutputBuffer(), msg.size()),boost::bind(&Session::handle_write, shared_from_this(), msg, boost::asio::placeholders::error));

    }
    else {
        //Queue message
        _msgqueue.push_back(msg);
    }

}
void handle_write(NetworkMessage& msg, const boost::system::error_code& error)
{
    if (error)
    {
        cout << "Error: " << error << endl;
        outputMessage(msg, true); //works, even though it's the same message
    }
    else {
        if(_msgqueue.size() != 0){
            //cout << "Sending queued message #" << _msgqueue.size() << endl;
            outputMessage(_msgqueue.front(), true);
            _msgqueue.pop_front();
        }
        else
            connectionLocked = false;
    }
}

これは基本的に私の送信関数のコードです。通常は正常に動作します。どういうわけか、たくさんのメッセージを続けて送信していると、このエラー(System.10014)が発生します。Winsockのエラーについて読んでみましたが、本当にわかりません(無効なポインタについて何かを言っていますが、メッセージを再度送信しても問題ないので、メッセージが有効であると確信していますか?)。また、プログラミング、特にC ++とポインターの経験がほとんどないため、少し問題があります。

メッセージを生成するループは、このようになります。XとYが有効であることを確認したので、問題はないと確信しています。

map->cursor = map->begin;
while(map->cursor != NULL)
{
    //I'm not sure if pointers like this are supposed to be deleted?
    //I suck when it comes to memory management, and most other things :D
    Tile* tile = map->cursor->tile;
    if(tile){
        NetworkMessage msg;
        msg.AddByte(0x03);
        msg.AddByte(tile->posx);
        msg.AddByte(tile->posy);
        msg.AddByte(1);
        msg.AddByte(2);
        outputMessage(msg);
    }
    else
        break;
    map->cursor = map->cursor->next;

}

また、これは関連性がないように見えるかもしれませんが、outputMessageを次のように変更しようとすると:

void outputMessage(NetworkMessage& msg)
{
    boost::asio::async_write(socket_, boost::asio::buffer(msg.getOutputBuffer(), msg.size()),boost::bind(&Session::handle_write, shared_from_this(), msg, boost::asio::placeholders::error));
}
void handle_write(NetworkMessage& msg, const boost::system::error_code& error)
{
    if (error)
    {
        cout << "Error: " << error << endl;
    }
}

エラーは発生しませんが、送信されるメッセージはすべてクローンです。したがって、600のメッセージはすべて同じように見えます。変に見えたので、今抱えている問題に関係があるのではないかと思いました。

また、ここにNetworkMessage.hがあります。コメントで確認できるように、pastebinにも投稿しました。

#ifndef _NETWORK_MESSAGE_H
#define _NETWORK_MESSAGE_H
class NetworkMessage
{
    public:
        enum { header_length = 2 };
        enum { max_body_length = NETWORKMESSAGE_MAXSIZE - header_length};
        NetworkMessage()
        {
            buf_size=0;
            m_ReadPos=header_length;
        }
        void AddByte(char byte_)
        {
            if (!canAdd(1)) return;
            data_[m_ReadPos++] = byte_;
            //data_[m_ReadPos] = '\0';
            buf_size++;
        }
        uint16_t PeekU16(){
            return (data_[1] | uint16_t(data_[0]) << 8);
        }
        uint16_t GetU16(){
            m_ReadPos += 2;
            return (data_[m_ReadPos+1]) | (uint16_t(data_[m_ReadPos]) << 8);
        }

        uint8_t  GetByte(){return data_[m_ReadPos++];}
        char* getBuffer()
        {
            return (char*)&data_[m_ReadPos];
        }
        char* getOutputBuffer()
        {
            writeMessageLength();
            return (char*)&data_[0];
        }

        void setMessageLength(uint16_t v)
        {
            buf_size=v;
        }
        void writeMessageLength()
        {
            *(uint8_t*)(data_) = (buf_size >> 8);
            *(uint8_t*)(data_+1) = buf_size;
        }
        void reset()
        {
            m_ReadPos = 0;
            buf_size = 0;
        }
        uint16_t size(){return buf_size+header_length;}
    protected:
        inline bool canAdd(uint32_t size)
        {
            return (size + m_ReadPos < max_body_length);
        };
    private:
        uint8_t data_[NETWORKMESSAGE_MAXSIZE];
        uint16_t buf_size;
        uint16_t m_ReadPos;
};
#endif //_NETWORK_MESSAGE_H

更新:申し分なく、奇妙な何かに出くわしました...

function error_func(NetworkMessage& msg){
    cout << &msg << endl; //0x2882e8(not 0x274c0e8)
    send(msg.getOutputBuffer(), msg.size(), error_func, msg); //no error
}
cout << &msg << endl; //0x274c0e8
send(msg.getOutputBuffer(), msg.size(), error_func, msg); //error system.10014

明らかにこれは実際のコードではありませんが、あなたはその考えを理解しています...これがerror_funcからの再送信が機能する理由だと思います。結局のところ、問題はNetworkMessageにある可能性があります。私はずっと間違った場所をいじっています:Dそれでも助けが必要です、笑。

本当に助けていただければ幸いです、私は立ち往生しています。ここまで来たら読んでくれてありがとう。

4

1 に答える 1

3
void outputMessage(NetworkMessage& msg, bool forceTrue = false)
{
    if(!connectionLocked || forceTrue) {
        connectionLocked = true;

        std::cout << "Message: ";
        char* buf = msg.getOutputBuffer();
        for (int i = 0; i < msg.size(); i++){
            std::cout << (buf[i] + 0) << ":"; //Never any errors
        }

        boost::asio::async_write(socket_, boost::asio::buffer(msg.getOutputBuffer(), msg.size()),boost::bind(&Session::handle_write, shared_from_this(), msg, boost::asio::placeholders::error));

    }
    else {
        //Queue message
        _msgqueue.push_back(msg);
    }
}

に渡されるバッファasync_writeは、操作の間ずっと有効である必要があります。ドキュメントはここで非常に明示的です

書き込まれるデータを含む 1 つ以上のバッファー。buffers オブジェクトは必要に応じてコピーできますが、基になるメモリ ブロックの所有権は呼び出し元によって保持されます。呼び出し元は、ハンドラーが呼び出されるまでそれらが有効であることを保証する必要があります。

オブジェクトが破棄されたときに無効になったポインターを渡しました。これは、操作が完了NetworkMessageする前であると推測しています。完了ハンドラに渡されると、オブジェクトがコピーされますasync_writeNetworkMessagehandle_write()

于 2012-04-13T21:46:36.903 に答える