winsock,面向消息的网络,以及从recv中类型转换缓冲区

winsock, message oriented networking, and type-casting the buffer from recv

本文关键字:recv 类型转换 缓冲区 网络 消息 winsock      更新时间:2023-10-16

好吧,实际上我还没有代码,因为我只是暂时挑选一个框架,但我仍然有点困惑于我希望如何实现这一点:。

在服务器端,我希望有一个类,其中每个实例都有一个套接字和标识每个连接的各种信息。每个对象都有自己的线程来接收数据。我知道我将如何实现其中的大部分,但我的困惑始于服务器和客户端之间的实际数据传输。对于特定的情况,我想要一堆不同的消息结构(例如CONNECT_MSG、DISCONNECT_MSG、POSTTEXT_MSG等),然后我所要做的就是在该结构上有一个char*点,然后通过send()函数传递它。

但我想,在这一点上,它变得有点复杂。这些不同的消息类型中的任何一种都可以发送,在接收端,你都不知道应该将传入缓冲区强制转换为什么。我希望做的是,在每个连接对象的线程中,阻止它,直到它接收到带有消息的数据包,然后将其转储到服务器管理的单个队列对象中(互斥将防止贪婪),然后服务器将独立于连接对象以FIFO顺序处理每条消息。

我还没有写任何东西,但让我写一些东西来说明我的设置。

#define CONNECT 1000
struct GENERIC_MESSAGE
{
    int id;
}
struct CONNECT_MESSAGE : public GENERIC_MESSAGE
{
    m_username;
}
void Connection::Thread()
{
    while(1)
    {
         char buffer[MAX_BUFFER_SIZE];    // some constant(probably 2048)
         recv(m_socket, buffer, MAX_BUFFER_SIZE, 0);
         MESSAGE_GENERIC * msg = reinterpret_cast<MESSAGE_GENERIC *> (buffer);
         server->queueMessage(msg);
    }
}
void Server::QueueMessage(MESSAGE_GENERIC * msg)
{
    messageQueue.push(msg);
}
void Server::Thread()
{
    while(1)
    {
         if(!messageQueue.empty())
              ProcessMessages();
         else
              Sleep(1);
    }
}
void Server::ProcessMessages()
{
     for(int i = 0; i < messageQueue.size(); i++)
     {
          switch(messageQueue.front()->id)
          {
                case CONNECT:
                {
                     // the part i REALLY don't like
                     CONNECT_MESSAGE * msg = static_cast<CONNECT_MESSAGE *>(messageQueue.front() );
                     // do the rest of the processing on connect
                     break;
                }
                // other cases for the other message types
          }
          messageQueue.pop();
     }
}

现在,如果你一直在跟踪到现在,你就会意识到这是多么的STUPID和脆弱。它强制转换到基类,将指针传递到队列,然后假设该指针在其他线程中仍然有效,即使这样,派生类的其余部分的指针之后的剩余缓冲区在强制转换之后是否始终有效,但我还没有找到正确的方法。我对任何建议都持开放态度,无论是让它发挥作用,还是采用完全不同的消息设计。

在编写一行代码之前,请设计将在有线网络上使用的协议。决定在字节级别上消息将由什么组成。决定谁先发送,消息是否被确认,接收者如何识别消息边界,等等。决定连接将如何保持活动(如果会),哪一边将首先关闭,等等。然后围绕规范编写代码。

不要把你在内存中存储东西的方式和你在网络上发送东西的方式紧密联系在一起。这是两个非常不同的东西,有两组非常不同的要求。

当然,在编写代码时可以随意调整协议规范。