locator
Постоялец
Offline
|
|
« : 09-06-2013 13:33 » |
|
Доброго времени суток! есть девайс, собирающий данные (на шине PC/104), сам компьютер PC/104 соединен через wi-fi с ноутбуком. Девайс формирует данные в виде пакетов размером около 600 байт. Интервал обновления пакетов около 1мс (частота 1кГц). Задача в том, чтобы посылать пакеты в ноут с максимальной скоростью (которую позволяет соединение wi-fi 50мбит/c). Я создал сервер, и тупо написал поток передачи пакетов клиенту, вот потоковая функция: DWORD WINAPI SendData(LPVOID client_socket) { SOCKET my_sock; my_sock = ((SOCKET *)client_socket)[0]; union { DEV_DATA dat; // структура данных от девайса рамером 600 байт char buff[sizeof(DEV_DATA)]; }; while(1) { send(my_sock, buff, sizeof(DEV_DATA), 0); Sleep(10); // задаю 100 раз в секунду передачу пакетов } return 0; } Но клиент на ноутбуке принимает битые пакеты или вообще зависает (писал с компонентом TClientSocket на билдере). Задал интервал передачи в потоке 5 раз в секунду (написал Sleep(200)), все нормально передается. Я так понимаю, что пакеты можно намного чаще передавать, чем 5 раз в секунда. Как мне грамотно написать процесс передачи/приема пакетов (так, чтобы скорость обмена была максимальной) ? В инете про это никто не пишет (все статьи о том, как соединить сервер с клиентом, не более того ). Может ссылки полезные дадите? На PC/104 установлена winxp, на ноуте win7. Спасибо за ответы!
|
|
« Последнее редактирование: 09-06-2013 14:02 от locator »
|
Записан
|
|
|
|
Sla
|
|
« Ответ #1 : 09-06-2013 14:32 » |
|
Ну... тут скорей нужна математика.
50Мбит/с ~ 5Мб/с
делим на 600, получаем 8000 пакетов в сек
зы... я не ошибся в расчетах?
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #2 : 09-06-2013 16:07 » |
|
немного ошибся, в пакет добавляется заголовок ip, поэтому скорость поменьше будет. и как это реализовать?
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #3 : 09-06-2013 16:11 » |
|
А собрать несколько пакетов в обший пакет?
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #4 : 09-06-2013 17:16 » |
|
а это как?
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #5 : 09-06-2013 18:32 » |
|
locator, с позиции API сокетов пофиг, посылаешь ли ты по гигабитному ethernet, через WiFi или по модему на 1200 бод: интерфейс один и тот же. Битых пакетов программа получить не может. Пакет либо будет получен целиком, либо не будет получен совсем. Напрашивается вывод, что у тебя ошибка в программе (в какой — тебе виднее, код мы не видим).
Подмечу, что упрощенная формула, применяемая к ethernet (байт/с = бит/с ÷ 10), в WiFi не работает. Фактическая скорость передачи будет зависеть от множества факторов, предсказать которые заранее невозможно. Это сеть с негарантированной пропускной способностью. Кстати, служебные данные WiFi передаются на скоростях 1 или 2 Мбит/с, а с большими скоростями передается полезная нагрузка (в данном случае IP-пакеты). Т.к. WiFi — сеть с разделяемой средой передачи, то возможны коллизии и есть переменная задержка начала передачи (и повторной передачи пакета). Еще есть подтверждение приема пакета. При работе через точку доступа пакет проходит по эфиру дважды. В общем, протокол сложен и для оценки приблизительной максимальной скорости стоит делить не на 10, а на 25. А есть и еще понижающие скорость факторы: загрузка эфира (разделение частотного канала разными пользователями WiFi), помехи (возможны повторные пересылки и понижение скорости передачи). Для точного расчета задержек передачи нужно углубляться в чтение стандартов. Попробую очень грубо прикинуть... Скажем, на скорости 54 Мбит/с блок данных в 600 байт (плюс 28 байт на заголовки IP и UDP) передастся за ≈93 мкс. Накинем на служебные нужды: пусть получится порядка 150 мкс. Двойной проход по эфиру: уже 300 мкс. Два подтверждения получения пакета, задержки, помехи, коллизии: 1000 пакетов в секунду — это оптимистичный прогноз, хотя и достижимый при должных условиях. Куда производительнее будет собирать данные в буфер и пересылать более крупными партиями.
|
|
« Последнее редактирование: 09-06-2013 18:42 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #6 : 09-06-2013 19:09 » |
|
ну какая может быть ошибка, все копировалось с известных программ: int nclients = 0;
while((client_socket = accept(mysocket, (sockaddr *)&client_addr, &client_addr_size))) // цикл извлечения запросов на подключение из очереди клиентов { nclients++;
HOSTENT *hst;
hst = gethostbyaddr((char *)&client_addr.sin_addr.s_addr, 4, AF_INET); DWORD thID; CreateThread(NULL, NULL, SendData, &client_socket, NULL, &thID);
if(nclients == 1) break; // нам больше одного клиента не надо }
// функция сервера (передает пакеты) DWORD WINAPI SendData(LPVOID client_socket) { SOCKET my_sock; my_sock = ((SOCKET *)client_socket)[0]; union { DATA data; char buff[sizeof(DATA)]; };
while(1) { send(my_sock, buff, sizeof(DATA), 0); Sleep(10); } return 0; }
// функция клиента void __fastcall TForm1::ClientSocket1Read(TObject *Sender, TCustomWinSocket *Socket) { if(ClientSocket1->Active == false) return;
int len = Socket->ReceiveLength(); // получили длину пакета //если более 5 раз/с передача, то длина получается любой, 1000 байт, 2000 байт... (почему ?????)
char *Buff = new char[sizeof(DATA)];
AnsiString s; s.SetLength(len);
Socket->ReceiveBuf(Buff, len);
strcpy(data, Buff); // массив data объявлен глобальным } Кстати, если весь обмен тестировать на локальном компе, то все летает..... действительно около 1000 раз/с. Я просто не понимаю, как передаются данные, например, фильмы, музыка по сетевым протоколам....? Видимо, как-то по другому, а как? Добавлено через 2 минуты и 32 секунды:Finch, двинь идейку пожалуйста
|
|
« Последнее редактирование: 09-06-2013 19:11 от locator »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #7 : 09-06-2013 19:30 » |
|
locator, у тебя сокеты UDP или TCP?
А программа — ужас.
|
|
« Последнее редактирование: 09-06-2013 19:33 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #8 : 10-06-2013 03:58 » |
|
сокеты TCP конечно
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #9 : 10-06-2013 04:21 » |
|
locator, когда мне встречалась такая задача, самый действенный вариант каждый раз оказывался такой: запускается несложного содержания поток считывания, работающий максимально быстро (понадобится ознакомиться с описанием функций timeGetDevCaps , timeBeginPeriod , CreateEvent ,WaitForSingleObject )
поток имеет некоторый не сильно большой приёмный буфер (килобайты) . Одна итерация запрашивает (методом receive) из сокета данные размером с этот буфер, и всё, что считалось, через синхронизатор (критическая секция) дописывает во внешний приёмный буфер (бОльших размеров). Затем производится ожидание в 1 мс - сбрасывается созданный для этих целей хендл события и вызывается WaitForSingleObject для него, затем идёт новая итерация
Таким образом во внешнем буфере имеем актуальный поток данных, разгружая при этом сокет и не допуская потерь на этом уровне). При работе с внешним буфером, через тот же синхронизатор вытаскиваем порцию данных (копируем и разлочиваем, собственно, чтобы не затормаживать поток) и дальше "спокойно" анализируем.
Не претендую на идеальность способа, но он работает )
Всё то же самое будет работать и с UDP
Добавлено через 2 минуты и 35 секунд: данные, передаваемые по wi-fi лучше, конечно же, собирать в пакеты. Попробуй ещё и сжимать , если скорость не устроит
|
|
« Последнее редактирование: 10-06-2013 04:24 от Алексей++ »
|
Записан
|
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #10 : 10-06-2013 05:24 » |
|
значит, тотальная буферизация нужна. Известно, что у компонента TClientSocket есть поток встроенный. Алексей++, это случайно не тот поток, о котором ты говоришь? И еще я не понимаю: на передатчике пакетов должен стоять сервер или клиент? Или это без разницы?
|
|
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #11 : 10-06-2013 05:26 » |
|
locator, а что Вы понимаете под "битыми" пакетами? Как правильно сказал RLX в tcp/ip и udp/ip пакет битым прийти не может, его должны отфильтровать на протокольном уровне - там контрольные суммы передаются. Могут быть потери, если используете udp, и это значит, что, скорее всего, Вы не успеваете забирать сообщения из сокета. В качестве варианта - можно попробовать увеличить буфера приёма через setsockopt(fd, .., SO_RCVBUF,..), но более правильным будет вариант, который тут предложили - попробовать объединить пакеты, т.е. за раз выдавать информацию не одного пакета, а двух, но зато с вдвое меньшей частотой.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #12 : 10-06-2013 05:39 » |
|
locator, мне неизвестно, что есть в TClientSocket , я билдером не пользовался. В самой WinAPI при создании сокета вроде никаких потоков не создаётся.
Сервер должен стоять на сервере (на приёмнике) - он нужен для принятия подключения от клиента в случае TCP. Но уже в передаче и приёме данных сервер никак не участвует
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #13 : 10-06-2013 05:41 » |
|
locator, а что Вы понимаете под "битыми" пакетами? Как правильно сказал RLX в tcp/ip и udp/ip пакет битым прийти не может,
Может. Две последовательные передачи могут быть приняты одновременно или даже разрезаться по неравным частям. Например: Передаём три раза по 600 байт. Варианты приёма: 1) Три раза по 600 байт. 2) Один раз 1800 байт 3) 1500 + 300 .. Надеюсь проблема понятна. P.S.: Для TCP сокета можно ещё выключить алгоритм Нагла (Nagle).
|
|
« Последнее редактирование: 10-06-2013 05:43 от sss »
|
Записан
|
while (8==8)
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #14 : 10-06-2013 06:02 » |
|
locator, а что Вы понимаете под "битыми" пакетами?
я смтотрю длину пакета функцией Socket->ReceiveLength(), и длина все время разная получается (1000, 2000 байт). Получается, что пакет не принят. Или сразу два пакета прилетело.
|
|
« Последнее редактирование: 10-06-2013 06:03 от locator »
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #15 : 10-06-2013 06:10 » |
|
locator, а что Вы понимаете под "битыми" пакетами? Как правильно сказал RLX в tcp/ip и udp/ip пакет битым прийти не может,
Может. Две последовательные передачи могут быть приняты одновременно или даже разрезаться по неравным частям. Например: Передаём три раза по 600 байт. Варианты приёма: 1) Три раза по 600 байт. 2) Один раз 1800 байт 3) 1500 + 300 .. Надеюсь проблема понятна. P.S.: Для TCP сокета можно ещё выключить алгоритм Нагла (Nagle). В TCP нет понятия пакетов, там - поток, соответственно данные могут хоть по байту приходить - если их правильно принимать (например использовать в recv() флаг MSG_WAITALL в unix-подобных ОС, или просто дочитывать до требуемой длины в win), то таких проблем быть не должно. При этом битых пакетов всё-равно быть не может - сообщение либо приходит, либо нет, в tcp/ip если не было подтверждения о получении, то сообщение будет выслано повторно, в udp хуже - просто выбросят и всё. А про алгоритм Нагла Вы правильно сказали - в данной ситуации может немного помочь.
|
|
|
Записан
|
|
|
|
Sla
|
|
« Ответ #16 : 10-06-2013 06:11 » |
|
Я повторю вопрос.
По скорости все согласовано? Успеваешь передавать пакеты?
|
|
|
Записан
|
Мы все учились понемногу... Чему-нибудь и как-нибудь.
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #17 : 10-06-2013 06:12 » |
|
locator, в tcp нет пакетов. Вам надо не просто принимать сообщения, а ещё их правильно собирать.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #18 : 10-06-2013 06:15 » |
|
сокеты TCP конечно
Тогда для буферизации ничего делать не надо. Алгоритм отложенной отправки сам решит, когда отправлять очередной пакет. А для API TCP сокет представлен как поток байт, а не набор пакетов. Соотв., тебе нужно структуировать данные, чтобы можно было понять начало и конец блока данных. Например, так: typedef struct _packet_buffer{ uint16 size; DEV_DATA dat; void _packet_buffer(void) { size = sizeof(_packet_buffer); }; } packet_buffer_t;
// ... packet_buffer_t buffer;
//... send(socket, (void *)&buffer, sizeof(packet_buffer_t), 0); При приеме считать sizeof(uint16) байт, после чего считать указанное число байт. Если объем считанных данных недостаточен, значит надо повторить считывание (обычных блокируемый ввод-вывод решает эту проблему). Добавлено через 5 минут и 45 секунд:locator, а что Вы понимаете под "битыми" пакетами? Как правильно сказал RLX в tcp/ip и udp/ip пакет битым прийти не может,
Может. Две последовательные передачи могут быть приняты одновременно или даже разрезаться по неравным частям. Например: Передаём три раза по 600 байт. Варианты приёма: 1) Три раза по 600 байт. 2) Один раз 1800 байт 3) 1500 + 300 .. Надеюсь проблема понятна. P.S.: Для TCP сокета можно ещё выключить алгоритм Нагла (Nagle). Это не «битые пакеты», а невыровненные данные. Потому как потоки и пакеты — разные концепции.
|
|
« Последнее редактирование: 10-06-2013 06:28 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #19 : 10-06-2013 06:23 » |
|
то бишь читать по одному байтику из принимаемого потока, и разделять заголовки пакетов? Или функцией Socket->ReceiveBuf(Buff,len) складывать буферы Buff в другой большой буфер (или очередь), и уже оттуда анализировать цепочку байтов (отделять заголовки пакетов)?
|
|
« Последнее редактирование: 10-06-2013 06:26 от locator »
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #20 : 10-06-2013 06:26 » |
|
locator, зачем побайтно? Читать по столько, по сколько читается, просто написать алгоритм разбора, например конечный автомат. Или функцией Socket->ReceiveBuf(Buff,len) складывать буферы Buff в другой большой буфер (или очередь), и уже оттуда анализировать цепочку байтов (отделять заголовки пакетов)?
можно и так.
|
|
« Последнее редактирование: 10-06-2013 06:27 от darkelf »
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #21 : 10-06-2013 06:26 » |
|
Это не «битые пакеты», а невыровненные данные. Потому как потоки и пакеты — разные концепции.
Человек передаёт и ожидает пакеты через поток TCP. В TCP нет пакетов? Есть(!) - используются для организации потока.. И вообще - есть связь с установлением соединения и без установления соединения.
|
|
« Последнее редактирование: 10-06-2013 06:29 от sss »
|
Записан
|
while (8==8)
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #22 : 10-06-2013 06:28 » |
|
sss, на прикладном уровне, на котором работает человек - пакетов нет, как нет секторов при работе с диском.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #23 : 10-06-2013 06:29 » |
|
locator, перечитай пост, я его дополнил примером. https://forum.shelek.ru/index.php/topic,29445.msg289155.html#msg289155Добавлено через 3 минуты и 55 секунд: Это не «битые пакеты», а невыровненные данные. Потому как потоки и пакеты — разные концепции.
Человек передаёт и ожидает пакеты через поток TCP. В TCP нет пакетов? Есть(!) - используются для организации потока.. И вообще - есть связь с установлением соединения и без установления соединения. Чушь говоришь, дорогой. Ты приравниваешь программный буфер отправки к транспортному пакету и программному буфер приема, да еще для протокола, не гарантирующего пакетную разбивку. Отправь 600 байт по сети с TCP MSS равным 400!
|
|
« Последнее редактирование: 10-06-2013 06:33 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
sss
Специалист
Offline
|
|
« Ответ #24 : 10-06-2013 06:33 » |
|
sss, на прикладном уровне, на котором работает человек - пакетов нет, как нет секторов при работе с диском.
Блин где Вы взяли что TCP поточный, а UDP пакетный? Ещё раз - есть связь с установлением соединения и без установления соединения. Все протоколы используют пакеты..
|
|
|
Записан
|
while (8==8)
|
|
|
RXL
|
|
« Ответ #25 : 10-06-2013 06:36 » |
|
sss, личные убеждения — это святое, но не при обмене информацией. Поднимись над IP и углубись в API.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
locator
Постоялец
Offline
|
|
« Ответ #26 : 10-06-2013 06:37 » |
|
из сказанного выше, я понял что передаваемые мной данные система делит на блоки и передает эти блоки, причем размером блоков я уже не могу управлять. За одну посылку пакета 600 байт передаться может как 600, так и 400 байт, тогда остаток принимается уже в следующий прием.
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #27 : 10-06-2013 06:38 » |
|
RXL, вот что я знаю - есть сети с коммутацией пакетов и коммутацией каналов. Хотите поговорить об этом? Или это мои личные убеждения?
Добавлено через 2 минуты и 44 секунды: А вот нашёл - Протокол не сохраняющий границы сообщений, обычно называют протоколом, основанном на потоке.
|
|
« Последнее редактирование: 10-06-2013 06:41 от sss »
|
Записан
|
while (8==8)
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #28 : 10-06-2013 06:44 » |
|
sss, имхо, Вы немного путаете, как оно реализовано "внизу" и какой интерфейс имеет "вверху". То, что там бегают пакеты никак не влияет на его интерфейс с верхом, а этот интерфейс таков, что предоставляется поток данных, без разбиения на пакеты - можете хоть побайтно вычитывать - если будете успевать - всё будет работать и данные теряться не будут. Ещё раз приведу аналогию с жестким диском - там внутри сектора, на уровне ФС - блоки и кластеры, но тем не менее, когда Вы работаете через интерфейс ОС типа read()/write() - Вас это как-то мало волнует - для Вас это просто поток байтов, хотя физически он там может быть очень неплохо быть разбросанным по диску..
|
|
« Последнее редактирование: 10-06-2013 06:46 от darkelf »
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #29 : 10-06-2013 06:46 » |
|
из сказанного выше, я понял что передаваемые мной данные система
Вам придётся передавать пакеты через поток. Вначале - длина пакета, затем данные. На приёмной стороне парсить.. Иначе это всё лишь предположения и танцы с бубнами.. Это очень вылезет на дальнем расстоянии в условиях больших задержек пакетов на маршрутизаторах.. Там будут абсолютно непредсказуемые буферы приходить.. Но зато всегда по порядку
|
|
|
Записан
|
while (8==8)
|
|
|
|