Виктор
Гость
|
|
« : 07-11-2009 14:02 » |
|
Доброго всем времени суток))) Моя проблема состоит в следующем: при передаче данных с сервера клиенту половина данных теряется. То есть, просто не доходит до клиента. Клиент и сервер работают в асинхронном режиме. Уже второй день сижу и не могу понять, почему так происходит. Может кто-нибудь уже сталкивался с такой проблемой? И еще один вопрос в связи с этим: может ли переполняться очередь сообщений до того, как их прочитает клиент? P.S.: Сокеты потоковые.
|
|
« Последнее редактирование: 07-11-2009 17:39 от Sel »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #1 : 07-11-2009 16:32 » |
|
Какой именно протокол используеш? Если TCP, то сам протокол гарантирует доставку данных. В UDP вполне могут быть потери. Также не мешало посмотреть на код, который ты сделал.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Виктор
Гость
|
|
« Ответ #2 : 07-11-2009 18:07 » |
|
Нет , делаю не на UDP) Вот код отправителя. Эта функция перебирает все содержимое заданной директории и отправляет данные о них для копирования структуры данной директории на клиенте. void getspisdir(TCHAR *Dir,TCHAR *Path) { char *ch; TCHAR *ch1; ifstream fin; int l; char *msg; char *msg1; //TCHAR *path=_T(""); char bufer[4090]; char bufer1[4096]; ZeroMemory(bufer,sizeof(bufer)); WIN32_FIND_DATA fd;//Инициализируем структуру HANDLE hfile;//Дескриптор файла TCHAR *Dir1;//Адрес к папке или файлу TCHAR *Dir2=new TCHAR[_tcslen(Dir)+5]; _tcscpy(Dir2,Dir); _tcscat(Dir2,_T("\\*")); hfile=FindFirstFile(Dir2,&fd); if(hfile==INVALID_HANDLE_VALUE) { //Нет такого файла } else { Dir1=new TCHAR[_tcslen(Dir)+8+_tcslen(fd.cFileName)]; _tcscpy(Dir1,Dir); _tcscat(Dir1,_T("\\")); _tcscat(Dir1,fd.cFileName); if(SetCurrentDirectory(Dir1)) { if(_tcscmp(fd.cFileName,_T("."))!=0) { }
//Отправка информации о директории } else { //значит это фаил //отправка информации о файле } } while(FindNextFile(hfile,&fd)) { Dir1=new TCHAR[_tcslen(Dir)+8+_tcslen(fd.cFileName)]; _tcscpy(Dir1,Dir); _tcscat(Dir1,_T("\\")); _tcscat(Dir1,fd.cFileName); if(SetCurrentDirectory(Dir1)) { if(_tcscmp(fd.cFileName,_T(".."))!=0) { ch=new char[4]; msg=datamsg(_T(""),_T("Dir"),fd.cFileName,Path); l=strlen(msg)+1; _itoa(l,ch,10); ch1=ConvertToCharArray(ch); msg1=datamsg(ch1,_T("Dir"),fd.cFileName,Path); l=strlen(msg1)+1; send(cli,msg1,l,0); TCHAR *path=getpath(DirPathSourse,Dir1); getspisdir(Dir1,path); delete[] msg; delete[] path; delete[] ch; //отправка информации о директории } } else { ch=new char[4]; msg=datamsg(_T(""),_T("File"),fd.cFileName,Path); l=strlen(msg)+1; _itoa(l,ch,10); ch1=ConvertToCharArray(ch); msg1=datamsg(ch1,_T("File"),fd.cFileName,Path); l=strlen(msg1)+1; send(cli,msg1,l,0); fin.open(Dir1,ios_base::binary); while(!fin.eof()) { ZeroMemory(bufer,sizeof(bufer)); ZeroMemory(bufer1,sizeof(bufer1)); fin.read(bufer,4080); ch=new char[4]; l=strlen(bufer)+strlen("Write*")+1; _itoa(l,ch,10); strcpy(bufer1,ch); strcat(bufer1,"*"); strcat(bufer1,"Write*"); strcat(bufer1,bufer); strcat(bufer1,"\0"); l=strlen(ch)+strlen("*")+strlen(bufer)+strlen("Write*")+1; send(cli,bufer1,l,0); } fin.close(); l=strlen("7*?end?*")+1; send(cli,"7*?end?*",9,0); //значит это фаил //отправка информации о файле } } }
|
|
« Последнее редактирование: 07-11-2009 18:15 от Sel »
|
Записан
|
|
|
|
Виктор
Гость
|
|
« Ответ #3 : 07-11-2009 18:09 » |
|
Вот код приемника. Сначала он с читывает первые несколько байт с размером сообщения , а потом считыва ет остаток , уже точно зная его размер. void OnWSANetEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { int rc; int j=0; int k=0;
char DirPath[520]; char command[10]; char Name[260]; char dirloc[260]; char size[5]; char *ch=new char[1]; int s; ZeroMemory(Temp,sizeof(Temp)); ZeroMemory(size,sizeof(size)); ZeroMemory(command,sizeof(command)); ZeroMemory(Name,sizeof(Name)); ZeroMemory(dirloc,sizeof(dirloc)); ZeroMemory(DirPath,sizeof(DirPath));
SOCKET sock; if (WSAGETSELECTEVENT(lParam) == FD_READ) // с клиента пришли данные и их надо прочесть {//Фаил пришли данные на запись читаем int i=0; int flag=0; sock = (SOCKET)wParam; rc = recv(sock,ch,1,0); while(*ch!='*') { size[i]=*ch; recv(sock,ch,1,0); if(i>3) { ch="*"; flag=1; } i++; } if(flag!=1) { s=atoi(size); } else s=0;
if(s>0) { rc=recv(sock,Temp,s,0); Temp[rc]='\0'; } if (rc>0 && s>0) { i=0; while(Temp[i]!='*') { command[i]=Temp[i]; i++; } command[i]='\0'; if (!strcmp(command,"File")) //обработчик на создание файла------------------------------------------ { int k=0; i++; while(Temp[i]!='*') { Name[k]=Temp[i]; k++;i++; } k=0; i++; while(Temp[i]!='*') { dirloc[k]=Temp[i]; k++;i++; } strcpy(DirPath,ConvertToCharArray(DirPathDest)); strcat(DirPath,"\\"); strcat(DirPath,dirloc); strcat(DirPath,"\\"); strcat(DirPath,Name); strcat(DirPath,"\0"); fout.open(ConvertToCharArray(DirPath),ios_base::binary); } if (!strcmp(command,"Dir")) //обработчик на создание файла------------------------------------------ { int k=0; i++; while(Temp[i]!='*') { Name[k]=Temp[i]; k++;i++; } Name[k]='\0'; k=0; i++; while(Temp[i]!='*') { dirloc[k]=Temp[i]; k++;i++; } dirloc[k]='\0'; strcpy(DirPath,ConvertToCharArray(DirPathDest)); strcat(DirPath,"\\"); strcat(DirPath,dirloc); strcat(DirPath,"\\"); strcat(DirPath,Name); strcat(DirPath,"\0"); CreateDirectory(ConvertToCharArray(DirPath),NULL); } if (!strcmp(command,"Write")) { i++; while(Temp[i]!='\0') { fout.put(Temp[i]); i++; } } if(!strcmp(command,"?end?")) { fout.close(); } } } else { if (WSAGETSELECTEVENT(lParam) == FD_CLOSE) { // клиент разорвал соединение со своей стороны sock = (SOCKET) wParam; closesocket(sock); MessageBox(NULL,_T("Сервер разорвал соединение"),_T("Сообщение"),MB_OK|MB_ICONWARNING); } } //DirPath=NULL; }
P.S. я то льк о начинаю раз бираться с сокетами , если что , сильно не бейте)))
|
|
« Последнее редактирование: 07-11-2009 18:14 от Sel »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #4 : 07-11-2009 19:14 » |
|
В твоем коде отправшика, честно говоря не увидел места, где именно идет иницилизация сокетов.
Когда то я делал серверную и клиентскую часть на UDP сокетах. Заметил такую вешь, что пакеты затераются другими пакетами, если вовремя их не взять. Выход из положения у меня был: Прослушивание сокета я сделал в отдельной нитке (thread). В ней просто накидывал данные в буфер, а уже в головной нитке отрабатывал данные. Кстати мьютексы для синхронизации также тормозили получение.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Виктор
Гость
|
|
« Ответ #5 : 07-11-2009 19:54 » |
|
Вот инициализация сокета сервера(с него отправляются сообщения клиенту) void start_socket_srv(HWND hwnd,SOCKET &s) {
int rc; struct sockaddr_in srv_address; s = socket(AF_INET,SOCK_STREAM,0); if (s == INVALID_SOCKET) { MessageBox(NULL,_T("Не удалось создать сокет"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } srv_address.sin_family = AF_INET; srv_address.sin_addr.S_un.S_addr = INADDR_ANY; srv_address.sin_port = htons(SERV_PORT); if (bind(s,(LPSOCKADDR)&srv_address,sizeof(srv_address)) == SOCKET_ERROR) { MessageBox(NULL,_T("Не удалось связать сокет"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } if (listen(s,5) == SOCKET_ERROR) { MessageBox(NULL,_T("Не удалось прослушать сокет"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } rc=WSAAsyncSelect(s,hwnd,WSA_ACCEPT,FD_ACCEPT); if (rc > 0) { MessageBox(NULL,_T("Не удалось запустить сервер"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } MessageBox(NULL,_T("Сервер запущен"),_T("Сообщение"),MB_OK|MB_ICONINFORMATION);
}
А вот инициализация клиента void strat_socket_cli(HWND hWnd,SOCKET &c) { //PHOSTENT phe; c = socket(AF_INET,SOCK_STREAM,0); if (c == INVALID_SOCKET) { MessageBox(NULL,_T("Не удалось создать сокет"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } dest_sin.sin_family = AF_INET; dest_sin.sin_port = htons(SERV_PORT); dest_sin.sin_addr.s_addr=serv_ip; if (connect(c,(LPSOCKADDR)&dest_sin,sizeof(dest_sin)) < 0) { MessageBox(NULL,_T("Не удалось соединиться с сервером"),_T("Ошибка"),MB_OK|MB_ICONERROR); return; } MessageBox(NULL,_T("Соединение установлено"),_T("Сообщение"),MB_OK|MB_ICONINFORMATION);
|
|
« Последнее редактирование: 07-11-2009 19:56 от Finch »
|
Записан
|
|
|
|
Виктор
Гость
|
|
« Ответ #6 : 07-11-2009 19:59 » |
|
Блин, я вот не понимаю ве зде пишут , что при передаче по TCP/IP информация не теряется , если это не UDP сокеты . Так куда же деваются отправленные мной куски бинарного файла ?
|
|
« Последнее редактирование: 07-11-2009 20:09 от Sel »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #7 : 07-11-2009 20:37 » |
|
Попробуй сразу считывать данные, а потом уже локально работать с буффером. Думаю это намного логичнее, чем потрошить системный буффер по 1 байту. Еше, через netstat попробуй отследить, объем данных, который тебе приходит. Для этого отключи все программы, которые обшаются с сетью. Возьми статистику пакетов. Насколько я помню опция -s. Затем запусти свою программу на выполнение, и также после исполнения возьми статистику пакетов. Разница будет объем который пришел на машину. Также на отправителе.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Михалыч
|
|
« Ответ #8 : 08-11-2009 08:08 » |
|
Я с винсокетами, к сожалению (а может к счастью) дел не имел, ибо работаю под unix-like OS QNX. Учился программировать сетевые приложения вот по этой книге: Йон Снейдер "Эффективное программирование TCP/IP". В сети она точно есть, сам скачивал - поищите. Настоятельно рекомендую всем. Более разжеванного материала с примерами я, пожалуй, не видел. Там, кстати не только TCP, но и UDP рассматривается. И с примерами реализации под винду тоже. Т.е., примеры там совместимые. Кстати, там очень хорошо освещены вопросы надежности связи, именно после этой книги я перестал верить в миф о "надежности TCP, гарантирующей доставку". Это, конечно, так, протокол для надежной связи и придумывался, однако, зачастую не учитываются очень многие моменты... Вот, лишь небольшая цитата: Как уже неоднократно отмечалось, TCP - надежный протокол. Иногда эту мысль выражают так: «TCP гарантирует доставку отправленных данных». Хотя эта формулировка часто встречается, ее следует признать исключительно неудачной. Предположим, что вы отсоединили хост от сети в середине передачи данных. В таком случае TCP не сможет доставить оставшиеся данные. А на практике происходят сбои в сети, аварии серверов, выключение машины пользователями без Разрыва TCP-соединения. Все это мешает TCP доставить по назначению данные, преданные приложением. Но еще важнее психологическое воздействие фразы о «гарантируемой TCP ставке» на излишне доверчивых сетевых программистов. Разумеется, никто не считает, что TCP обладает магической способностью доставлять данные получателю, невзирая на все препятствия. Вера в гарантированную доставку проявляется в небрежном программировании и, в частности, в легкомысленном отношении к проверке ошибок. Что такое надежность Прежде чем приступать к рассмотрению ошибок, с которыми можно столкнутся при работе с TCP, обсудим, что понимается под надежностью TCP. Если TCP нe гарантирует доставку всех данных, то что же он гарантирует? Первый вопрос: кому дается гарантия?
Книга, кстати, отнюдь не огромных размеров, и написана очень доступным языком
|
|
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
Виктор
Гость
|
|
« Ответ #9 : 08-11-2009 12:22 » |
|
Спасибо всем большое за ответы ))Возник еще один вопрос а можно ли как бы так правильно выразиться выключать асинхронность сокетов чтобы функция recv блокировала программу.Мне это нужно чтобы синхронизировать прием и отправку сообащений чтобы не было их потери.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #10 : 08-11-2009 12:42 » |
|
Вообще, сокет по умолчанию должен быть блокирующим. То есть, recv должна блокировать исполнение программы, пока не будет принят блок данных, или пока не произойдёт ошибка. Если это почему-то не так, переключение между блокирующим и неблокирующим режимами осуществляется в WinSock с помощью функции ioctlsocket
|
|
|
Записан
|
|
|
|
Михалыч
|
|
« Ответ #11 : 08-11-2009 14:15 » |
|
Похвальное стремление разобраться Однако, явно виден пробел в знаниях, такое впечатление, что Вы, Виктор, пытаетесь написать программу, до конца не представляя себе механизмы сокетов и протоколов связи. Поверьте моему опыту - лучше потратить какое-то время на внимательное прочтение книги, хотя бы начало, чем пытаться освоить программирование TCP методом "программного тыка" Работа пойдет намного быстрее, а главное - будет явно более осмысленной. Судя по Вашим вопросам, у Вас пока явно нет общей картины того, как работать с с сокетами и протоколом. Почитайте Снайдера, отпадет сразу куча вопросов, отвечать на Ваши вопросы ведь нисколько не жалко, только времени у Вас на такое познание уйдет на порядок больше
|
|
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
Виктор
Гость
|
|
« Ответ #12 : 08-11-2009 16:15 » |
|
Спасибо за совет уже начал читать Снайдера))))
|
|
|
Записан
|
|
|
|
Виктор
Гость
|
|
« Ответ #13 : 09-11-2009 14:15 » |
|
Михалыч огромное вам спасибо за то что вы мне посоветовали книгу Снайдера)))После ее прочтения потребовалось 45 минут на дописание программы после чего все корректно заработало))))Еще раз СПАСИБО
|
|
|
Записан
|
|
|
|
Михалыч
|
|
« Ответ #14 : 09-11-2009 16:44 » |
|
Было бы за что Завсегда пожалуйста Вы, главное, не бросайте ее на полпути, там очень много полезного
|
|
« Последнее редактирование: 09-11-2009 16:46 от Михалыч »
|
Записан
|
Поживем - увидим... Доживем - узнаем... Выживу - учту
|
|
|
|