Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Проблема с передачей данных WinSock  (Прочитано 16896 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
Виктор
Гость
« : 07-11-2009 14:02 » 

Доброго всем времени суток)))
Моя проблема состоит в следующем: при передаче данных с сервера клиенту половина данных теряется. То есть, просто не доходит до клиента. Клиент и сервер работают в асинхронном режиме. Уже второй день сижу и не могу понять, почему так происходит. Может кто-нибудь уже сталкивался с такой проблемой? И еще один вопрос в связи с этим: может ли переполняться очередь сообщений до того, как их прочитает клиент?
P.S.:
Сокеты потоковые.
« Последнее редактирование: 07-11-2009 17:39 от Sel » Записан
Finch
Спокойный
Администратор

il
Offline 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
Спокойный
Администратор

il
Offline 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
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 07-11-2009 20:37 » 

Попробуй сразу считывать данные, а потом уже локально работать с буффером. Думаю это намного логичнее, чем потрошить системный буффер по 1 байту. Еше, через netstat попробуй отследить, объем данных, который тебе приходит. Для этого отключи все программы, которые обшаются с сетью. Возьми статистику пакетов. Насколько я помню опция -s. Затем запусти свою программу на выполнение, и также после исполнения возьми статистику пакетов. Разница будет объем который пришел на машину. Также на отправителе.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #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 блокировала программу.Мне это нужно чтобы синхронизировать прием и отправку сообащений чтобы не было их потери. Улыбаюсь
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 08-11-2009 12:42 » 

Вообще, сокет по умолчанию должен быть блокирующим. То есть, recv должна блокировать исполнение программы, пока не будет принят блок данных, или пока не произойдёт ошибка. Если это почему-то не так, переключение между блокирующим и неблокирующим режимами осуществляется в WinSock с помощью функции ioctlsocket
Записан
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 08-11-2009 14:15 » 

Похвальное стремление разобраться Улыбаюсь
Однако, явно виден пробел в знаниях, такое впечатление, что Вы, Виктор, пытаетесь написать программу, до конца не представляя себе механизмы сокетов и протоколов связи. Поверьте моему опыту - лучше потратить какое-то время на внимательное прочтение книги, хотя бы начало, чем пытаться освоить программирование TCP методом "программного тыка" Улыбаюсь Работа пойдет намного быстрее, а главное - будет явно более осмысленной. Судя по Вашим вопросам, у Вас пока явно нет общей картины того, как работать с с сокетами и протоколом. Почитайте Снайдера, отпадет сразу куча вопросов, отвечать на Ваши вопросы ведь нисколько не жалко, только времени у Вас на такое познание уйдет на порядок больше Улыбаюсь
Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Виктор
Гость
« Ответ #12 : 08-11-2009 16:15 » 

Спасибо за совет уже начал читать  Снайдера))))
Записан
Виктор
Гость
« Ответ #13 : 09-11-2009 14:15 » 

Михалыч огромное вам спасибо за то что вы мне посоветовали книгу Снайдера)))После ее прочтения потребовалось 45 минут на дописание программы после чего все корректно заработало))))Еще раз СПАСИБО Улыбаюсь
Записан
Михалыч
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #14 : 09-11-2009 16:44 » 

Было бы за что Улыбаюсь Завсегда пожалуйста Улыбаюсь
Вы, главное, не бросайте ее на полпути, там очень много полезного Улыбаюсь
« Последнее редактирование: 09-11-2009 16:46 от Михалыч » Записан

Поживем - увидим... Доживем - узнаем... Выживу - учту  Улыбаюсь
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines