Slowhan 0 21 июля, 2011 Опубликовано 21 июля, 2011 (изменено) · Жалоба Люди, я знаю, что лето, душно и все достало. Но помогите пожалуйста советом ибо у меня совсем горят сроки... А вопросы даже больше теоретические... Есть прибор(arm7), отсылающий по tcp посылки удаленной системе(нетбук). Посылки достаточно объемны - 100 КБайт. Т.к. софт для удаленной системе будет писаться на стороне заказчика, то проверяю скорость работы обычной терминалкой. И что я вижу - каждый фрагмент tcp посылки передается раз в 200 мс. Стал гуглить - оказалось в винде (и не только) есть такая штука, delay ack - т.е. винда отправляет ACK на посылку раз в 200 мс. Меня такое совсем не устраивает... Мои 100 Кбайт получается разбиваются на примерно 68 посылок и отправляются по 200 мс каждая - в сумме 14 секунд. Ужас. Стал гуглить касаемо моего стека (взял кейловский). На кейловском форуме нашел решение - создать сокет с атрибутом TCP_TYPE_DELAY_ACK. Тогда каждая посылка будет разбиваться на две подряд и в этом случаи винда отвечает сразу. После этих действий скорость заметно возросла, но... Но все равно не достаточно высоко - для меня это критично. В WireShark во время передачи моей 100 кбайтной посылки иногда проскакивает после обычного TCP ACK от нетбука, еще какойто непонятный пакет - [TCP Window Update]. И это заметно отжирает время. Собственно вопросы: 1) Можно ли настроить delay ack винды. Скажем 10 мсек вместо стандартных 200? И как?... :) 2) В програмирование для винды не силен, с сокетами не работал. Человек котоырй будет писать софт для моей системы, как то может сам отсылать ACK или же в винсокетах используется стандартный delay ack в 200 мсек? Он пишет на си шарпе. 3) Что такое [TCP Window Update] в сниффере и почему он происходит? Как от него избавиться? Спасибо Всем кто откликнется! Изменено 21 июля, 2011 пользователем Slowhan Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SFx 0 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба а какая у Вас скорость должна быть? выложите еще pcap file. работу с сокетами в винде лучше делать на winapi. C# будет несщадно тормозить все это дело. тем более если Вам важна скорость, хотя смотря какой компьютер. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба 1) Можно ли настроить delay ack винды. Скажем 10 мсек вместо стандартных 200? И как?... Но не нужно. Правильное решение - вменяемый стек, который правильно работает с Delayed Ack. Между прочим, решение по разбивке пакета пополам - оно паллиативно до жути и работает только в быстрой сети. 2) В програмирование для винды не силен, с сокетами не работал. Человек котоырй будет писать софт для моей системы, как то может сам отсылать ACK или же в винсокетах используется стандартный delay ack в 200 мсек? Он пишет на си шарпе. Аллах до делов велик, что не позволил всем кому не попадя крутить подтверждения TCP (да и вообще всякие параметры стека). Трогать его не надо, это я уже говорил выше. 3) Что такое [TCP Window Update] в сниффере и почему он происходит? Как от него избавиться? Ну я так понимаю, у Вас терминалка тормозит. Посмотрите внимательно, как меняется поле окна в пакетах подтверждения от большого брата. Видимо оно уменьшается до 0, потом, когда терминалка выводит все и выгребает следующую порцию данных, происходит уведомление передающей стороны о появлении места в окне пакетом TCP Window Update. Эта проблема уйдет сама, когда у Вас будет вменяемый быстрый код на большом брате, а не консолька. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Slowhan 0 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба Скорость хотелось бы 2-3 Мбайта в секунду. Реально ли это на кейловском стеке? По тестам терминалки только около мегабайта... Между прочим, решение по разбивке пакета пополам - оно паллиативно до жути и работает только в быстрой сети. Там не пополам, там разбивается на 1514 байт и 60. Вроде так и делают умные люди?) просто по мне на отправку второго, пусть и маленького пакета уходит ценное время и проще исправить настройку стека, чтобы отвечал ACK на каждый пакет... Хотя может я заблуждаюсь... Аллах до делов велик, что не позволил всем кому не попадя крутить подтверждения TCP (да и вообще всякие параметры стека). Трогать его не надо, это я уже говорил выше. А как там в общем происходит работа? ВинСокет как-то понимает что пришел самый последний кусочек большой TCP посылки или это делается по таймауту у "большого брата"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба ВинСокет как-то понимает что пришел самый последний кусочек большой TCP посылки Подтверждается каждый второй пакет, а если новые пакеты не приходят, то через 200мс. Вменяемый стек, имея данные для передачи, должен начинать эту передачу не ожидая подтверждения. Реально ли это на кейловском стеке? По тестам терминалки только около мегабайта... Реально. Замените терминалку на самонаписанное ПО. Ну хотя-бы вот так (пример на C++ Builder): //--------------------------------------------------------------------------- #include <vcl.h> #include <winsock2.h> #pragma hdrstop #include "main.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { WSADATA WSAData; if(WSAStartup(MAKEWORD(2,0), &WSAData) != 0) { ShowMessage("Error: WSAStartup failed!"); } } //--------------------------------------------------------------------------- #define SAMPLE_RATE (130208UL) static const unsigned char wav_hdr[]={ 0x52,0x49,0x46,0x46,0x00,0x00,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20, 0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,(SAMPLE_RATE>>0)&0xFF,(SAMPLE_RATE>>8)&0xFF,(SAMPLE_RATE>>16)&0xFF,0x00,0xC0,0x27,0x09,0x00, 0x08,0x00,0x20,0x00,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00 }; HANDLE fout; DWORD total_size; SOCKET ADCsock; void __fastcall TForm1::StartBTClick(TObject *Sender) { struct hostent * he; struct sockaddr_in addr; if ((he=gethostbyname("usm.rov"))==NULL) { ShowMessage("Error: gethostbyname failed!"); return; } if (he->h_addr==NULL) { ShowMessage("Error: Host not found!"); return; } memset(&addr, 0, sizeof(addr)); memcpy(&(addr.sin_addr.s_addr), he->h_addr, sizeof(addr.sin_addr.s_addr)); addr.sin_port=htons(2000); addr.sin_family=PF_INET; if ((ADCsock=socket(PF_INET, SOCK_STREAM, 0))==INVALID_SOCKET) { ShowMessage("Error: Can't create socket!"); return; } { DWORD v_ctl=1; ioctlsocket(ADCsock,FIONBIO,&v_ctl); //Неблокирующийся режим } if (connect(ADCsock,(const struct sockaddr *)&addr, sizeof(addr))) { int err=WSAGetLastError(); if (err!=WSAEWOULDBLOCK) { closesocket(ADCsock); ShowMessage("Error: Connect failed!"); return; } fd_set rfds; //Ожидающие данных (или ответ, или закрытие) fd_set wfds; //Ожидающие подключения (готовность писать) fd_set efds; //Ожидающие подключения влетают сюда при ошибке struct timeval tv; tv.tv_sec=3; //Дольше 3х секунд не ждем, нефиг tv.tv_usec=0; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(ADCsock,&wfds); FD_SET(ADCsock,&efds); int i=select(0,NULL,&wfds,&efds,&tv); if (i!=0) { if (FD_ISSET(ADCsock,&wfds)) { //соединились goto L1; } } //Ахтунг, короче closesocket(ADCsock); ShowMessage("Error: Can't connect!"); return; } L1: DWORD br; fout = CreateFile("adc_data.wav",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, 0); WriteFile(fout,wav_hdr,sizeof(wav_hdr),&br,NULL); total_size=0; Timer1->Enabled=true; LblReceivedBytes->Caption=""; } //--------------------------------------------------------------------------- void __fastcall TForm1::StopBTClick(TObject *Sender) { if (!Timer1->Enabled) return; Timer1->Enabled=false; shutdown(ADCsock, SD_BOTH); closesocket(ADCsock); DWORD br=0; if (total_size&4) { WriteFile(fout,&br,4,&br,NULL); } //WriteFile(fout,RE_ARR,total_bytes,&br,NULL); SetFilePointer(fout,0x28,NULL,FILE_BEGIN); WriteFile(fout,&total_size,4,&br,NULL); SetFilePointer(fout,0x04,NULL,FILE_BEGIN); total_size+=0x24; WriteFile(fout,&total_size,4,&br,NULL); CloseHandle(fout); } //--------------------------------------------------------------------------- void __fastcall TForm1::ADCsockError(TObject *Sender, TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode) { ShowMessage("Errorcode: "+ErrorCode); } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { int l; String s; do { char p[8192]; l=recv(ADCsock,p,8192,0); if (l<0) { int err=WSAGetLastError(); if (err!=WSAEWOULDBLOCK) { s="Error: recv() return error "; s+=err; s+="!"; ShowMessage(s); } } else if (l>0) { DWORD br; WriteFile(fout,p,l,&br,NULL); total_size+=l; } } while(l>0); s="Received "; s+=total_size; s+="bytes..."; LblReceivedBytes->Caption=s; } //--------------------------------------------------------------------------- Тут чтение выполняется по таймеру, дабы не морочиться с ожиданиями и прочим. Можно просто вызывать Timer1Timer в вечном цикле. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Slowhan 0 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба Вменяемый стек, имея данные для передачи, должен начинать эту передачу не ожидая подтверждения. Вот тут не понял, что Вы имеете ввиду. Какой же это вменяемый стек, если он без подтверждения работает. Тогда UDP какое-то получается. За пример кода большое спасибо, буду разбираться! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба Вот тут не понял, что Вы имеете ввиду. Подтверждение не надо ждать принципиально, потом придет. А новые данные надо сразу передавать. Именно за счет этого будет скорость. А если вдруг пакет в потоке потеряется, то есть два метода быстрого восстановления - Fast Retransmit (попроще) и Selective ACK (посложнее). Рекомендую накормить гугль этими словами и плотно раскурить что и как. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Slowhan 0 21 июля, 2011 Опубликовано 21 июля, 2011 (изменено) · Жалоба Подтверждение не надо ждать принципиально, потом придет. А новые данные надо сразу передавать. Именно за счет этого будет скорость. А если вдруг пакет в потоке потеряется, то есть два метода быстрого восстановления - Fast Retransmit (попроще) и Selective ACK (посложнее). Рекомендую накормить гугль этими словами и плотно раскурить что и как. Гугл, конечно, накормлю, но у кейловского TCP такая реализация функции send_data, что она не будет работать, если не пришел ACK после предыдущей посылки. Можно при создании сокета выставить упомянутый мной флаг и тогда внутри функции send_data кеил делит пакет на 2 - 1510 и 60 байт. Т.е. скорость таки теряется в этой реализации... Собственно вот подтверждение моих слов - http://www.keil.com/forum/19008/ Если не секрет какие стеки Вы используете? Правда особо ковырять и портировать время не позволяет сейчас - но на будущее буду иметь ввиду. Изменено 21 июля, 2011 пользователем Slowhan Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба но у кейловского TCP такая реализация Ну так а кто Вас заставлял брать этот стек? Теперь все, ойц. Если не секрет какие стеки Вы используете? Я использую свой собственный. Вам посоветую смотреть в сторону lwip - он хоть и здоровый, но куда более адекватен. Уважаемый zltigo рекомендует смотреть в сторону TCP-стека от TN-kernel - там, вроде бы, на основе классического кода от bsd-sockets сделано все. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Slowhan 0 21 июля, 2011 Опубликовано 21 июля, 2011 (изменено) · Жалоба Ну так а кто Вас заставлял брать этот стек? Теперь все, ойц. Соблазнителен больно - и документирован, и сразу поддержка компилятора. А тот же lwip прикручивать и прикручивать, адаптировать и адаптировать ибо готового проекта для моего lpc2368 неть. Хотя полезно, конечно, при наличии времени. =) Спасибо за консультации, теперь хоть что-то прояснилось! Буду надеяться, что удаленный программист заказчика грамотно организует все и нужные скорости вытянем. Изменено 21 июля, 2011 пользователем Slowhan Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 июля, 2011 Опубликовано 21 июля, 2011 · Жалоба Соблазнителен больно - и документирован, и сразу поддержка компилятора. Только вот геморрой в комплекте забыли прорекламировать ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться