powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Разделить выделенный буфер на части
25 сообщений из 32, страница 1 из 2
Разделить выделенный буфер на части
    #39693992
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Возможно глупый вопрос, но нагуглить как отрицание так и варианты не смог. Допустим мне в сокет прилетает три команды на 3, 4 и 6 байт (в заголовке содержит свой размер)

Код: plaintext
1.
2.
3000
40020
6000004

Которые в сумме укладываются в общий буфер на 255 байт и поэтому забираются сразу:

Код: plaintext
1.
2.
3.
TSocket::char FBuffer[I_BUFFER_LENGTH];

int TmpBytesRead = recv(*TmpSocket, FBuffer, I_BUFFER_LENGTH, 0);


Далее полученный буфер отправляется на обработку, где каждая порция данных копируется в отдельный объект и далее объекты расходятся по подсистемам.

Так вот, тут получается что память выделяется дважды - первый раз для общего буфера и каждый раз для копирования в команды. Можно ли как-то сделать так, что память будет выделяться один раз в куче и далее команды только отдавать указатель на эту область памяти?

Т.е. получается так - имея буфер на 255 символов - голову отдаем указателю А, кусок тела - вырезаем (именно вырезаем или переназначаем) указателю Б, а указателю в делаем также как и Б + отбрасываем лишний буфер с конца.

В теории если сделать TmpBuffer на стеке - так и будет. Но если команды улетают в разные подсистемы, то когда та команда, которая содержит указатель на весь буфер - удаляется, то остальные указатели получается ссылаются уже на мусор.

Но тут еще сомнение есть, не выйдет ли дороже каждый раз выделять 255 байт и обрезать их, чем просто копировать куски этого буфера.
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39693998
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CiplusorКоторые в сумме укладываются в общий буфер на 255 байт и поэтому забираются сразу

На это никогда нельзя полагаться. Читай сколько прочтётся, парсь конечным автоматом.
Выделение памяти - не бутылочное горлышко в данном случае.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694197
kolobok0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CiplusorВозможно глупый вопрос,....

делается порой по разному, в зависимости от задач.
Если Вы немного вникните в суть TCP связи - то это труба (в плане похожести :) ). Т.е. переданные ваши 6 байт могут быть дефрагментированы. Ситуация практически надуманная(обычно это уже софтовые притормаживатели такое могут вам какнуть на приёме), но может. Т.е. может прийти 2 байта, потом 1 потом ещё 1000.

Посему есть два способа логики на приёме (без разрыва коннекта)
- вводить понимание логических пакетов (где есть хедеры содержащие длину)
- ловить некую сигнатуру заголовка

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

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

удачи вам
(круглый)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694324
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kolobok0, первый вариант у меня как раз и есть, запрос вызывается до тех пор пока не заполнится нужный буфер либо клиент не отвалится. Он в рабочий и в принципе идеальный. Но меня интересовал именно второй вариант, как иметь выделенный срез который могу пользовать несколько подсистем.

Накидал пару тестов - первый вариант рабочее, проще сделать выделение памяти, чем тащить сопровождение этого отреза который выделяется на каждую итерацию опроса. Там же еще может получиться что пакет частично попадет в первый буфер который заполнится, а частично во второй - новый, тогда придется склеивать в промежуточный - по затратам намного дороже выходит.
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694330
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Отвечая на вопрос как передавать куски буфера не выделяя их заново:
Передавать shared_ptr на буфер и смещение с длиной куска.

Ну и то что выше сказано тоже учесть (что пакеты могут приходить частично, за несколько чтений)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694388
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ciplusorkolobok0, первый вариант у меня как раз и есть, запрос вызывается до тех пор пока не заполнится нужный буфер либо клиент не отвалится. Он в рабочий и в принципе идеальный. Но меня интересовал именно второй вариант, как иметь выделенный срез который могу пользовать несколько подсистем.

Накидал пару тестов - первый вариант рабочее, проще сделать выделение памяти, чем тащить сопровождение этого отреза который выделяется на каждую итерацию опроса. Там же еще может получиться что пакет частично попадет в первый буфер который заполнится, а частично во второй - новый, тогда придется склеивать в промежуточный - по затратам намного дороже выходит.Странный у тебя какой-то механизм получился, обычно приходится свой менеджер блоков делать и забирать данные уже зная сколько и где они есть. Например, 10кб на соединение это вполне приемлимо.
В идеале как написал Dimitry Sibiryakov лучше вообще парсить на месте с помощью ДКА и не передавать на обрабоку сырые данные, что за протокол такой?
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694477
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan), ну.. грубо говоря простой бинарный протокол. Если игрок двигает юнит - отправляется команда примерно такого вида

NNNN - размер буфера с командой
4800 - код команды передвижения юнита
2000 - код подсистемы
2100 - уникальный идентификатор юнита
3800 - уникальный идентификатор текущего местоположения юнита (на случай если его уже сдвинул другой игрок - тогда команда будет проигнорирована)
3900 - уникальный идентификатор нового местоположения

Далее сервер ждет пока от клиента что то придет, смотрит какой размер команды ожидается, создает под нее буфер - и ждет пока не придут все данные. Далее по коду подсистемы определяется в какой поток запулить эту команду - в обработку планетарных боев, космических, в модуль авторизации и т.д. Если пришло более одной команды - сервер просто создает новый буфер, пишет в нее то что есть и также ждет дальше
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
    bool TServer::OnCommand(void * AInfo, char * ABuffer, int ABufferSize)
    {
        int TmpCommand;
        // Если это старт команды - считаем размер
        if (FCommandSize == 0)
        {
            // Заберем размер            
            FCommandSize = *ABuffer;
            if (FCommandSize <= 0)
            {
                Log("Empty command size");
                return false;
            }
            FBuffer = new Transport::TBuffer(AInfo, FCommandSize);
        }
        // Сдвинем позицию чтения буфера
        int TmpCopyCount = std::min(ABufferSize, FCommandSize);
        ABuffer += sizeof(FCommandSize);
        ABufferSize -= TmpCopyCount;
        FCommandSize -= TmpCopyCount;
        // Запишем буфер
        if (!FBuffer->WriteBuffer(*ABuffer, TmpCopyCount))
        {
            Log("Error copy command");
            return false;
        }
        // Сдвинем буфер на прочитанный размер
        ABuffer += TmpCopyCount;
        // Если вся команда записана, убираем задачу в очередь
        if (FCommandSize > 0)
            return OnCommand(AInfo, ABuffer, ABufferSize);
        else
            FBuffer->Commit();
        // Попробуем считать команду с буфера
        if (!FBuffer->PeekCommand(TmpCommand))
        {
            Log("Broken command");
            return false;
        }
        // Иначе добавим в обработчики
        switch (TmpCommand / 1000)
        {
        case 0:
            FAuth.Command(FBuffer);
            break;
        /*case  1:
            FPlanetar.Subscribe(TmpInfo);
            break;
        case 2:
            FPlanetar.Connect(TmpInfo);
            break;
        default:
            TmpInfo->Reader->Buffer->Rollback();
            TmpInfo->Reader->Commit();
            break;*/
        }
        // Успешно
        return true;
    }



Команда (сейчас) копируется в объект буфера (что-то типа самописного stream reader/writer) и через мьютекс отправляется в очередь нужного модуля (как раз недавно поднимал по этому вопросу тему о блокировках).
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
    void TBufferTransport::Push(TBuffer * ABuffer)
    {
        TLockGuard lock(FMutexAccess);
        FQueue.push(ABuffer);
        FSignal.notify_one();
    }

    TBuffer * TBufferTransport::Pop()
    {
        // Заблокируем мьютекс сигнала
        std::unique_lock<std::mutex> locker(FMutexSignal);
        // Подождем появления сигнала
        FSignal.wait(locker);
        // Заблокируем от изменения
        TLockGuard lock(FMutexAccess);
        // Выделим элемент
        if (FQueue.empty())
            return nullptr;
        else
        {
            TBuffer * tmpResult = FQueue.front();
            FQueue.pop();
            return tmpResult;
        }
    }


А там уже модуль сам смотрит что с командой делать дальше.

В секунду таких команд в пике на дельфи было около семи тысяч, поэтому решил что сейчас стоит рассмотреть варианты минимизации расходных операций.

ps. Да, код скорее всего топорный и унылый, но я только начал изучение, после дельфи тут как папуас с камнем бегаешь, пока вокруг самолеты летают :)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694584
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ciplusor,

комнады у тебя маленькие, читай когда приходит необходимый размер, остатки дочитываешь следующим циклом - это самое простое

есть такая библиотечка SDL (её очень часто используют в играх как кросс-платформенную библиотеку), отдельная её часть SDL_NET (именно что полностью самостоятельная)

вот с ней можно поиграться в Select(SDLNet_CheckSockets) - эта абстракция есть на многих осях

кстати, заголовки к ней и для дельфи есть - не можешь сразу на плюсах, пиши сначала на паскале, потом переводи
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39694590
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да у меня смысл - все написать по максимуму самому, уже не сколько разрабатываю, сколько учусь пока разрабатываю. Вот сокеты изучил подробно, понял что они действительно "труба", начиная от проверки на дубли в FD_SET и бредогенерированием набора клиента для очередного сбора кусочка данных. А дельфевый indy - это насадка в виде тонкой поливалки к этой трубе.

Если делать так как описано во всяких книжках по кодингу - сервер затыкается уже на первой сотне бото-клиентов. Поэтому ни boost ни что то еще не пользую. Да, грешен - вместо изучения темплейтов использую std:: списки и т.п. но на темплейтах у меня крыша поехала пока пытался разобрать код в генофонде. Поэтому сперва только то что просто и более менее понятно. Потом конечно найму аудит чтобы ткнули носом где совсем все плохо, но пока форумы спасают :)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695216
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ciplusor,

Я наверное порекомендую вам простые истины, хотя большинство новичков(от языка это не зависит) их игнорят, набивая шишки сами - хотя это может быть и правильно, сам таким был. Не будешь падать в детстве, потом это аукается.

для вашей задумки многопоточность не нужна от слова совсем, нету от неё плюсов кроме разделения логики

зря вы не используете готовые решения вроде SDL

надо понять почему стандартные примеры валятся
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695226
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan), Это не суть важно, не имеет смысла обсуждать суть системы, которую вы не понимаете.
kealon(Ruslan)для вашей задумки многопоточность не нужна от слова совсем, нету от неё плюсов кроме разделения логики Если приходит сообщение авторизации, оно обрабатывается в своем потоке. Если это движение юнита - то в потоке, который обрабатывает карту боевых действий, если это галактическое сражение - то поток, отвечающий за область галактики. Если я на команду авторизации буду ждать пока база раздуплится с ответом - это будет конец всему. Или если зависнет с ошибкой одна из карт системы - ее просто перезагружаю, а остальные работают параллельно. Это не говоря уже о шардинге и методах их соединения / расслоения.
kealon(Ruslan)надо понять почему стандартные примеры валятсяА что понимать? Нагрузка в 800 тестовых клиентов, при каждом заборе буфера постоянно выставляются FD_SET с учетом уникальности, т.е. заведомо жесткие тормоза в реал-тайм системе. Да и 64 дефолтных клиента - во всей литературе для чайников что видел описано только поверхностно, мол создайте 2 клиента и будет вам счастье. А при попытке использовать этот код в нагруженной системе - он просто встает в позу рака.
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695243
kolobok0
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ciplusor...Нагрузка в 800 тестовых клиентов....

это не нагрузка. от слова совсем.
а большие нагрузочные серваки делаются немного по другому уже. почитайте про микросервисную архитектуру, плюс докер-контейнер, плюс любой оркестратор = и будет вам счастье, только подкидывайте на ран-тайме железа если заткнётесь. Ваша задача как разработчика сводится к оптимизации "единичного" сценария работы. А далее уже дело техники. И там не просто, а очень просто получается...

удачи вам
(круглый)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695245
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Completion port поэффективнее будет, чем select
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695253
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилCompletion port поэффективнее будет, чем select

На Windows и select() ништяк если FD_ISSET не пользоваться, а прямо лезть в возвращаемый
массив. А на Linux есть эти самые completion port?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695256
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,

нету, да и нужды в ней для работы с сетью особой нет.
MS как всегда придумало ещё одну "фичу", и видимо для продвижения специально корявит Select

мелькали где-то исходники нормальной реализации Select под Windows (как раз через Completion port)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695317
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,

Перед тем, как лезть в возвращаемый массив, его ещё сформировать нужно,
И не один бит на дескриптор, а байт эдак восемь на хэндл
И всё это скопировать в ядро и обратно

В линуксе есть epoll. Хочется эффективкости - для каждой ОС своя стратегия
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695321
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ciplusorkealon(Ruslan), Это не суть важно, не имеет смысла обсуждать суть системы, которую вы не понимаете.
kealon(Ruslan)для вашей задумки многопоточность не нужна от слова совсем, нету от неё плюсов кроме разделения логики Если приходит сообщение авторизации, оно обрабатывается в своем потоке. Если это движение юнита - то в потоке, который обрабатывает карту боевых действий, если это галактическое сражение - то поток, отвечающий за область галактики. Если я на команду авторизации буду ждать пока база раздуплится с ответом - это будет конец всему. Или если зависнет с ошибкой одна из карт системы - ее просто перезагружаю, а остальные работают параллельно. Это не говоря уже о шардинге и методах их соединения / расслоения.вчера не было времени
Например, "проверка авторизации" - у вас что, лярд клиентов? загрузите всех в обычный мап при загрузке. Вообще в бд лучше не лезть при "работе".
"Карта зависла" - это я так понимаю поток завис, как же вы его перегрузите? Тесты писать надо, не должно быть такой ситуёвины. Я бы как юзер офигел если бы вдруг карта перегрузилась ни с того ни с сего когда я стою с честно накрафтенным.

И такие решения можно найти по всем пунктам. Очереди это не киллер-фича, ими нужно очень осторожно пользоваться, когда уж совсем никак.
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695322
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)MS как всегда придумало ещё одну "фичу", и видимо для продвижения специально корявит Select
Completion port в винде для всего асинхронного ввода-вывода, а убогий select из третьей винды пришёл, ничего специально не портили
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695323
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил,

но заметь, скорее всего специально и не чинили
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695331
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилВ линуксе есть epoll. Хочется эффективкости - для каждой ОС своя стратегияНе обязательно палить под каждую систему, хотя тонкий тюнинг ПРИ ВОЗНИКНОВЕНИИ ПОТРЕБНОСТИ никто не отменял
Для сервера проще загнать тот же netmap и не париться с разными реализациями. К тому во фюхе, например, он уже дефолт
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695367
Ciplusor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)Карта зависла" - это я так понимаю поток завис, как же вы его перегрузите? Тесты писать надо, не должно быть такой ситуёвины. И такие решения можно найти по всем пунктам. Очереди это не киллер-фича, ими нужно очень осторожно пользоваться, когда уж совсем никак.Надеюсь это слова опытного гейм-девелопера, а не диванного теоретика :)
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695391
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)для вашей задумки многопоточность не нужна от слова совсем, нету от неё плюсов кроме разделения логики

а когда вообще в демонах нужна многопоточность?
например, идёт поток запросов всех сортов: и в бд сходить, и вьюху отдать, и посчитать чего-то...
их все обрабатывать в одном потоке?
Я конечно понимаю, что компьютер это конечный автомат, но ядра тут не помогают чтоли?

авторНапример, "проверка авторизации" - у вас что, лярд клиентов? загрузите всех в обычный мап при загрузке. Вообще в бд лучше не лезть при "работе".
а как же не лазать в БД, если демон для игры? На ум только редиска приходит. Но она вообще-то тоже БД...
Держать в ней массив горячих юзеров, имхо, оптимальный вариант. Вы его имели ввиду?
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695393
Фотография полудух
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
тут вот разработчик Tarantool (APP-сервер с БД на борту (и ещё кучей плюшек)) неплохо про fibers задвинул тему, вот обдумываю, как их в демонах максимально заюзать...
YouTube Video
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695441
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
полудухтут вот разработчик Tarantool (APP-сервер с БД на борту (и ещё кучей плюшек)) неплохо про fibers задвинул тему, вот обдумываю, как их в демонах максимально заюзать...
Не такое тяжёлое как поток и нет проблем с синхронизацией, но памяти жрёт как поток
Если логка сложная то да, удобно. Минусы он уже расписал.
уже во всю используется в Net, Go и пр.
...
Рейтинг: 0 / 0
Разделить выделенный буфер на части
    #39695446
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
полудуха как же не лазать в БД, если демон для игры? На ум только редиска приходит. Но она вообще-то тоже БД...
Держать в ней массив горячих юзеров, имхо, оптимальный вариант. Вы его имели ввиду?а зачем туда лазить? нужда в этом есть ОСОБАЯ?
...
Рейтинг: 0 / 0
25 сообщений из 32, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / Разделить выделенный буфер на части
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]