Модераторы: feodorv
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Разработка своего сетевого протокола 
:(
    Опции темы
Aoizora
Дата 25.12.2016, 16:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 18.11.2016

Репутация: нет
Всего: нет



Пишу несложный сетевой протокол. Мне нужно, чтобы приходящие пакеты в зависимости от значения некоторого поля выводились либо в консоль, либо добавлялись в конец файла, который может создаваться с рандомным именем каждый раз, когда происходит соединение. Какой паттерн проектирования для этого использовать? Пытаюсь прикрутить шаблон стейтмашин, но получается неоптимально: когда нужно сбрасывать нагрузку пакета в конец файла, приходится этот файл открывать каждый раз, когда приходит пакет данного типа. Поток пакетов может быть неоднородным, т.е. друг за другом приходят пакеты, содержимое которых надо записывать в разные места. 

Вот что я написал сейчас:

Код

#ifndef NETWORK_H
#define NETWORK_H

#include <Windows.h>
#include <stdio.h>
#include "packet.h"

class State
{
public:
    virtual int recv(SOCKET sock) = 0;
    virtual int send(SOCKET sock, char *data, size_t len) = 0;
};

class ConsoleState : public State
{
public:
    int recv(SOCKET sock);
    int send(SOCKET sock, char *data, size_t len);
};

class FileState : public State
{
    HANDLE hFile;
public:
    FileState();
    ~FileState();
    int recv(SOCKET sock);
    int send(SOCKET sock, char *data, size_t len);
};

class Network
{
    SOCKET sock;
    State *state;
    static int last_state;
public:
    Network();
    Network(SOCKET s) : sock(s), state(nullptr) {}

    void set_state(State *s)
    {
        delete state;
        state = s;
    }
    int send(char *data, size_t len);
    int recv();
};

#endif


Код

#include "network.h"

int ConsoleState::recv(SOCKET sock)
{
    char buffer[200] = { 0 };

    int ret = ::recv(sock, buffer, 200, 0);
    printf("recieved : %s\n", buffer);

    return ret;
}

int ConsoleState::send(SOCKET sock, char *data, size_t len)
{
    packet header = { 0 };

    header.command = CMD_WRITE_CONSOLE;
    header.type_of_data = TYPE_ASCII_TEXT;
    header.size_of_data = len;

    ::send(sock, reinterpret_cast<char *>(&header), sizeof(header), 0);
    int ret = ::send(sock, data, len, 0);
    return ret;
}

FileState::FileState()
{
    hFile = CreateFile(TEXT("log.txt"),
        GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
}

FileState::~FileState()
{
    CloseHandle(hFile);
}

int FileState::recv(SOCKET sock)
{
    char buffer[200];
    DWORD bytes_read = 0;
    DWORD bytes_written = 0;

    bytes_read = ::recv(sock, buffer, 200, 0);
    printf("recieved %d bytes\n", bytes_read);
    WriteFile(hFile, buffer, bytes_read, &bytes_written, NULL);

    return bytes_read;
}

int Network::last_state = 0;

int FileState::send(SOCKET sock, char *data, size_t len)
{
    return 0;
}

int Network::send(char *data, size_t len)
{
    int ret = state->send(sock, data, len);
    return ret;
}

int Network::recv()
{
    packet header;

    ::recv(sock, reinterpret_cast<char *>(&header), sizeof(header), 0);

    if (last_state != header.command)
    {
        last_state = header.command;
        switch(header.command)
        {
        case CMD_WRITE_CONSOLE:
            set_state(new ConsoleState);
            break;
        case CMD_WRITE_FILE:
            set_state(new FileState);
            break;
        }
    }

    return state->recv(sock);
}


Сейчас работает запись в консоль или в файл в зависимости от пакетов, но проблем нет только тогда, когда приходят пакеты одного типа. Если приходят пакеты разного типа, но файл перезаписывается, например, когда происходит смена состояния. Это не то, что я хочу.

Плохо и то, что на каждый пакет открывается/закрывается файл. Еще и запись попакетная.

Нужно предусмотреть и обработку ошибок в пакетах. Как это сделать?
PM MAIL   Вверх
likehood
Дата 25.12.2016, 19:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


666
**


Профиль
Группа: Участник
Сообщений: 536
Регистрация: 21.12.2005

Репутация: нет
Всего: 24



Насколько я понял, главная проблема в том, что в строках 80 и 83 при смене состояния каждый раз создаются новые объекты, а значит заново открываются файлы. В принципе, паттерн StateMachine не требует обязательно создавать новые объекты. Можно в начале создать два объекта ConsoleState и FileState, и в классе Network хранить указатель на один из этих объектов. При смене состояния указатель переключается на другой объект, а сами объекты не уничтожаются/создаются. Если конечно я правильно понял вопрос smile.

P.S. Как я понял функция send в классах ConsoleState и FileState делает одно и то же. Может, её лучше реализовать в базовом классе State?
PM MAIL   Вверх
Aoizora
Дата 25.12.2016, 21:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 18.11.2016

Репутация: нет
Всего: нет



Спасибо. Видимо, так и будет лучше, если отойти от стандартной реализации стейтмашины.
PM MAIL   Вверх
Forstrot
Дата 9.1.2017, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 9.1.2017

Репутация: нет
Всего: нет



Блин, а Вы на заказ делаете? Мне необходимо выполнить подобного рода работу на производстве: https://www.konsom.ru/solutions/informatsio...ki-dannyh-tsod/ вот пытаюсь найти специалиста.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1271 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.