Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.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++ winsock,面向消息的网络,并从recv类型转换缓冲区_C++_Visual C++_Winsock2 - Fatal编程技术网

C++ winsock,面向消息的网络,并从recv类型转换缓冲区

C++ winsock,面向消息的网络,并从recv类型转换缓冲区,c++,visual-c++,winsock2,C++,Visual C++,Winsock2,好的,我实际上还没有代码,因为我只是暂时挑选一个框架,但我仍然有点困惑,不知道我想怎么做: 在服务器端,我希望有一个类,其中每个实例都有一个套接字和标识每个连接的各种信息。每个对象都有自己的线程来接收数据。我知道我将如何实现其中的大部分,但我的困惑开始于服务器和客户端之间的实际数据传输。我希望在特定情况下有一组不同的消息结构(例如CONNECT\u MSG、DISCONNECT\u MSG、POSTTEXT\u MSG等),然后我所要做的就是在该结构上有一个char*点,然后通过send()函数

好的,我实际上还没有代码,因为我只是暂时挑选一个框架,但我仍然有点困惑,不知道我想怎么做:

在服务器端,我希望有一个类,其中每个实例都有一个套接字和标识每个连接的各种信息。每个对象都有自己的线程来接收数据。我知道我将如何实现其中的大部分,但我的困惑开始于服务器和客户端之间的实际数据传输。我希望在特定情况下有一组不同的消息结构(例如CONNECT\u MSG、DISCONNECT\u MSG、POSTTEXT\u 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();
     }
}
#定义连接1000
结构泛型消息
{
int-id;
}
结构连接消息:公共通用消息
{
m_用户名;
}
无效连接::线程()
{
而(1)
{
char buffer[MAX_buffer_SIZE];//某个常量(可能是2048)
recv(m_插槽,缓冲区,最大缓冲区大小,0);
消息\u GENERIC*msg=reinterpret\u cast(缓冲区);
服务器->队列消息(msg);
}
}
void Server::QueueMessage(MESSAGE_GENERIC*msg)
{
messageQueue.push(msg);
}
void服务器::线程()
{
而(1)
{
如果(!messageQueue.empty())
ProcessMessages();
其他的
睡眠(1);
}
}
void服务器::ProcessMessages()
{
对于(int i=0;iid)
{
案例连接:
{
//我真的不喜欢的部分
CONNECT_MESSAGE*msg=static_cast(messageQueue.front());
//在connect上执行其余的处理
打破
}
//其他消息类型的其他情况
}
messageQueue.pop();
}
}

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

在编写一行代码之前,先设计将在有线电视上使用的协议。决定一条消息将在字节级别包含哪些内容。决定谁先发送,消息是否被确认,接收者如何识别消息边界,等等。决定如何保持连接处于活动状态(如果将保持活动状态),先关闭哪一侧,依此类推。然后围绕规范编写代码

不要将存储在内存中的内容与在网络上发送内容的方式紧密联系在一起。这是两个非常不同的东西,有两套非常不同的需求


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

实际上我已经解决了大部分问题。所有消息都将包含消息类型的id,其余消息将根据id的不同而变化。其中一个可以先发送,另一个可以同时接收。它将是tcp/ip,因此消息被确认,但不确定消息边界是什么意思。Connect将保持活动状态,直到收到断开连接消息,客户端或服务器端都可以发送断开连接消息,并相应地进行处理。目前,唯一的问题是发送消息的数据类型的可变性。在字节级别定义每个消息负载。定义接收者将如何找到消息之间的边界(一条消息在哪里结束,下一条消息在哪里开始)。这实际上是我试图避免使用强制转换和消息的原因,我以前做过一些winsock编程,发现字节级别的复杂解析方案和我现在尝试的一样不稳定。试图将单个char*缓冲区拆分为多个对象总是碰运气。现在我试图限制它,使每个缓冲区只有一个消息对象,可以将其转换为一种类型,并且数据现在都放在一个兼容的对象中,但这似乎也不起作用。您不想避免它。TCP连接是一个字节流。您需要以字节为单位定义协议。您可能会发现它命中或未命中,但至少可以调试它——只需将生成的字节与您的协议规范进行比较。是的,我甚至不会将上面的内容称为协议规范:\。只是想知道类似的方法是否可行。当你说字节流虽然,这使我认为,我可以把它像C++处理流,有一个缓冲区,然后一个字符标记你当前的解析位置,并从那个点创建对象,并移动char *到刚刚解析的结束。我看看能不能解决一些问题。不过,谢谢你的建设性批评,我想我现在的心态是对的。