winsock, сеть, ориентированная на сообщения, и приведение типов к буферу из recv - PullRequest
0 голосов
/ 14 февраля 2012

Ладно, у меня на самом деле пока нет кода, потому что я пока что просто выбираю фреймворк, но я все еще немного сбит с толку о том, как я хочу поступить об этом:.

На стороне сервера, я хотел бы иметь класс, в котором каждый экземпляр имеет сокет и различную информацию, идентифицирующую каждое соединение.у каждого объекта будет свой поток для получения данных.Я понимаю, как я буду реализовывать большую часть этого, но моя путаница начинается так же, как я перехожу к фактической передаче данных между сервером и клиентом.Я хочу иметь несколько различных структур сообщений для конкретных случаев (например, CONNECT_MSG, DISCONNECT_MSG, POSTTEXT_MSG и т. Д.), А затем все, что мне нужно сделать, это указать точку char * в этой структуре и затем передать ее через send() function.

Но, как я думаю, в этот момент все становится немного сложнее.Любой из этих различных типов сообщений может быть отправлен, и на принимающей стороне вы не будете иметь представления о том, как следует преобразовывать входящий буфер.Я надеялся сделать в потоке каждого объекта подключения блокировку до получения пакета с сообщением, а затем сбросить его в один объект очереди, управляемый сервером (мьютексы предотвратят жадность), а затем сервер.обрабатывать каждое сообщение в порядке 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();
     }
}

Теперь, еслиВы следили до сих пор, вы понимаете, насколько это глупо и хрупко.он преобразуется в базовый класс, передает этот указатель в очередь, а затем просто предполагает, что указатель все еще действителен из другого потока, и даже в этом случае всегда будет ли оставшийся буфер после указателя для остальной части производного класса всегдабыть действительным впоследствии для кастинга, но мне еще предстоит найти правильный способ сделать это.Я широко открыт для ЛЮБЫХ предложений, как для создания этой работы, так и для совершенно другого дизайна сообщений.

1 Ответ

0 голосов
/ 14 февраля 2012

Прежде чем написать хотя бы строку кода, разработайте протокол, который будет использоваться в проводной сети. Решите, из чего будет состоять сообщение на уровне байтов. Решите, кто отправляет первым, подтверждаются ли сообщения, как получатели идентифицируют границы сообщений и так далее. Решите, как будет поддерживаться соединение (если оно будет), какая сторона будет закрыта первой и т. Д. Затем напишите код вокруг спецификации.

Не связывайте тесно, как вы храните вещи в памяти, с тем, как вы отправляете вещи по проводам. Это две совершенно разные вещи с двумя совершенно разными наборами требований.

Конечно, не стесняйтесь настраивать спецификацию протокола при написании кода.

...