Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Как лучше организовать много-поточный сервер


Автор: io2me 15.3.2006, 20:39
Здраствуйте. Вот хотел спросить сабж.
Помоему есть 2 варианта:
1. Запустить N потоков, каждый ждет поключения (помоему что попало)
2. Запустить цыкл while, ожидающий подключения, и если ктото коннектиться обрабатывать его в потоки, чтобы сразу ждать других коннектов.

Что скажете ? Как лучше ?

Автор: adonin 16.3.2006, 12:18
Лучше так:

в основном потоке делаете listen(), затем accept(). accept() возвратит вам описатель нового сокета, через который вы можете общаться с данным клиентом.
После этого создаёте новый поток для работы через данный сокет. а в основном потоке опять делаете listen(). и accept().

Автор: io2me 16.3.2006, 15:41
можно пример ?

Автор: adonin 16.3.2006, 17:25
Код

#include <conio.h>
#include <stdio.h>
#include <winsock2.h>

#pragma comment (lib, "ws2_32.lib")
#define MAX_PACKET_SIZE    0x10000
#define SIO_RCVALL         0x98000001

char src[10];
char dest[10];
char ds[15];
unsigned short lowbyte;
unsigned short hibyte;

DWORD WINAPI ThreadProc(
  LPVOID lpParameter   // thread data
)
{

    SOCKET S=(SOCKET)lpParameter; 
    // Работа с клиентом
    // recv(S,...);
    // send(S,...);
    // и т.д.

    return 1;
}
void main()
{
  WSADATA     wsadata; 
  SOCKET      s;  
  char        name[128]; 
  HOSTENT*    phe;       
  SOCKADDR_IN sa;        
  IN_ADDR sa1;        
  unsigned long        flag = 1;  

  WSAStartup(MAKEWORD(2,2), &wsadata);
  s = socket( AF_INET, SOCK_RAW, IPPROTO_IP );
  gethostname(name, sizeof(name));
  phe = gethostbyname( name );
  ZeroMemory( &sa, sizeof(sa) );
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = ((struct in_addr *)phe->h_addr_list[0])->s_addr;
  bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR));

  SOCKADDR SIN;
  SOCKET S2;

  while(1)
  {
    DWORD TreadId;
    listen(s,10); // 10 - количество возможных соединений
    int i=sizeof(SIN);
    S2=accept(s,&SIN,&i);

    CreateThread(NULL,0,ThreadProc,(PVOID)S2,0,&TreadId);
  }
  closesocket( s );
  WSACleanup();
}



Примерно так. smile

Автор: io2me 16.3.2006, 17:44
спасиб, идея понятна.. а можна без win32 ?
а то я буду на linux переводить !

Автор: adonin 16.3.2006, 17:59
Не-а smile
Спроси в форуме "Программирование под linux". Но принцип тот же. Особо переделывать не придётся.

Автор: io2me 16.3.2006, 21:11
да в том форуме все молчат )))
маздаевцы smile

Автор: YanTsys 23.3.2006, 01:54
Как я понимаю после открытия сокет активен пока его принудительно не закрыть...
А нет нигде параметра позволяющего сокету автоматически закрываться в случае если оборвана связь?
Или нужно по таймеру делать опрос всех открытых сокетов на живность?

Автор: Kill_em_all 29.3.2006, 11:52
А с помощью асинхронных сокетов?
Еще лучший вариант! Забудьте про использование
потоков для такой цели

Автор: adonin 29.3.2006, 13:26
Цитата(Kill_em_all @ 29.3.2006, 11:52 Найти цитируемый пост)
А с помощью асинхронных сокетов?

Так делать не хорошо: клиенты будут обслуживаться по очереди!!! им придётся ждать, если нагрузка на сервер будет значительной. И потом, если у вас многопроцессорная система, Вы получите значительный выигрыш в скорости, если будете использовать потоки.

Цитата(YanTsys @ 23.3.2006, 01:54 Найти цитируемый пост)
А нет нигде параметра позволяющего сокету автоматически закрываться в случае если оборвана связь?
Или нужно по таймеру делать опрос всех открытых сокетов на живность?

Жаль, нет под рукой MSDN. Скорее всего, уровень TCP скажет вам о разрыве соединения (recv не получит данные, а GetLastError возвратит ошибку!=0). Но, возможно и нет. Легче всего проверить на двух машинах: выдернуть сетевой кабель из клиента, когда сервер будет ожидать запрос.
Посмотрите функцию SetSockOpt() возможно там что-нибудь будет: что-то типа SO_KEEP_ALIVE

Автор: LuckLess 29.3.2006, 13:45
Цитата(adonin @ 16.3.2006, 12:18 Найти цитируемый пост)
а в основном потоке опять делаете listen(). и accept().

listen опять не надо

Цитата(Kill_em_all @ 29.3.2006, 11:52 Найти цитируемый пост)
А с помощью асинхронных сокетов?
Еще лучший вариант! Забудьте про использование
потоков для такой цели

Цитата(adonin @ 29.3.2006, 13:26 Найти цитируемый пост)
Так делать не хорошо: клиенты будут обслуживаться по очереди!!! им придётся ждать, если нагрузка на сервер будет значительной. И потом, если у вас многопроцессорная система, Вы получите значительный выигрыш в скорости, если будете использовать потоки.

клиентам в любом случае придеться ждать. и к томуже 1 процесс может создать всего около 1300 потоков(в винде)
лучший вариант - комбинированный - асинхронные сокеты + потоки.
но не знаю как его реализовать под nix системы.

Автор: Romikgy 29.3.2006, 14:28
Имхо в
Цитата(LuckLess @ 29.3.2006, 12:45 Найти цитируемый пост)
nix

нет потоков

Цитата(LuckLess @ 29.3.2006, 12:45 Найти цитируемый пост)
listen опять не надо

имхо надо , т.к. аксепт сьедает под себя сокет, а при создании нового ему снова надо говорит "слушай"

Автор: LuckLess 29.3.2006, 16:11
Цитата(Romikgy @ 29.3.2006, 14:28 Найти цитируемый пост)
имхо надо , т.к. аксепт сьедает под себя сокет, а при создании нового ему снова надо говорит "слушай"

Не надо .
Листен лишь говорит какова максимальная очередь ожидающих соединения и все.
Добавлено @ 16:12
Цитата(Romikgy @ 29.3.2006, 14:28 Найти цитируемый пост)
нет потоков

Ну наверняка чтото похожее естьsmile
Добавлено @ 16:12
не fork()-иться же каждый раз..

Автор: Бонифаций 29.3.2006, 16:47
Цитата(Romikgy @ 29.3.2006, 14:28 Найти цитируемый пост)
Имхо в
Цитата(LuckLess @ 29.3.2006, 12:45 Найти цитируемый пост)
nix

нет потоков


Есть. Куда же они денутся. mysql к примеру многопоточный сервер, oops прокси, firebird-ss.

Автор: Romikgy 29.3.2006, 16:53
Цитата(LuckLess @ 29.3.2006, 15:11 Найти цитируемый пост)
Не надо .
Листен лишь говорит какова максимальная очередь ожидающих соединения и все.

точно не надо аксепт создает новый сокет

Цитата(LuckLess @ 29.3.2006, 15:11 Найти цитируемый пост)
Ну наверняка чтото похожее есть

есть эт точно smile но что я не в курсе

Автор: Бонифаций 29.3.2006, 19:36
Цитата(YanTsys @ 23.3.2006, 01:54 Найти цитируемый пост)
А нет нигде параметра позволяющего сокету автоматически закрываться в случае если оборвана связь?
Или нужно по таймеру делать опрос всех открытых сокетов на живность?


А зачем? если связь оборвется, вы просто получите ошибку в recv() при приеме. Или сигнал SIGPIPE если будете писать в неисправный сокет.

Автор: 040375 7.4.2006, 04:43
Если Вы хотите писать многопоточный сервер, и писать будете под Линукс - то Вам лучше всего разобраться с вызовом select, именно с помощью него работает большинство серверов в линукс, т.к. у многопоточной идеи много минусов, рассказывать не буду про них - лучше найдите в инете ман, про select есть даже русский ман и разберитесь с ним. Весь смысл в том, что select "берёт на обслуживание" любое (по теории) кол-во сокетов не блокируя основной цикл программы и экономя ресурсы процессора при таймаутах. У этого вызова есть ещё библиотечная обработка - pselect - это более новая ф-я. Пример приводить не буду пока - их в инете предостаточно, могу позже про выслать по почте.

Автор: adonin 7.4.2006, 08:11
Цитата(040375 @ 7.4.2006, 04:43 Найти цитируемый пост)
многопоточной идеи много минусов

Покажите хотя бы один недостаток, чтобы утверждение голословным не было. Вообще говоря, существует только два способа обработки параллельных запросов: многопоточность и ассинхронный ввод/вывод. Остальные методы должны сводиться к одному из них. Итак, select сводится к одному из этих способов, следовательно, обладает его недостатками.
Если я не прав, поправьте меня.

Автор: adonin 7.4.2006, 08:28
Нашёл статью:
http://www.opennet.ru/base/dev/server_way.txt.html
Итак, select - это разновидность ассинхронного ввода/вывода и ему присущи недостатки этого метода (см. статью)
Цитата

Сервер - процесс, использующий небольшое количество нитей, каждая
из которых обслуживает некоторое количество сокетов одновременно.

для Linux это лучший вариант.

Автор: Necias 7.4.2006, 20:42
жабер сервер - опенсорс, под линух, очень прямо написанный, можно работу с сокетами оттуда взять. Если кому интересно - в маздае эта проблема решается порождением класса CSocket в новом потоке. Но сервера с такой "в лоб" реализованной многопоточностью на коммерческом уровне не делаются ибо макс число потоков даже на Крее будет весьма ограниченным. Техника плавающего (до опр числа потоков в каждом изних находится по 1у сокету, затем они заполняются по 2й и тд) распределения сокетов не сложна, но безопасна и эффективна и при реализации многопоточности не следует о ней забывать.

Автор: blur 5.5.2006, 13:51
А у меня вот такой вопрос: если к серверу будут подключаться десятки тысяч клиентов, то как в таком случае организовать их работу. Не в отдельный же поток каждого   smile  

Автор: cozzzy 5.5.2006, 14:38
Использовать ACE  smile  

Автор: blur 5.5.2006, 14:50
Цитата(cozzzy @  5.5.2006,  14:38 Найти цитируемый пост)
Использовать ACE 

Это что?
 

Автор: cozzzy 5.5.2006, 15:26
Цитата(blur @  5.5.2006,  13:50 Найти цитируемый пост)
Это что?

http://www.cs.wustl.edu/~schmidt/ACE.html

Фактически - лучшая сетевая библиотека, которой пользуются многие крупнейшие компании. 
Кроссплатформенная, гибкая, защищенная + достаточно легка в изучении и использовании
 

Автор: Nuzur 20.6.2006, 16:01
cozzzy, А можете в 2-х словах описать как им пользоваться?
А то я чего-то недопонял... Вещица интерестная особенно прочитав кто ею пользуеться... 
Есть ли какое-то опиание сего на русском? 

Автор: Nuzur 21.6.2006, 16:59
Не все-таки не смог я АСЕ осилить, буду пользоваться стандартными средствами! 

Автор: Nuzur 22.6.2006, 09:20
adonin, Что-то я очень плохо понял ваш пример, тоесть до упора создаються потоки причем потом даже с "пустыми" сокетами. Всем все побарабану, подключился к нему кто-то или нет...
Можете пролить свет на происходящее? 

И код клиента который будет конектиться к такому серверу как бут выглядить? 

Автор: Goryachev 29.3.2007, 16:43
Цитата(Romikgy @  29.3.2006,  14:28 Найти цитируемый пост)
Имхо в 

Цитата(LuckLess @ 29.3.2006, 12:45 )
nix


нет потоков


А про pthread.h слышали? POSIX threads standard.
Работает отлично в nixe.

Для компиляции, используйте -lpthread флаг

Автор: Owen 30.3.2007, 12:39
Под 'nix'ом не писал, но  почему не использовать такое явление, как порты завершения?( CreateIOCompletionPort( ) ) Это будет вполне логично, в случае если сервер расчитан на большое кол-во пользователей.

Создавать потоки на каждый сокет имеет смысл лишь в том случае, если ожидается сравнительно мелое количество пользователей. На мой взгляд около 20. Однако от многопотоковости отказываться не стоит. Просто распределить обработку данных на несколько потоков. Особенно продуктивно в многопроцессорных машинах.

Автор: SenkraD 6.4.2007, 17:09
Могу вывесить свой курсач по Linux - это HTTP - сервер. Там несколько вариантов работы сервера и через fork, и через потоки, и через пул потоков.

Если надо пиши!

Автор: phprus 14.4.2007, 08:44
SenkraD
Если вам не трудно, то пожалуйста выложите.

Автор: SenkraD 17.4.2007, 18:40
Вот.

Автор: phprus 17.4.2007, 19:54
SenkraD
Спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)