Модераторы: feodorv

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Нужна помощь, При работе с сокетами Windows 
:(
    Опции темы
vikaz
Дата 16.12.2008, 09:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Всем добрый день!
Передо мной поставили задачу написать клиент-серверное приложение, обменивающиеся данными через интернет. Есть клиентское приложение, которое отправляет на сервер текстовые сообщения, являющиеся по сути командами, а также графику (bmp, jpg, gif). Сервер получает данную строку и формирует из нее SQL запрос, данный запрос отправляется базе MySQL, которая отрабатывает данный запрос и возвращает данные, которые переправляются обратно клиенту. Клиент их визуализирует. Примерное количество клиентов, которые будут подключаться к серверу равно 1000 (это примерно). Пишу на с++ Builder 2009.
Сначала я думал писать при помощи Indy, но ребята меня переубедили, что этого не стоит делать, а лучше написать транспортный модуль самому. Под транспортным модулем я подразумеваю не новый протокол обмена данными по сети, а так сказать интерфейс работающий с TCP/IP протоколом.
Почитав литературу и порывшись на сайтах, нашел много информации и методов работы с TCP/IP, НО НА КАКОМ ОСТАНОВИТЬСЯ не знаю. Поэтому и прошу у Вас помощи.
Вот основные методы для работы с TCP/IP протоколом:
1. Блокирующий(синхронный) сокет.
2. Не блокирующий (асинхронный) сокет.

Для нормальной работы первого метода, создаются потоки, при подключении нового клиента к серверу. Как мне кажется плюс этого метода, что одна на писаная функция работы с клиентом и каждый раз запускаемая в потоке решает  все задачи, которые я пропишу. Но вопрос, не накладно ли будет для железа создавать 1000 потоков, разгребет ли, и есть ли смысл и целесообразно ли? Но есть и большой минус. Допустим, что был вызов функции recv, но по каким-то причинам она не вернула данные. В этом случае она останется заблокированной навечно, и сервер больше не будет реагировать на действия пользователя.

Второй метод более гибкий, но он и труднее в программировании и лишен выше описанной проблемы.
Для асинхронных соке тов так же можно выделить несколько методов:
1. Использование массива соке тов и с использованием select
2. Использование соке тов через события windows
3. Асинхронная работа через объекты событий.

Описывать +/- каждого метода долго. Но вся проблема, для меня, упирается в то, как использовать асинхронные сокеты 2 и 3 для 1000 подключенных, как отслеживать, от кого пришла стока и кому ответить (для всех трех методов).

И ко всему этому остается проблема правильности доставки сообщений, не факт, и это известно, что данные придут сразу все. Могут придти не все, а если сообщения маленькие, то они могут придти сразу оба. Как при использовании асинхронного сокета учесть это и при синхронном тоже?
Надеюсь не утомил. smile 
Очень нужна помощь, направьте на путь истинный! smile
Заранее спасибо.


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
J0ker
Дата 17.12.2008, 05:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 1
Всего: 14



не изобретайте велосипед
используете паттерн реактор
кол-во потоков = кол-во ядер * 2
для винды используете completion ports, для *nix - пулы - если есть, select - если пулов нет - оптимально можно заюзать boost::asio - там использование этих фич скрыто в классах


--------------------
user posted image
PM MAIL   Вверх
vikaz
Дата 17.12.2008, 07:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



J0ker, можно подробнее. Много "красивых" слов. Но пока они мне не все понятны. smile


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
Cтpaнник
Дата 17.12.2008, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 53
Регистрация: 12.10.2008
Где: Россия, Санкт-Пет ербург

Репутация: нет
Всего: нет



PM MAIL   Вверх
vikaz
Дата 17.12.2008, 12:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Cтpaнник, не могу с этого сайта ничего скачать. Можешь скинуть скаченные архивы, благо они весят не много. + ссылочку на описание IOCP. не могу найти русскоязычного описания! Заранее спасибо!


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
Олег2005
Дата 17.12.2008, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



Тут найдете основное:

Присоединённый файл ( Кол-во скачиваний: 16 )
Присоединённый файл  IOCP.zip 51,81 Kb
PM MAIL WWW MSN   Вверх
Cтpaнник
Дата 17.12.2008, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 53
Регистрация: 12.10.2008
Где: Россия, Санкт-Пет ербург

Репутация: нет
Всего: нет



vikaz, там чтобы что-то скачивать (архивы, примеры и т.п.) просто надо зарегистрироваться. Это бесплатно smile
PM MAIL   Вверх
J0ker
Дата 17.12.2008, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 1
Всего: 14



Цитата(vikaz @ 17.12.2008,  07:19)
J0ker, можно подробнее. Много "красивых" слов. Но пока они мне не все понятны. smile

паттерн многопоточный реактор - создаете пул потоков которые сидят на ожидании (лучше организовать LIFO)
в случае пулов и completion ports - когда приходит сообщение первый свободный поток из очереди его подхватывает и вызывает соответствующий обработчик
в случае использования select - диспетчер подхватывает сообщение, и соответственно типу передает его потоку инициализированному конкретным обработчиком
по поводу кол-ва потоков в пуле
обычно бессмысленно держать в работе больше потоков, чем имеется ядер
но учитывая особенности например completion ports, надо иметь под рукой запасные потоки, т.к. при попадании работающего потока в операцию, вызывающую какую-либо wait функцию, система считает, что можно запустить еще один поток.
т.о. все зависит от того, что делает обработчик - если это голые вычисления, допустим, где гарантированно нет wait вызовов, то можно ограничится кол-вом потоков равным кол-ву ядер, если-же есть обращение, например, к удаленной базе данных с длительными ожиданиями - то здесь нужно увеличить кол-во потоков в пуле больше чем 2*кол-во ядер
можно попробовать сделать динамический пул - если запущеный поток последний в пуле, то создается еще один - т.е. пул никогда не бывает пустым, если-же поток не запускался определенное время, то он уничтожается - по идее для LIFO эта тактика должна быть довольно эффективна...

ЗЫЖ да, и посмотрите все-таки boost::asio - возможно это как раз то, что вам нужно



--------------------
user posted image
PM MAIL   Вверх
vikaz
Дата 18.12.2008, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Ребята, всем огромное спасибо, буду смотреть и разбираться. Олег2005 и тебе спасибо за файл. smile 


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
vikaz
Дата 18.12.2008, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Олег2005, это вырезка, а откуда? Если не секрет.....


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
Олег2005
Дата 18.12.2008, 12:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



Это из моего учебника по сетевому программированию smile 
PM MAIL WWW MSN   Вверх
MAKCim
Дата 18.12.2008, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 6
Всего: 207





--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
vikaz
Дата 18.12.2008, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



MAKCim спс, за ссылку. Олег2005 и много у тебя там такого интересного? Можно ли как-то её почитать?


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
vikaz
Дата 19.12.2008, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Олег2005, спасибо еще раз за инфу. Но у меня по ней возникли вопросы. А именно к серверной части, так как в клиентской все просто.

Вопросы:
1. В фунции main в конце есть сл. код:

Код

//Добавляем клиента в список
ClientList.insert(ClientList.end(),client);
// Создаем overlapped-структуру 
ovpConnection * op = new ovpConnection;
//Заполняем overlapped-структуру 
op->sock_handle = client;
op->op_type = ovpConnection::op_type_recv;
op->buffer = new char[BUFF_SIZE];
op->hEvent = 0;
op->client_number=++ClientCount;
strcpy(buffer,"Клиент № %d подключился, активных клиентов %d\n");
CharToOem(buffer,buffer);
printf(buffer,ClientCount,ClientList.size());
unsigned long b;
WSABUF buf;
buf.buf = op->buffer;
buf.len = BUFF_SIZE;
flags=0;
err=WSARecv(op->sock_handle, &buf, 1, &b, &flags, op, 0);
if(!err)
{
   strcpy(buffer,"Ошибка ф-ции WSARecv");
   CharToOem(buffer,buffer);
   printf("%s %d\n",buffer, WSAGetLastError());
}


Сам вопрос, зачем в конце сл. строки? 
Код

unsigned long b;
WSABUF buf;
buf.buf = op->buffer;
buf.len = BUFF_SIZE;
flags=0;
err=WSARecv(op->sock_handle, &buf, 1, &b, &flags, op, 0);
if(!err)
{
   strcpy(buffer,"Ошибка ф-ции WSARecv");
   CharToOem(buffer,buffer);
   printf("%s %d\n",buffer, WSAGetLastError());
}

Что ты пытаешься тут отправить. Как мне показалось, ты просто ошибся и я убрал эти строки.
Но Код так и не заработал. Точнее часть. Сервер показывает, что клиент подключился, но сообщения не принимает и не отправляет! :(
еще возник вопрос, в структуре мы не вводили данный параметр, но он присутствует:
op->hEvent = 0;

Это сообщение отредактировал(а) vikaz - 19.12.2008, 09:18


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
Олег2005
Дата 19.12.2008, 15:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



Посмотрите вот  здесь
Там есть кое-какие комментарии.
Цитата

Что ты пытаешься тут отправить.

Да нет, там не отправка - а прием от клиента - WSARecv
Цитата(vikaz @  19.12.2008,  07:52 Найти цитируемый пост)
op->hEvent = 0;

Это поле из структуры OVERLAPPED, которая включена в структуру ovpConnection, и его имя - hEvent - по умолчанию.

И еще - в функцию void SendToAll(char *buffer,unsigned long bytes) тоже надо добавить 
op->hEvent = 0;

Это сообщение отредактировал(а) Олег2005 - 22.12.2008, 23:26
PM MAIL WWW MSN   Вверх
vikaz
Дата 19.12.2008, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Спасибо, гляну на выходных. Там будет видно! smile


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
vikaz
Дата 22.12.2008, 07:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: нет
Всего: 12



Всем привет! Посмотрел я статью, не очень много полезной информации я там нашел ДЛЯ СЕБЯ. 
Возникли вопросы и опять же по серверной части:
 - Как мы уже выяснили в конце функции main есть строка принимающее сообщение, но я так и не нашел строки, которая отправляет полученное сообщение клиенту. Зато нашел еще одну функцию для приема, это так и нужно или......?
Код

if(GetQueuedCompletionStatus(hport, &bytes, &key, &overlapped, INFINITE)) 
   {
    // Операция завершена успешно
   ovpConnection * op = (ovpConnection*)overlapped;
// Определяем тип завершенной операции и выполняем соответствующие действия
   switch(op->op_type) 
{
      //Завершена отправка данных
      case ovpConnection::op_type_send:
      delete [] op->buffer;
      delete op;
      break;
      //Завершен приём данных
      case ovpConnection::op_type_recv:
      if(!bytes) 
{
//Соединение с данным клиентом закрыто
            ClientList.remove(op->sock_handle);
            closesocket(op->sock_handle);
            strcpy(buffer,"Клиент № %d отключился, активных клиентов %d\n");
            CharToOem(buffer,buffer);
            printf(buffer,op->client_number,ClientList.size());
            break;
       }
   op->buffer[bytes]='\0';
   if(op->buffer[0]=='*')    //Звездочка * - признак приема сообщения, которое 
//должно быть переслано всем подключенным клиентам
   {
   strcpy(buffer,"От клиента № %d получено сообщение для всех  %s\n");
   CharToOem(buffer,buffer);
   printf(buffer,op->client_number,(op->buffer+1));
   SendToAll(op->buffer, bytes);  //Отправляем данные всем
   }
   else
   {
   strcpy(buffer,"От клиента № %d получено сообщение %s\n");
   CharToOem(buffer,buffer);
   printf(buffer,op->client_number,op->buffer);
   }
  unsigned long b;
   WSABUF buf;
   buf.buf = op->buffer;
   buf.len = BUFF_SIZE;   // buffer_len – постоянная величина
   err=WSARecv(op->sock_handle, &buf, 1, &b, &flags, op, 0); 
   if(!err)
   {
   strcpy(buffer,"Ошибка ф-ции WSARecv");
   CharToOem(buffer,buffer);
   printf("%s %d\n",buffer, WSAGetLastError());
   }
   }


Вопрос собственно вот в этом месте:
Код

 unsigned long b;
   WSABUF buf;
   buf.buf = op->buffer;
   buf.len = BUFF_SIZE;   // buffer_len – постоянная величина
   err=WSARecv(op->sock_handle, &buf, 1, &b, &flags, op, 0); 
   if(!err)
   {
   strcpy(buffer,"Ошибка ф-ции WSARecv");
   CharToOem(buffer,buffer);
   printf("%s %d\n",buffer, WSAGetLastError());
   }


И еще, я так и не въехал, про 4 байта, где они там у тебя передаются. Это все про то, что передается только одно сообщение от клиента И что еще интересного. Моя антивирусная программа, определяет код сервера как вирус. smile

Это сообщение отредактировал(а) vikaz - 22.12.2008, 10:38


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
Олег2005
Дата 22.12.2008, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



В ссылке есть такая фраза:
С повторной отправкой сообщения от клиента серверу я разобрался.
Так что флаг и вам в руки......
Я уже не помню что там и как - давно писалось, и не мной лично, а одним коллегой. 
А насчет антивирусника?
 Так это его проблемы - а не программы. В коде программы нет ничего и близко подобного.....

Добавлено через 3 минуты и 12 секунд
Цитата(vikaz @  22.12.2008,  06:39 Найти цитируемый пост)
И еще, я так и не въехал, про 4 байта, где они там у тебя передаются

Из ссылки:
есть только одна засада, с которой я бился пару дней пока случайно не догадался, у меня пакет устроен так:
1. 4 байта это размер тела пакета
2. тело пакета.
соответственно на сервере строго сначала читаю 4 байта, а потом читал столько, сколько было прислано клиентом.

Это сообщение отредактировал(а) Олег2005 - 22.12.2008, 23:29
PM MAIL WWW MSN   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1034 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.