Mike_mvk
Гость
|
|
« : 18-10-2004 14:07 » |
|
Описываю обстановку. Есть некий девайс, соединенный с компом по Ethernet. Умеет общаться по протоколу UDP. Между компом и девайсом два потока данных: команды управления девайсом ( полудуплекс с квитированием ) и поток некой информации от девайса. На компе программа с 3 сокетами (winapi). 2 на команды управления, 1 для приема информации от девайса (обмен только в одну сторону). Сокеты живут в разных потоках. Описываю проблему. От девайса идет поток пакетов информации. При обмене командами управления, при чтении из сокета для приема информации, наблюдается исчезновение некоторых пакетов. Перехват (winpcap'ом) показывает, что пакеты до сетевой доходят. Увеличение буфера nParam = 524288; setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char*)&nParam, sizeof(nParam));
результата не дало. Есть ли у Вас какие-нить мысли? Если нужно, покажу куски кода. ЗЫ Надеюсь на помощь и сочувствие... ЗЗЫ Надеюсь, что понятно объяснил.
|
|
« Последнее редактирование: 02-12-2007 14:11 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #1 : 18-10-2004 14:15 » |
|
давай поглядим код который читает данные из буфера tcp (там где идет прием данных)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #2 : 18-10-2004 15:48 » |
|
Там не tcp. Там тоже UDP. while( Running ) { nParam = sizeof( SOCKADDR_IN ); if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; } if( !Running ) break; //далее обработка пакета ...
|
|
« Последнее редактирование: 02-12-2007 14:15 от Алексей1153++ »
|
Записан
|
|
|
|
npak
|
|
« Ответ #3 : 18-10-2004 15:49 » |
|
Mike_mvk, wincap показывает, на какие адреса и порты идут пропавшие пакеты?
|
|
|
Записан
|
|
|
|
Mike_mvk
Гость
|
|
« Ответ #4 : 19-10-2004 05:45 » |
|
Девайс немного туповат. Что такое ARP не знает, поэтому шлет бродкастом. Для приема инфы открыт порт 100. Привожу код инициализации этого сокета. if( WSAStartup ( MAKEWORD( 2, 2 ), &wsaData ) != 0 ) return TRACE( WSAGetLastError() );
sock = WSASocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, WSA_FLAG_OVERLAPPED ); if( sock == INVALID_SOCKET ) return TRACE( WSAGetLastError() );
//здесь я увеличивал приемный буфер. на пропадание пакетов это не влияет nParam = 524288; if( setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char*)&nParam, sizeof(nParam)) != 0 ) return TRACE( WSAGetLastError() ); addr.sin_family = AF_INET ; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(100);
if( bind( sock, (LPSOCKADDR) &addr, sizeof( addr ) ) != 0 ) return TRACE( WSAGetLastError() );
WinPcap показывает, что девайс шлет все честно, однако при обмене по другим сокетам в программе не все пакеты читаются из этого сокета.
|
|
« Последнее редактирование: 02-12-2007 14:16 от Алексей1153++ »
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #5 : 19-10-2004 05:58 » |
|
Скорее всего Вы просто не успеваете выбирать данные.
|
|
|
Записан
|
|
|
|
Mike_mvk
Гость
|
|
« Ответ #6 : 19-10-2004 07:08 » |
|
Скорее всего Вы просто не успеваете выбирать данные. Не уверен. Поток данных всего около 8 кб/с. Заполнить такой буфер нереально. Да и программа много ресурсов не жрет.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #7 : 19-10-2004 07:31 » |
|
Mike_mvk, да кто ж так данные принимает... while( Running ) { nParam = sizeof( SOCKADDR_IN ); if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; } if( !Running ) break; //далее обработка пакета ...
надо типа такого while( Running ) { nParam = sizeof( SOCKADDR_IN ); int length = sizeof( PACKET ); char * buffer = (char *) &bp; while (length > 0) { int recv_now = recvfrom( sock, buffer + length, length, 0, &addr, &nParam ); if (recv_now == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; }
length -= recv_now; }
if( !Running ) break; //далее обработка пакета ... }
|
|
« Последнее редактирование: 02-12-2007 14:17 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #8 : 19-10-2004 07:34 » |
|
Mike_mvk, да кто ж так данные принимает... while( Running ) { nParam = sizeof( SOCKADDR_IN ); if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; } if( !Running ) break; //далее обработка пакета ...
надо типа такого while( Running ) { nParam = sizeof( SOCKADDR_IN ); int length = sizeof( PACKET ); char * buffer = (char *) &bp; while (length > 0) { int recv_now = recvfrom( sock, buffer + length, length, 0, &addr, &nParam ); if (recv_now == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; }
length -= recv_now; }
if( !Running ) break; //далее обработка пакета ... }
Помимо основной информации, в потоке идет служебная информация, которую надо отфильтровать и обработать. Да к тому же данные идут асинхронно и постоянно. Придется организовывать кольцевой буфер или что-нить еще. Такой алгоритм не пойдет. У меня склейка идет несколько другим образом. Хотя... Мысль интересная... можно что-ниьт типа такого попробовать...
|
|
« Последнее редактирование: 02-12-2007 14:19 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #9 : 19-10-2004 07:38 » |
|
Виноватая я... вот так { nParam = sizeof( SOCKADDR_IN ); int full_length = sizeof( PACKET ); int rev_length = 0; char * buffer = (char *) &bp; while (rev_length < full_length) { int recv_now = recvfrom( sock, buffer + rev_length, full_length - rev_length, 0, &addr, &nParam ); if (recv_now == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; }
rev_length += recv_now; }
if( !Running ) break; //далее обработка пакета ... }
|
|
« Последнее редактирование: 02-12-2007 14:21 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #10 : 19-10-2004 07:42 » |
|
lapulya, Все равно немножко некорректно... sizeof( PACKET ) - размер одного пакета. Да, к тому же, recvfrom не возвращает количество принятых байт (могу и ошибаться). Но мысль понятна.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #11 : 19-10-2004 07:45 » |
|
я это к чему писал-то, дело в том, что так if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR )
нет гарантии, что ты примешь ВСЕ данные (т.е. что длинна принятых данных составит sizeof( PACKET )), прием должен происходить в цикле!!!! посмотри описание recvfrom, она возвращает количестко принятых байтов!!!! :arrow: принимать надо до тех пор пока мы не выберем данных объемом в sizeof( PACKET ) а ты как раз полагаешься на то что твоя разовая операция выберет ВЕСЬ объем!!! отсюда как раз и "потеря данных"
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #12 : 19-10-2004 07:49 » |
|
lapulya, Я не полагаюсь на то, что разовая операция выберет весь объем. Я выбираю по одному пакету. Разве буфер сокета не сохранит для меня остальные (не выбранные мной) данные?
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #13 : 19-10-2004 07:55 » |
|
буфер то сохранит (не волнуйся), но повторяю, вызов recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam )
не гарантирует того, что в твой bp запишутся данные размером sizeof( PACKET ) ну чисто к примеру, пусть sizeof( PACKET ) равен 10 байтам, после вызова recvfrom ты считаешь что в bp записано (из буфера UDP) ровно 10 байтов, А ЭТО НЕ ВЕРНО, может запросто так случиться что их записано только 3(например)
|
|
« Последнее редактирование: 02-12-2007 14:24 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #14 : 19-10-2004 08:02 » |
|
Вот смотри так может понятнее будет
For stream oriented sockets such as those of type SOCK_STREAM, a call to recvfrom returns as much information as is currently available—up to the size of the buffer supplied.
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #15 : 19-10-2004 08:03 » |
|
lapulya, Если записано 3, то и прочитаю 3. Вообще, я что-то запутался... Поправьте меня, если я скажу что не так. recvfrom возвращает кол-во прочитанных из буфера сокета данных. Если данных меньше - прочитает сколько есть. Если данных нет вообще, то будет ждать. Если данных больше, чем я прошу прочитать, данные останутся в буфере до след. чтения.
Т.е. теоретически, я могу терять данные только если переполню буфер сокета?
|
|
|
Записан
|
|
|
|
Mike_mvk
Гость
|
|
« Ответ #16 : 19-10-2004 08:04 » |
|
Вот смотри так может понятнее будет
For stream oriented sockets such as those of type SOCK_STREAM, a call to recvfrom returns as much information as is currently available—up to the size of the buffer supplied. У меня так sock = WSASocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, WSA_FLAG_OVERLAPPED );
|
|
« Последнее редактирование: 02-12-2007 14:27 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #17 : 19-10-2004 08:11 » |
|
Mike_mvk, вот смотри тыже сам говоришь Если данных меньше - прочитает сколько есть.
а в твоем коде цитирую его while( Running ) { nParam = sizeof( SOCKADDR_IN ); if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; } if( !Running ) break; //далее обработка пакета ...
ты никак не сможешь понять что ты принял ТОЛЬКО (допустим) 3 байта при sizeof( PACKET ) равном 10, ты (твой код думает что он считал их буфера UDP ровно sizeof( PACKET ) байтов, тоесть 10, а это НЕ так.... потому что их там было только 3, вот ты 3 и считал) P.S. все что ты написал Если данных меньше - прочитает сколько есть. Если данных нет вообще, то будет ждать. Если данных больше, чем я прошу прочитать, данные останутся в буфере до след. чтения.
абсолютно верно
|
|
|
Записан
|
С уважением Lapulya
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #18 : 19-10-2004 08:24 » |
|
:oops: :oops: :oops: елы палы........ тут же UDP (во до чего доводит только 6 часов сна в сутки)..... говорю одно думаю про другое.... коли сокет SOCK_DGRAM, то так как ты принимать данные можно, т.е. while( Running ) { nParam = sizeof( SOCKADDR_IN ); if( recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) == SOCKET_ERROR ) { TRACE( WSAGetLastError() ); continue; } if( !Running ) break; //далее обработка пакета ...
корректно (прошу прощения) в твоем случае MSDN говорит следующее For message-oriented sockets, data is extracted from the first enqueued message, up to the size of the buffer supplied. If the datagram or message is larger than the buffer supplied, the buffer is filled with the first part of the datagram, and recvfrom generates the error WSAEMSGSIZE. For unreliable protocols (for example, UDP) the excess data is lost. так что виноватая я, буду читать чего люди спрашивают повнимательнее
|
|
« Последнее редактирование: 02-12-2007 14:29 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #19 : 19-10-2004 08:33 » |
|
а вот TRACE( WSAGetLastError() ); ничего не пишет... например WSAEMSGSIZE
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #20 : 19-10-2004 08:58 » |
|
а вот TRACE( WSAGetLastError() ); ничего не пишет... например WSAEMSGSIZE Это у меня макрос такой.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #21 : 19-10-2004 09:11 » |
|
я понял что макрос.... я имел ввиду, не дает ли ошибок recvfrom при вызове, особенно эту WSAEMSGSIZE
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #22 : 19-10-2004 09:21 » |
|
lapulya, Ошибок нет. SOCKET_ERROR не возникает.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #23 : 19-10-2004 09:33 » |
|
для верности я бы все же проверил количество принятых байтов т.е. написал бы так int result = recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ); if ((result == SOCKET_ERROR) || (result != sizeof( PACKET ))) { TRACE( WSAGetLastError() ); continue; }
|
|
« Последнее редактирование: 02-12-2007 14:31 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #24 : 19-10-2004 09:41 » |
|
lapulya, Именно так и пробовал. Результат: пропадания есть, но на TRACE не попадает.
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #25 : 19-10-2004 10:03 » |
|
я не совсем понял твой пост, так всегда ли result ==sizeof( PACKET ) или нет, т.е. равны ли следующее выражения в любых проводимых тобой тестах 1. recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) 2. sizeof( PACKET )
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #26 : 19-10-2004 10:09 » |
|
я не совсем понял твой пост, так всегда ли result ==sizeof( PACKET ) или нет, т.е. равны ли следующее выражения в любых проводимых тобой тестах 1. recvfrom( sock, (char *) &bp, sizeof( PACKET ), 0, &addr, &nParam ) 2. sizeof( PACKET ) Да, равны. recvfrom всегда возвращает значение равное sizeof( PACKET ).
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #27 : 19-10-2004 10:44 » |
|
мдаааа..... нельзя ли для чистоты эксперимента сменить порт с 100 на что нить другое...
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mike_mvk
Гость
|
|
« Ответ #28 : 19-10-2004 10:50 » |
|
мдаааа..... нельзя ли для чистоты эксперимента сменить порт с 100 на что нить другое... Можно, но сложно... Девайс перепрограммировать надо... Однако похоже это единственное, что осталось попробовать. Буду пробовать... О результатах доложу.
|
|
|
Записан
|
|
|
|
Mike_mvk
Гость
|
|
« Ответ #29 : 19-10-2004 10:58 » |
|
Смена порта на 10000 не помогла. Сбои продолжаются, к сожалению...
Возник вопрос: а может ли каким-либо образом обмен по одному сокету влиять на обмен по другому сокету?
|
|
|
Записан
|
|
|
|
|