Не думал, что могут возникнуть проблемы в этой теме, но все же. Есть сервер и несколько клиентов (протокол TCP). Клиенты общаются с сервером. Причем данные ходят совершенно разного типа: могут передаваться файлы, может передаваться просто какая-нибудь управляющая информация и т. п. Сначала я сделал так, чтобы при каждой потребности клиент подключается к серверу и передает/получает инфу, после чего закрывает соединение. Но здесь много минусов: 1) каждый раз надо создавать соединение 2) есть вероятность застрять на accept в клиенте при обрыве связи во время того, как сервер в цикле передает данные 3) Больше проверок на ошибки 4) etc... Потом переделал так: Клиент коннектится к серверу и хранит соединение во время всей работы. Сервер создает отдельный тред и в бесконечном цикле принимает данные от клиента (recv). Приняв какие-то данные, сервер отвечает клиенту send-ом. Все вроде бы хорошо, НО функция recv возвращает ноль, только при ОБРЫВЕ связи с клиентом. Т.е. когда клиент разрывает соединение. Я сделал так: recv бесконечно принимает данные порциями по 100 байт. И каждый раз проверяет эти 100 байт на вхождение сигнатуры, обозначающей конец приема "*EOF*". При встрече сигнатуры сервер все принятые данные передает в процедуру обработки. После чего опять зацикливается на recv. Минусов у этого метода предостаточно. Так как же делать лучше? Жду советов...
Реализуй свой простой протокол. В своей проге я делал так. Первые 4 байта идут на длину пакета, дальше принимается и накапливается в буфере пока не придет весь пакет. Главное поставить ограничение на длину и т.п. чтоб сильно не ломали. При передачи файлов немного расширил формат "пакета" Сначала длина всего пакета, потом позиция с какой файл передается, потом длина имени, потом имя, и только потом файл. Прекрасно работает + докачка.
Если проблема в опознаваию данных тогда зделай свои пакеты (структуры). В каждом пакете должно быть поле ХЕДЕР пакета. ПроЕнумь все типы пакетов(для удобства). И читай с сокета хедер пакета что пришел. Когда получил тип пакета читаешь сам пакет. struct Hdr { int PacketId; int PacketLen; }; struct Packet1 { Hdr packetHdr; ... }; struct Packet2 { Hdr packetHdr; ... }; Hdr PacketInfo; Packet1 p1; Packet2 p2; recv(socket,(char*)&PacketInfo,sizeof(Hdr),0); switch(PacketInfo.PacketId) { case 1: { memcpy(&p1.packetHdr,&PacketInfo,sizeof(Hdr)); recv(socket,(char*)(&p1+sizeof(Hdr)),sizeof(Packet1)-sizeof(Hdr),0); } Что то типа такого. Валял здесь так что мог что-то профтикать Но суть я думаю понятна.
SnugForce Я примерно так и сделал. Но проблема не в этом. Если связи не обрывать, recv будет беконечно принимать данные, сколько бы раз клиент не вызвал send. Проблема различить логические блоки данных. Например, клиент послал запрос на получение файла и сразу же запрос на получение фамилии какого-то пользователя в базе. Сервер все примет в один бкфер. А если коиент еще и файл начнет кидать в это время, вообще путаница получится. MegaZu Насчет своих пакетов идея хорошая, попробую..
А принимать все данные в один буфер а потом парсить - БРЕД !!!Загнаться можна в 3 секи, что зделает прога если клиент отправит такой набор данных как твой идентификатор пакета ? Юзать свои пакеты оптимальный вариант. Так как ты будеш всегда знать какой пакет пришел + мона crc присобачить для верификации данных.
perez Нет не получиться, для этого нуна указать типа пакета. Только есть еще проблема, если начать пересылать файл, то отправка других пакетов, как и прием будет не возможен. Я просто сделал на разных портах. Я делал не на структурах, а просто выдерал из памяти необходимые данные, проверив их до этого на все что можно. Далее в зависимости от типа пакета передавал в свою функцию для обработки. При при необходимости, а она была, делал вложенные пакеты т.е. иерархия внутреннего протокола.
у меня было так: каждый логический блок состоит из: 5 байт- длина заголовка по смещению из этого числа идет буфер, к примеру, файл. заголовок устроин как в методе GET: название=значение&название=значение&название=значение. Но как сервер узнает, что пришел новый логический блок? Логический блок может быть большим и принимается циклически recv-ом.
SnugForce я тоже делал на разных портах- файлы на один порт, управляющая инфа-на другой. Но это надо пересылать как от клиента к серверу, так и наоборот. Много возьни и проверок. Хотелось сделать все через одно подключение, хранимое в течение всейго времени работы клиента
perez Какие проблемы ?? Делаешь доп. поля в пакете для обмена файлами - bool AppendToFile , i int SegmentSize. Если файл = 4097 байта а буфер для данных допустим 4к , то клиент будет слать 2 пакета. В 1 пакете AppendToFile - false (то есть создать файл или перезаписать) , SegmentSize - 4к; В 2 пакете AppendToFile - true , SegmentSize - 1;
Тады надо отсылку пакетов ставить в очеред. Формировать пакеты в одной функции. По-любому слать файл нуна будет в отдельном потоке, а месаги в другом. Синхронизировать доступ к функции формат-пакетов с CriticalSection. Очередь можно организовать либо самому, либо юзать стандратные функции NT. Я брал первый способ, хотя использовал немного по другому назначению пул обработки.
Думаю сделать так. Будут идти такие пакеты: заголовок и, если есть, буфер данных. Если надо передать упр. информацию, проблем нет- в заголовке будет указано, что это управляющая информация. Если это файл, клиент разбивает его на куски по 150 байт и отправляет пакетами. В заголовках таких пакетов будет название файла и информация о части файла, к примеру, 3-й из 10-ти. Когда все части соберутся, сервер сохранит на диск файл.
Да тут главная проблема по ходу в отправке данных, а не приеме. Одно замечание - зачем весь файл хранить в буфере, а только после приема сохранять на диск? И зачем номер куска файла? Отправлять все равно будешь посл-но, а TCP обеспечит правильную последовательность автоматом.
Млин, приехали. Попробую объяснить еще раз. После отправки файла клиент НЕ разрывает связь. Это значит, что recv продолжает слушать интерфейс. КАК УЗНАТЬ, что отправка файла закончена, и начилась отправка ДРУГОГО? Собственно, это вопрос, с которым я обратился сюда