Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 11:31
Оценка:
Всем добрый день,

Крайне необходима Ваша помощь. Потому что самостоятельно уже устал бороться.
Задача:
Организовать ретранслятор. То есть сервер, к которому подключены клиенты посредством TCP. Сервер принимает данные от одного клиента, и просто передает их всем остальным. Данные строковые, от 1кб до 4-х. В секунду может быть до 5 таких пакетов. Текущий вариант, сделан на c# на ассинхронных сокетах. Все прекрасно пока клиентов 50 — 60 ... но как только клиентов становится более 100, то начинаются безбожные задержки в получении данных (раздача сервера) иногда пакеты задерживаются до 10 минут !!! Что крайне не приемлемо, нужно по возсожности почти мгновенная передача.

Начал делать на c++ с применением не блокирующих сокетов. Но при двух телнет подключениях процессор уходит в жесткую нагрузку до 80%, при пяти, процессор перестает отвечть ! ((((

Вот код.



#include <windows.h>
#include <stdio.h>
#include <list>
#include <time.h>
#include <process.h>

std::list<SOCKET> clients;
#pragma comment(lib,"ws2_32.lib")

FILE *log_srvf = NULL;

static void log( const char *fmt, ... )
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(log_srvf, fmt, ap);
    va_end(ap);
    fflush(log_srvf);
}

static void recve_line( SOCKET s, std::string& r )
{
    while (1) {
        char ch;

        if(recv(s, &ch, 1, 0) == SOCKET_ERROR)
        {
            continue;
        }
        r.append(1, ch);
        if (ch == '$')  
            break;
    }
    log( "receive: %d bytes\n", r.length());
}

unsigned int __stdcall _thread_start_proc(void *arg)
{
    SOCKET s = *reinterpret_cast<SOCKET *>(arg);
    printf("entry socket: %d\n", s);
    clients.push_back(s);

    send(s, "SERVER OK\r\n", sizeof("SERVER OK\r\n"), 0);
    int user_counter;
    time_t start,end;
    char szInput [256];
    double dif;

  
    while (1) {   
        std::string r;

        recve_line( s, r );

        user_counter = 0;
        time(&start);
        if (r.empty()) 
            break;
        
        for (std::list<SOCKET>::iterator it = clients.begin(); it != clients.end(); it++) {
            if (*it != s) 
                send(*it, r.c_str(), r.length(), 0);
            user_counter++;
        }
        
        system("cls");
        time (&end);
        dif = difftime (end,start);
        log( "I spent %.4f sec that would send data to %d users\n", dif, user_counter);
    }
  
    clients.remove(s);
    closesocket( s );

    return 0;
}

int main( int argc, char **argv )
{
    SOCKET listener;
    SOCKET _socket;
    WSADATA info;
    struct sockaddr_in addr;

    log_srvf = fopen("srvlog_srvf.log_srvf", "wb");
    
    if( WSAStartup(0x2002, &info) != 0 )
    {
        log( "WSAStartup: fail: errno = %d!\n", WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        log( "WSAStartup successfull!\n");

    if((listener = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    {
        log( "socket: Unable to create socket: errno = %d!\n",  WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        log( "socket: Create successfull!\n");
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(32165);
    if(bind(listener, (const sockaddr *)&addr, sizeof addr) == SOCKET_ERROR)
    {
        log( "bind: Unable bind socket %d, errno = %d!\n", listener, WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        log( "bind: socket: %d, success!\n", listener);

    if( listen(listener, 1) )
    {
        log( "listen: Unable listen port: 32165, socket: %d, errno = %d!\n", listener, WSAGetLastError());
        return 1;
    } else
        log( "listen: socket: %d, port: 32165!\n");
    
    u_long argp = 1;
    ioctlsocket(listener, FIONBIO, &argp);

    int size = sizeof addr;
    while( true )
    {
        if((_socket = accept(listener, (sockaddr *)&addr, &size)) != INVALID_SOCKET)
        {
            printf("accept: %d\n", _socket);
            ioctlsocket(_socket, FIONBIO, &argp);

            unsigned int thid;
            printf("pass socket: %d\n",_socket);
            _beginthreadex(0, 0, _thread_start_proc, (void *)&_socket, 0, &thid);
        }
        Sleep(1000);
    }
    closesocket(listener);
    WSACleanup();
    return 0;
}



Пытался уйти в другой вариант на IOCP но там еще хуже. Так как задача сверхсрочная а опыта у меня кот наплакал, то так и не смог их завести.

Прошу помощи. Если возможно в чем проблема в данном подходе, и есть ли более удачные варианты реализации мгновенной передачи данных от одного клиента всем. UDP не подходит. Так как клиенты сидят в интернете, а не за одной сеткой.
Re: Нагруженный TCP сервер как и на чем реализовать
От: Crackjack Россия  
Дата: 16.02.12 12:11
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>
S>#include <windows.h>
S>#include <stdio.h>
S>#include <list>
S>#include <time.h>
S>#include <process.h>

S>std::list<SOCKET> clients;
S>#pragma comment(lib,"ws2_32.lib")

S>FILE *log_srvf = NULL;

S>static void log( const char *fmt, ... )
S>{
S>    va_list ap;
S>    va_start(ap, fmt);
S>    vfprintf(log_srvf, fmt, ap);
S>    va_end(ap);
S>    fflush(log_srvf);
S>}

S>static void recve_line( SOCKET s, std::string& r )
S>{
S>    while (1) {
S>        char ch;

S>        if(recv(s, &ch, 1, 0) == SOCKET_ERROR) // Ошибка здесь, сокет находится в неблокирующем режиме. Вызов recv возвращает управление немедленно в любом случае, независимо пришли данные или нет.
/*
  В итоге ты получаешь замкнутый цикл типа while(1){}, вот тебе и загрузка CPU
  Если хочешь использовать неблокирующий режим, то нужно пользоваться функциями для ожидания результата WSAAsyncSelect и WSAEventSelect. 
  Но в твоем случае(глядя на алгоритм работы) вообще нужно использовать блокирующий режим, 
  т.к. выгоды от неблокирующего режима при такой организации обмена ты не получишь, исключительно один геморой при написании и сопровождении исходников.
  Попробуй не вызывать ioctlsocket(listener, FIONBIO, &argp); и увидишь разницу сразу.
*/ 
S>        {
S>            continue;
S>        }
S>        r.append(1, ch);
S>        if (ch == '$')  
S>            break;
S>    }
S>    log( "receive: %d bytes\n", r.length());
S>}


S>



S>Пытался уйти в другой вариант на IOCP но там еще хуже. Так как задача сверхсрочная а опыта у меня кот наплакал, то так и не смог их завести.


S>Прошу помощи. Если возможно в чем проблема в данном подходе, и есть ли более удачные варианты реализации мгновенной передачи данных от одного клиента всем. UDP не подходит. Так как клиенты сидят в интернете, а не за одной сеткой.
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 12:18
Оценка:
Здравствуйте, Crackjack, Вы писали:

C>Здравствуйте, stronciy77, Вы писали:



C> В итоге ты получаешь замкнутый цикл типа while(1){}, вот тебе и загрузка CPU

C> Если хочешь использовать неблокирующий режим, то нужно пользоваться функциями для ожидания результата WSAAsyncSelect и WSAEventSelect.
C> Но в твоем случае(глядя на алгоритм работы) вообще нужно использовать блокирующий режим,
C> т.к. выгоды от неблокирующего режима при такой организации обмена ты не получишь, исключительно один геморой при написании и сопровождении исходников.
C> Попробуй не вызывать ioctlsocket(listener, FIONBIO, &argp); и увидишь разницу сразу.

Совершенно согласен ... Вот первый вариант код ниже...
После 50 клиентов, начинает тормозить раздача (потому что много медленных соеденений) вот я и вычитал про не блокирующий режим. Теперь совершенно запутался...

Вопрос все тот же, как избавиться от медленных клиентов (то есть как отправлять данные) и никого не ждать ?


#include <windows.h>
#include <stdio.h>
#include <list>
#include <time.h>
#include <process.h>

std::list<SOCKET> clients;
#pragma comment(lib,"ws2_32.lib")

FILE *log = NULL;

static void recve_line( SOCKET s, std::string& r )
{
    while (1) {
        char ch;

        if(recv(s, &ch, 1, 0) == SOCKET_ERROR)
        {
            printf("recv: fail for socket: %d\n", s);
            return;
        }
        r.append(1, ch);
        if (ch == '$')  
            break;
    }
    printf("receive: %d bytes\n", r.length());
}

unsigned int __stdcall _thread_start_proc(void *arg)
{
    SOCKET s = *reinterpret_cast<SOCKET *>(arg);
    printf("entry socket: %d\n", s);
    clients.push_back(s);

    send(s, "SERVER OK\r\n", sizeof("SERVER OK\r\n"), 0);
    int user_counter;
    time_t start,end;
    char szInput [256];
    double dif;

  
    while (1) {   
        std::string r;

        recve_line( s, r );

        user_counter = 0;
        time(&start);
        if (r.empty()) 
            break;
        
        for (std::list<SOCKET>::iterator it = clients.begin(); it != clients.end(); it++) {
            if (*it != s) 
                send(*it, r.c_str(), r.length(), 0);
            user_counter++;
        }
        
        system("cls");
        time (&end);
        dif = difftime (end,start);
        fprintf(log, "I spent %.4f sec that would send data to %d users\n", dif, user_counter);
    }
  
    clients.remove(s);

    return 0;
}

int main( int argc, char **argv )
{
    SOCKET listener;
    SOCKET _socket;
    WSADATA info;
    struct sockaddr_in addr;

    log = fopen("srvlog.log", "wb");
    
    if( WSAStartup(0x2002, &info) != 0 )
    {
        fprintf(log, "WSAStartup: fail: errno = %d!\n", WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        fprintf(log, "WSAStartup successfull!\n");

    if((listener = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    {
        fprintf(log, "socket: Unable to create socket: errno = %d!\n",  WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        fprintf(log, "socket: Create successfull!\n");
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(32165);
    if(bind(listener, (const sockaddr *)&addr, sizeof addr) == SOCKET_ERROR)
    {
        fprintf(log, "bind: Unable bind socket %d, errno = %d!\n", listener, WSAGetLastError());
        WSACleanup();
        return 1;
    } else
        fprintf(log, "bind: socket: %d, success!\n", listener);

    if( listen(listener, 8) )
    {
        fprintf(log, "listen: Unable listen port: 32165, socket: %d, errno = %d!\n", listener, WSAGetLastError());
        return 1;
    } else
        fprintf(log, "listen: socket: %d, port: 32165!\n");
    
    u_long argp = 0;
    ioctlsocket(listener, FIONBIO, &argp);

    int size = sizeof addr;
    while( true )
    {
        if((_socket = accept(listener, (sockaddr *)&addr, &size)) != INVALID_SOCKET)
        {
            printf("accept: %d\n", _socket);
            ioctlsocket(_socket, FIONBIO, &argp);

            unsigned int thid;
            printf("pass socket: %d\n",_socket);
            _beginthreadex(0, 0, _thread_start_proc, (void *)&_socket, 0, &thid);
        }
    }
}
Re: Нагруженный TCP сервер как и на чем реализовать
От: maxlosyam Россия  
Дата: 16.02.12 12:27
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Всем добрый день,


S>Крайне необходима Ваша помощь. Потому что самостоятельно уже устал бороться.


S>Вот код.


[тут был ужас]

S>Пытался уйти в другой вариант на IOCP но там еще хуже. Так как задача сверхсрочная а опыта у меня кот наплакал, то так и не смог их завести.


почему там хуже? там как раз таки все прекрасно, и ваша задача решается очень быстро.

S>Прошу помощи. Если возможно в чем проблема в данном подходе, и есть ли более удачные варианты реализации мгновенной передачи данных от одного клиента всем. UDP не подходит. Так как клиенты сидят в интернете, а не за одной сеткой.


Если без IOCP то делать методом пула — читаем функицию select
но лин через iocp в сто раз легче чем через select.

ps:
1. не читайте строку побайтово, читайте в буфер и сразу много, и потом из буфера вычитывайте строку.
2. неблокирующие сокеты были придуманы для того чтобы не создавать по потоку на соединение, подумайте как это все сделать в одном потоке.
Re: Нагруженный TCP сервер как и на чем реализовать
От: AltCtrlDel  
Дата: 16.02.12 12:34
Оценка:
я только что тестировал свой проект под нагрузкой — ок. В чём то схоже.
Сделал на boost::asio.
На "чистых" сокетах я тоже раньше делал, но тут быстрее получается. Если не считать чтения манула по asio.
Но с нуля на сокетах ещё больше читать надо и дольше отлаживать.
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 12:37
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Вопрос все тот же, как избавиться от медленных клиентов (то есть как отправлять данные) и никого не ждать ?


Встречный вопрос.

Вот у вас есть N быстрый клиентов и M медленных. Вы хотите, чтобы данные валились со скоростью быстрых клиентов. Вопрос, куда вы собираетесь девать данные, которые уже отправлены быстрым клиентам, но еще не отправлены медленным? Учтите при этом, что если данные продолжают валиться, то неотправленные данные будут расти и расти.

P.S. Нагруженным ваш сервер бы был, если бы количество клиентов измерялось тысячами, и данных было бы на пару порядков побольше
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 12:39
Оценка:
Здравствуйте, maxlosyam, Вы писали:

M>Здравствуйте, stronciy77, Вы писали:


S>>Всем добрый день,


S>>Крайне необходима Ваша помощь. Потому что самостоятельно уже устал бороться.


S>>Вот код.


M>[тут был ужас]

Если покажу IOCP поделку, боюсь вызвать культурологический шок

S>>Пытался уйти в другой вариант на IOCP но там еще хуже. Так как задача сверхсрочная а опыта у меня кот наплакал, то так и не смог их завести.


M>почему там хуже? там как раз таки все прекрасно, и ваша задача решается очень быстро.


Все прекрасно, для тех кто понимает глубину и ширину сокетов

M>Если без IOCP то делать методом пула — читаем функицию select

M>но лин через iocp в сто раз легче чем через select.

M>ps:

M>1. не читайте строку побайтово, читайте в буфер и сразу много, и потом из буфера вычитывайте строку.
Как это сделать ?
M>2. неблокирующие сокеты были придуманы для того чтобы не создавать по потоку на соединение, подумайте как это все сделать в одном потоке.
Думаю ... только не найти получить хоть мало мальский пример, что бы знать куда копать.
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 12:41
Оценка:
Здравствуйте, AltCtrlDel, Вы писали:

ACD>я только что тестировал свой проект под нагрузкой — ок. В чём то схоже.

ACD>Сделал на boost::asio.
ACD>На "чистых" сокетах я тоже раньше делал, но тут быстрее получается. Если не считать чтения манула по asio.
ACD>Но с нуля на сокетах ещё больше читать надо и дольше отлаживать.

Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 12:45
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, stronciy77, Вы писали:


S>>Вопрос все тот же, как избавиться от медленных клиентов (то есть как отправлять данные) и никого не ждать ?


Pzz>Встречный вопрос.


Pzz>Вот у вас есть N быстрый клиентов и M медленных. Вы хотите, чтобы данные валились со скоростью быстрых клиентов. Вопрос, куда вы собираетесь девать данные, которые уже отправлены быстрым клиентам, но еще не отправлены медленным? Учтите при этом, что если данные продолжают валиться, то неотправленные данные будут расти и расти.


Pzz>P.S. Нагруженным ваш сервер бы был, если бы количество клиентов измерялось тысячами, и данных было бы на пару порядков побольше


Вот в этом и была трабла самого проекта на асинхронных сокетах в C# !!!
Пул не обработанных данных, рос и рос как гора, и начинались ужастики с задержками ... Уход в С++ ничего не изменил
А мне тысячи не нужно, мне бы хотя бы раздавал как надо (быстрым быстро, медленным медленно) хотя бы для 500 пользователей ! Это мой предел мечтаний !
Но ничего похожего (решение вопроса) уже неделю не могу найти нигде
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: maxlosyam Россия  
Дата: 16.02.12 12:48
Оценка:
Здравствуйте, stronciy77, Вы писали:

M>>почему там хуже? там как раз таки все прекрасно, и ваша задача решается очень быстро.

тут есть куча тем где iocp уже рассосали по пальцам, поищите.

S>Все прекрасно, для тех кто понимает глубину и ширину сокетов


M>>1. не читайте строку побайтово, читайте в буфер и сразу много, и потом из буфера вычитывайте строку.

S>Как это сделать ?
а зачем вам вообще вычитывать строку? там команды? читайте по килобайту, и сколько приняли столько и отправляйте.
M>>2. неблокирующие сокеты были придуманы для того чтобы не создавать по потоку на соединение, подумайте как это все сделать в одном потоке.
S>Думаю ... только не найти получить хоть мало мальский пример, что бы знать куда копать.
вот тут http://www.tenouk.com/Module41.html есть пример сервера на select, все делается в одном потоке. просто почитайте поищите про select.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Nikolay_Ch Россия  
Дата: 16.02.12 12:48
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>А мне тысячи не нужно, мне бы хотя бы раздавал как надо (быстрым быстро, медленным медленно) хотя бы для 500 пользователей ! Это мой предел мечтаний !

QoS вам поможет... Регулируйте ширину канала.
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Nikolay_Ch Россия  
Дата: 16.02.12 12:50
Оценка:
Здравствуйте, Crackjack, Вы писали:

C> В итоге ты получаешь замкнутый цикл типа while(1){}, вот тебе и загрузка CPU

В принципе, маленького вызова sleep с параметром 10 должно хватить для снижения загрузки CPU до приемлемых процентов... Не?
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 12:51
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Вот в этом и была трабла самого проекта на асинхронных сокетах в C# !!!

S>Пул не обработанных данных, рос и рос как гора, и начинались ужастики с задержками ... Уход в С++ ничего не изменил

Это же не проблема реализации, а тем более, не проблема языка, выбранного для реализации.

Это вопрос о постановке задачи: что делать, если данные поступают быстрее, чем клиенты успевают их потреблять?

S>А мне тысячи не нужно, мне бы хотя бы раздавал как надо (быстрым быстро, медленным медленно) хотя бы для 500 пользователей ! Это мой предел мечтаний !


Кто должен хранить данные, которые еще не розданы медленным клиентам? Каким механизмом это хранилище должно быть защищено от переполнения?

Еще раз, я сейчас обсуждаю ожидаемое поведение программы, а не то, как оно реализовано.
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: AltCtrlDel  
Дата: 16.02.12 12:53
Оценка:
S>Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?

Ну, асинхронные методы то там есть, конечно. А так, от твоей реализации именно твоей задачи зависит. Если "медленные", застревают и не успевают забирать иногда, так у меня для этого случая специально sqlite прикручена в виде внешнего буфера. Для медленных клиентов смотри размер их mtu, может они вообще через GPRS заходят. Не передавай мелкими порциями, накопи хотя бы до mtu*3, а то много полупустых пакетов летать будет.
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Nikolay_Ch Россия  
Дата: 16.02.12 13:04
Оценка:
Здравствуйте, AltCtrlDel, Вы писали:

S>>Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?

ACD>Ну, асинхронные методы то там есть, конечно. А так, от твоей реализации именно твоей задачи зависит. Если "медленные", застревают и не успевают забирать иногда, так у меня для этого случая специально sqlite прикручена в виде внешнего буфера. Для медленных клиентов смотри размер их mtu, может они вообще через GPRS заходят. Не передавай мелкими порциями, накопи хотя бы до mtu*3, а то много полупустых пакетов летать будет.
Тут никакого буфера может не хватить через определенное время. А нельзя включить управлением шириной канала в этом случае?
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 13:15
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, stronciy77, Вы писали:


S>>Вот в этом и была трабла самого проекта на асинхронных сокетах в C# !!!

S>>Пул не обработанных данных, рос и рос как гора, и начинались ужастики с задержками ... Уход в С++ ничего не изменил

Pzz>Это же не проблема реализации, а тем более, не проблема языка, выбранного для реализации.


Pzz>Это вопрос о постановке задачи: что делать, если данные поступают быстрее, чем клиенты успевают их потреблять?


Пробрасывать все данные которые не успел получить пользователь, то есть не получил лови следующий пакет ! ( К сожалению это единственных выход.)
Не создавать же для каждого пользователя пул сообщений и раздавать с него ? Тогда подтврждение получения будет потреблять еще больше ресурсов !
Вот такое ожидаемое поведение, что успел, то и получил
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Mr.Delphist  
Дата: 16.02.12 13:15
Оценка: +1
Здравствуйте, Nikolay_Ch, Вы писали:

N_C>Здравствуйте, Crackjack, Вы писали:


C>> В итоге ты получаешь замкнутый цикл типа while(1){}, вот тебе и загрузка CPU

N_C>В принципе, маленького вызова sleep с параметром 10 должно хватить для снижения загрузки CPU до приемлемых процентов... Не?
Программирование на слипах... Обожаю
Зачем нагревать зазря Вселенную, если можно просто ждать на каком-то объекте? Плюс слип-алгоритмы имеют обычай давать граблей по лбу при выходе измененной архитектуры проца: многоядерность, реордеринг, спин-локи...
Re: Нагруженный TCP сервер как и на чем реализовать
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 16.02.12 13:19
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Всем добрый день,


S>Крайне необходима Ваша помощь. Потому что самостоятельно уже устал бороться.

S>Задача:
S>Организовать ретранслятор. То есть сервер, к которому подключены клиенты посредством TCP. Сервер принимает данные от одного клиента, и просто передает их всем остальным. Данные строковые, от 1кб до 4-х. В секунду может быть до 5 таких пакетов. Текущий вариант, сделан на c# на ассинхронных сокетах. Все прекрасно пока клиентов 50 — 60 ... но как только клиентов становится более 100, то начинаются безбожные задержки в получении данных (раздача сервера) иногда пакеты задерживаются до 10 минут !!! Что крайне не приемлемо, нужно по возсожности почти мгновенная передача.

S>Начал делать на c++ с применением не блокирующих сокетов. Но при двух телнет подключениях процессор уходит в жесткую нагрузку до 80%, при пяти, процессор перестает отвечть ! ((((


S>Вот код.

У тебя в коде не используются неблокирующие сокеты. Прочитай про pool/epool и сделай через него. Либы, которые оборачивают это дело libevent, boost::asio и 9000 других.
Sic luceat lux!
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 13:28
Оценка:
Здравствуйте, Nikolay_Ch, Вы писали:

N_C>Здравствуйте, AltCtrlDel, Вы писали:


S>>>Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?

ACD>>Ну, асинхронные методы то там есть, конечно. А так, от твоей реализации именно твоей задачи зависит. Если "медленные", застревают и не успевают забирать иногда, так у меня для этого случая специально sqlite прикручена в виде внешнего буфера. Для медленных клиентов смотри размер их mtu, может они вообще через GPRS заходят. Не передавай мелкими порциями, накопи хотя бы до mtu*3, а то много полупустых пакетов летать будет.
N_C>Тут никакого буфера может не хватить через определенное время. А нельзя включить управлением шириной канала в этом случае?

Нет к сожалению, хостер сервера не хочет и не будет ничего менять , собственно сервер не плохой:
Intel Xeon E5345 2.33 (2 processors)
Windows Server 2008 R2 Standard
RAM 8 Gb
Network 1.0Gbps

И потом я же не cisco как я узнаю, кто у меня медленный, кто быстрый ?
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 13:32
Оценка:
Здравствуйте, AltCtrlDel, Вы писали:

S>>Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?


ACD>Ну, асинхронные методы то там есть, конечно. А так, от твоей реализации именно твоей задачи зависит. Если "медленные", застревают и не успевают забирать иногда, так у меня для этого случая специально sqlite прикручена в виде внешнего буфера. Для медленных клиентов смотри размер их mtu, может они вообще через GPRS заходят. Не передавай мелкими порциями, накопи хотя бы до mtu*3, а то много полупустых пакетов летать будет.


То есть накапливать для каждого пользователя (стек пакетов) и при очередном обходе, выгребать столько сколько может принять на данный момент ? А как получить подтверждение что он получил предыдущий пакет ? Хранить MTU каждого и вычислять сколько может принять ? То есть не могу в голове собрать картинку Придется рисовать на бумаге.
Re[7]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 13:56
Оценка:
Здравствуйте, stronciy77, Вы писали:

Pzz>>Это вопрос о постановке задачи: что делать, если данные поступают быстрее, чем клиенты успевают их потреблять?


S>Пробрасывать все данные которые не успел получить пользователь, то есть не получил лови следующий пакет ! ( К сожалению это единственных выход.)


Совершенно не обязательно это единственный выход.

Скорость поступления данных от чего зависит? Если данные летят с неограниченной скоростью (т.е., скорость определяется только скоростью рассылки), то при предложенном вами подходе только один, самый быстрый, клиент будет получать все данные. Остальным останется только зубами щелкать

Если же у источника данный есть своё собственное ограничение скорости, то возможны варианты. К примеру, клиенты, которые успевают в среднем, но не успевают в пиках, могли бы получать все данные без потерь, если обеспечить для них буферизацию. И только при переполнении такого буфера пришлось бы данные выбрасывать.

S>Не создавать же для каждого пользователя пул сообщений и раздавать с него ? Тогда подтврждение получения будет потреблять еще больше ресурсов !


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

S>Вот такое ожидаемое поведение, что успел, то и получил


И что им делать, бедолагам, если данные с пропусками? Они хоть должны знать-то, что не все получили?
Re[8]: Нагруженный TCP сервер как и на чем реализовать
От: stronciy77  
Дата: 16.02.12 14:26
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, stronciy77, Вы писали:


Pzz>>>Это вопрос о постановке задачи: что делать, если данные поступают быстрее, чем клиенты успевают их потреблять?


S>>Пробрасывать все данные которые не успел получить пользователь, то есть не получил лови следующий пакет ! ( К сожалению это единственных выход.)


Pzz>Совершенно не обязательно это единственный выход.


Pzz>Скорость поступления данных от чего зависит? Если данные летят с неограниченной скоростью (т.е., скорость определяется только скоростью рассылки), то при предложенном вами подходе только один, самый быстрый, клиент будет получать все данные. Остальным останется только зубами щелкать


Скорость поступления данных довольно большая. В среднем 4 раза в секунду, приходят пакеты от 1кб до 4кб, очень редко более длинные, скажем по 8кб
Это строки ограниченные знаком '$' сейчас работает ретранслятор, который перенаправляет всем клиентам с такой же скоростью данные, но из-за медленных накапливается пул в памяти (от меня не зависящий) который сам медленно раздает всем, и если медленных ребят много, скажем 50 из 100 , то все начинают получать данные очень медленно. Как програмно определять кто быстрый кто медленный я не знаю. И даже не догадываюсь.

Pzz>Если же у источника данный есть своё собственное ограничение скорости, то возможны варианты. К примеру, клиенты, которые успевают в среднем, но не успевают в пиках, могли бы получать все данные без потерь, если обеспечить для них буферизацию. И только при переполнении такого буфера пришлось бы данные выбрасывать.


Ок, буфер, это общая куча, или для каждого свой ? Если общая куча, то тогда будет обратный трафик, с номером, последнего принятого пакета, и нагрузка на выгребание всех данных пришедших за это время... Если у каждого свой, то как это сделать, в потоках ?

S>>Не создавать же для каждого пользователя пул сообщений и раздавать с него ? Тогда подтврждение получения будет потреблять еще больше ресурсов !


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


Так какая реализация будет самая лучшая для такой задачи ?

Pzz>И что им делать, бедолагам, если данные с пропусками? Они хоть должны знать-то, что не все получили?

А вот это проблема, потому что в принципе данные критичны ... Но как их доставлять медленным ребятам, я до сих пор не знаю !
Re[9]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 15:53
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Скорость поступления данных довольно большая. В среднем 4 раза в секунду, приходят пакеты от 1кб до 4кб, очень редко более длинные, скажем по 8кб


Ну т.е., даже если 4 раза в секунду по 4К, это 16К в секунду, т.е., 128 килобит. Копейки, если ваши клиенты не сидят на телефонном модеме

S>Это строки ограниченные знаком '$' сейчас работает ретранслятор, который перенаправляет всем клиентам с такой же скоростью данные, но из-за медленных накапливается пул в памяти (от меня не зависящий) который сам медленно раздает всем, и если медленных ребят много, скажем 50 из 100 , то все начинают получать данные очень


Это вы в каждом письме повторяете. Я уже запомнил, спасибо.

S>медленно. Как програмно определять кто быстрый кто медленный я не знаю. И даже не догадываюсь.


Ну, например, по тому факту, что очередь к данному клиенту доросла до ограничителя. Но это не будет работать, если источник данных может вывалить слишком много за раз.

S>Ок, буфер, это общая куча, или для каждого свой ? Если общая куча, то тогда будет обратный трафик, с номером, последнего принятого пакета, и нагрузка на выгребание всех данных пришедших за это время... Если у каждого свой, то как это сделать, в потоках ?


Зачем вам обратный трафик?

Потоки вам только мешают в этой задаче. Я бы сделал все в одном потоке. Выглядит это сложнее, но на самом деле — проще, т.к. не надо думать о синхронизации.

Можно сделать общий буфер, можно сделать по буферу для каждого клиента — при таком маленьком трафике любое решение будет работать. Я бы сделал общий кольцевой буфер с одним write pointer'ом, который сдвигается, когда в буфер добавляют данные, и по одному read pointer'у на каждого получателя. Но при этом может быть сложно вычислить, кто (а, вернее, на сколько) отстает больше всех — не сканировать же все 50-100 указателей каждый раз (RB-деревья рулят, но вы вряд ли захотите с ними возиться).

С другой стороны, по буферу на клиента при такой маленькой скорости тоже будет вполне адекватным решением.

Pzz>>И что им делать, бедолагам, если данные с пропусками? Они хоть должны знать-то, что не все получили?

S>А вот это проблема, потому что в принципе данные критичны ... Но как их доставлять медленным ребятам, я до сих пор не знаю !

Вы никак не можете доставить данные быстрее, чем можете. Вопрос в том, что вы делаете, если обнаруживаете, что данных у вас больше, чем в дырку пролазит.

Вполне адекватным может быть решение 1) написать в требованиях минимальную скорость канала к клиенту 2) закрывать соединение, если клиент не выполняет этого требования
Re: Нагруженный TCP сервер как и на чем реализовать
От: Michael Chelnokov Украина  
Дата: 16.02.12 15:53
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Крайне необходима Ваша помощь. Потому что самостоятельно уже устал бороться.


Попросите начальство переназначить задачу на кого-то другого или нанять оффсайт разработчика. Ничего личного, но увы.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Nikolay_Ch Россия  
Дата: 16.02.12 16:20
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>То есть накапливать для каждого пользователя (стек пакетов) и при очередном обходе, выгребать столько сколько может принять на данный момент ? А как получить подтверждение что он получил предыдущий пакет ? Хранить MTU каждого и вычислять сколько может принять ? То есть не могу в голове собрать картинку Придется рисовать на бумаге.

Подтверждение о получении потока байтов Вы можете получить от получателя. Заложите это в свой протокол. Как может в этом помочь MTU — для меня загадка.
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: Nikolay_Ch Россия  
Дата: 16.02.12 16:22
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>И потом я же не cisco как я узнаю, кто у меня медленный, кто быстрый ?

А при чем здесь это? А накопить статистику? Вы же можете реализовать такой протокол поверх TCP, используя который сможете определять скорость передачи и снижать/повышать ее по мере необходимости.
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 16:28
Оценка: +1
Здравствуйте, AltCtrlDel, Вы писали:

ACD>Ну, асинхронные методы то там есть, конечно. А так, от твоей реализации именно твоей задачи зависит. Если "медленные", застревают и не успевают забирать иногда, так у меня для этого случая специально sqlite прикручена в виде внешнего буфера. Для медленных клиентов смотри размер их mtu, может они вообще через GPRS заходят. Не передавай мелкими порциями, накопи хотя бы до mtu*3, а то много полупустых пакетов летать будет.


Какие все умные, а шизею. Интересно, сейчас все сетевые программы так и пишутся, или бывают исключения.

Hints:
0) Не mtu, а mss
1) Какой смысл накапливать до mtu*3, если передается все равно кусками по mtu?
2) Какой смысл накапливать до..., если это автоматически делает TCP?
3) Как узнать mtu пира?
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.02.12 16:31
Оценка:
Здравствуйте, Kernan, Вы писали:

K>У тебя в коде не используются неблокирующие сокеты. Прочитай про pool/epool и сделай через него. Либы, которые оборачивают это дело libevent, boost::asio и 9000 других.


У него венда, вообще-то. В венду пока не положили epool. Может, к 12-й версии положат. А может, решат, что родные IOCP ничем не хуже
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: flamin  
Дата: 16.02.12 16:32
Оценка:
Переход на C++ не решит проблемы.
Надо следить за буфером клиента — время за которое он полностью отправляет данные.
В синхронном варианте это интервал времени, за которое отрабатывает send
В асинхронном — время между вызовом send и onSend

Синхронный вариант не подходит в вашем случае, потому что первый медленный клиент обеспечивает задержку всем остальным.
Придется использовать асинхронные сокеты, с очередью сообщений на каждого клиента.
Если приходит новое сообщение, когда предыдущее еще не отправлено (не было onSend) — его не надо пихать в send, а положить в очередь.
Обязательно организовать отстрел клиента по максимальному количеству сообщений в очереди — иначе рано или поздно приложение выжрет память и свалится.

В общем надо понимать, что с задержками для медленных клиентов бороться бесполезно — если у них канал ужее, чем поток данных — то это гарантированные задержки, рост очереди и отстрел рано или поздно.
Ваша цель — минимизировать ущерб быстрым клиентам.

На чем писать — дело вкуса. У C#, Java нет проблем с производительностью для такой задачи
Связываться с C++ если нет опыта я бы не рекомендовал.
Если очень хочется — то boost:asio.
На чистых сокетах слишком много возможностей выстрелить себе в ногу.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: AltCtrlDel  
Дата: 17.02.12 05:03
Оценка:
S>То есть накапливать для каждого пользователя (стек пакетов) и при очередном обходе, выгребать столько сколько может принять на данный момент ?

когда у тебя заполнится выходная очередь для клиента, а подтверждения по tcp не будут поступать, то очередная асинхронная передача сама подвиснет.

S> А как получить подтверждение что он получил предыдущий пакет ?


Для этого, в своём слое, поверх TCP, делаешь подтверждения от клиентов.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: AltCtrlDel  
Дата: 17.02.12 05:47
Оценка:
Pzz>0) Не mtu, а mss

Поправка принята. Настроить или узнать, при желании, мы можем размер mtu, но данные то передадутся mss = mtu-40 при IPv4 (а при использовании SSL ещё меньше).

Pzz>1) Какой смысл накапливать до mtu*3, если передается все равно кусками по mtu?


Именно потому что мы не контролируем, как поток по пакетам шинкуется. Если посылаем мелкими порциями, то порции, всё таки, должны быть большие. Чтобы остатки реже передавались.

Pzz>2) Какой смысл накапливать до..., если это автоматически делает TCP?


Он ждёт десятки-сотни милисекунд поступления новых данных для передачи, потом остатки, всё таки уходят. Если отсылаем черз 50 мС, тогда всё равно, конечно.

Pzz>3) Как узнать mtu пира?


Можно просто ориентироваться по типу подключения, настроить размер буфера клиента зная его тип соединения, настроить в винде, узнать выполнив пингование с запретом фрагментации...
Re: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 17.02.12 08:13
Оценка:
Бери мою библиотеку.
prostoserver.com
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: Pzz Россия https://github.com/alexpevzner
Дата: 17.02.12 10:50
Оценка:
Здравствуйте, AltCtrlDel, Вы писали:

Pzz>>0) Не mtu, а mss


ACD> Поправка принята. Настроить или узнать, при желании, мы можем размер mtu, но данные то передадутся mss = mtu-40 при IPv4 (а при использовании SSL ещё меньше).


Вот до выделенного и надо было остановиться. Тогда никто не узнал бы, что вы не в курсе, что SSL живет над TCP, а не наоборот

Pzz>>1) Какой смысл накапливать до mtu*3, если передается все равно кусками по mtu?


ACD> Именно потому что мы не контролируем, как поток по пакетам шинкуется. Если посылаем мелкими порциями, то порции, всё таки, должны быть большие. Чтобы остатки реже передавались.


А почему не mtu*5?

Pzz>>2) Какой смысл накапливать до..., если это автоматически делает TCP?


ACD> Он ждёт десятки-сотни милисекунд поступления новых данных для передачи, потом остатки, всё таки уходят. Если отсылаем черз 50 мС, тогда всё равно, конечно.


Он это делает адаптивно и достаточно разумно. Сделать лучше, чем TCP делает автоматически, можно, но надо очень хорошо понимать, что вы делаете.

Pzz>>3) Как узнать mtu пира?


ACD> Можно просто ориентироваться по типу подключения, настроить размер буфера клиента зная его тип соединения, настроить в винде, узнать выполнив пингование с запретом фрагментации...


Нельзя по типу подключение — вы не можете знать, что между вами. Да и тип подключения вы толком не узнаете. А пинг может быть закрыт. В общем, даже встроенный в TCP Path MTU discovery работает через пень-колоду, а он гораздо ближе к нижнему уровню чем все, что вы можете понаделать из user space.
Re[7]: Нагруженный TCP сервер как и на чем реализовать
От: AltCtrlDel  
Дата: 17.02.12 12:07
Оценка:
ACD>> (а при использовании SSL ещё меньше).
Pzz>Вот до выделенного и надо было остановиться. Тогда никто не узнал бы, что вы не в курсе, что SSL живет над TCP, а не наоборот

Не поняли ничего, и улыбаетесь
При использовании SSL к нашим данным ещё добавляется 2-3 байта размера записи ssl. Это нужно учитывать при отсылки данных нечастыми небольшими порциями. Чтобы последний байт в отдельном пакете не ушёл.

Pzz>А почему не mtu*5?


Рекомендацию такую читал в книжке. Если нужно память под буфера экономить. Дальнейшее увеличение не так существенно влияет. Исследование такое проводилось. (Ссылку искать не нанимался, если чё).

Pzz>Нельзя по типу подключение — вы не можете знать, что между вами.


Отчего же нельзя. В клиентах настройка. При плохой связи через GPRS (реальный пример) подбор размера отсылаемых порций данных позволяет увеличить пропускную способность.

Pzz> А пинг может быть закрыт.


а я про реальные ситуации
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 18.02.12 12:18
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Бери мою библиотеку.

G>prostoserver.com

Готов взять, сразу вопрос, чем она хороша ?
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 18.02.12 14:41
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Бери мою библиотеку.

G>prostoserver.com

Вопрос, а как посредством Вашей библоитеки, организовать прием и передачу данных на разных портах. То есть, принимать данные, с одного порта, и передавать всем клиентам но на другой порт. Что бы избежать путаницы. С считаванием данных и передачей.
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 18.02.12 14:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Готов взять, сразу вопрос, чем она хороша ?


Простая, быстрая, надёжная. Короче — самая крутая. Даже денег за неё не прошу :)
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 18.02.12 14:47
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос, а как посредством Вашей библоитеки, организовать прием и передачу данных на разных портах. То есть, принимать данные, с одного порта, и передавать всем клиентам но на другой порт. Что бы избежать путаницы. С считаванием данных и передачей.


Хотелось бы знать задачу подробней. Это клиенты подключаются на разные порты, или как?
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 18.02.12 14:58
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Вопрос, а как посредством Вашей библоитеки, организовать прием и передачу данных на разных портах. То есть, принимать данные, с одного порта, и передавать всем клиентам но на другой порт. Что бы избежать путаницы. С считаванием данных и передачей.


G>Хотелось бы знать задачу подробней. Это клиенты подключаются на разные порты, или как?


Один порт работает на прием данных, то есть источник приема один на одном порту.
На втором порте сидит куча клиентов, которые только принемают данные.

То есть можно ли с помощью Вашей библиотеки, организовать сковозной ретранслятор ?
Вот примерно такое:

|-------------| --------> Client A
A --> port(xxx) -->| Retranslator| (port yyy) --------> Client ...
|-------------| --------> Client Z
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 18.02.12 15:05
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Вопрос, а как посредством Вашей библоитеки, организовать прием и передачу данных на разных портах. То есть, принимать данные, с одного порта, и передавать всем клиентам но на другой порт. Что бы избежать путаницы. С считаванием данных и передачей.


G>Хотелось бы знать задачу подробней. Это клиенты подключаются на разные порты, или как?


Предыдущая схема побилась не подумал про шрифт, вот такая схема, один порт приемник (xxx), второй порт раздает клиентам все что принемается через порт (yyy) то есть нужен быстрый ретранслятор сообщений.

                   |-------------|            |--------> Client A
A --> port(xxx) -->| Retranslator| (port yyy) |--------> Client ...
                   |-------------|            |--------> Client Z
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 18.02.12 15:54
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Один порт работает на прием данных, то есть источник приема один на одном порту.

А>На втором порте сидит куча клиентов, которые только принемают данные.

Т.е. сервер создает два порта. К одному подключается один клиент, к другому куча.
Да, создаем два экземпляра сервера на разных портах. Есть функция перечисления подключений, по ней и передаём принятое.
С двумя портами — это обязательное условие? Проще же с одним.
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 18.02.12 16:35
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Один порт работает на прием данных, то есть источник приема один на одном порту.

А>>На втором порте сидит куча клиентов, которые только принемают данные.

G>Т.е. сервер создает два порта. К одному подключается один клиент, к другому куча.

G>Да, создаем два экземпляра сервера на разных портах. Есть функция перечисления подключений, по ней и передаём принятое.
G>С двумя портами — это обязательное условие? Проще же с одним.

Нет с двумя совершенно не обязательно...

Ок, я принял сообщение, как разослать его всем кроме того что отправил ? делать вектор и заносить туда данные при подключении клиентов, а потом перебирать из, или это уже есть в библе ? Простите, просто API не очень ясный
Re[7]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 18.02.12 21:35
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Нет с двумя совершенно не обязательно...


Если только один может отправлять данные, то всё упрощается.

А>Ок, я принял сообщение, как разослать его всем кроме того что отправил ? делать вектор и заносить туда данные при подключении клиентов, а потом перебирать из, или это уже есть в библе ? Простите, просто API не очень ясный :)


Ккккак это АПИ не ясный?? API.chm -- яснее некуда ;)
Функция PServer_EnumConnections
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 20.02.12 07:09
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Готов взять, сразу вопрос, чем она хороша ?


G>Простая, быстрая, надёжная. Короче — самая крутая. Даже денег за неё не прошу


http://www.serverframework.com/
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 20.02.12 07:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>http://www.serverframework.com/


Не совсем понял что вы этим хочите сказать.

The Core Framework £3,100
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: savitar  
Дата: 20.02.12 12:20
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Бери мою библиотеку.

G>prostoserver.com

оффтоп:
покупают?
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 20.02.12 12:25
Оценка: 2 (1)
Здравствуйте, savitar, Вы писали:

S>оффтоп:

S>покупают?

Не часто, но да. Исходники тоже.
Re: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 21.02.12 21:29
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Организовать ретранслятор. То есть сервер, к которому подключены клиенты посредством TCP. Сервер принимает данные от одного клиента, и просто передает их всем остальным. Данные строковые, от 1кб до 4-х. В секунду может быть до 5 таких пакетов. Текущий вариант, сделан на c# на ассинхронных сокетах. Все прекрасно пока клиентов 50 — 60 ... но как только клиентов становится более 100, то начинаются безбожные задержки в получении данных (раздача сервера) иногда пакеты задерживаются до 10 минут !!! Что крайне не приемлемо, нужно по возсожности почти мгновенная передача.


Давайте посчитаем. 100 клиентов присылают каждый по 5 раз по 4 кб, т.е. около 2 МБ (в секунду!). Сервер должен отправить эти же данные остальным 99 клиентам (от каждого всем), т.е. 2 * 99 = 198 мегабайт в ту же секунду . Или я что-то неправильно понял, или вы слишком многого хотите? На тестовых машинах сетевые карты гигабитные или сотки?

Если я всё же понял задачу правильно, то достигнутый предел в 50-60 клиентов это весьма неплохой результат.
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 22.02.12 05:22
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Давайте посчитаем. 100 клиентов присылают каждый по 5 раз по 4 кб, т.е. около 2 МБ (в секунду!).


У него один клиент шлёт.
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 22.02.12 08:47
Оценка:
Здравствуйте, Gomes, Вы писали:

G>У него один клиент шлёт.


Не похоже, судя по коду полученное от клиента сообщение отсылается всем остальным клиентам:


unsigned int __stdcall _thread_start_proc(void *arg)
{
//пропуск кода
    while (1) {   
        std::string r;

        recve_line( s, r );

        user_counter = 0;
        time(&start);
        if (r.empty()) 
            break;
        
        for (std::list<SOCKET>::iterator it = clients.begin(); it != clients.end(); it++) {
            if (*it != s) 
                send(*it, r.c_str(), r.length(), 0);
            user_counter++;
        }        
        system("cls");
        time (&end);
        dif = difftime (end,start);
        log( "I spent %.4f sec that would send data to %d users\n", dif, user_counter);
    }
//пропуск кода
}

int main( int argc, char **argv )
{
//пропуск кода
    while( true )
    {
        if((_socket = accept(listener, (sockaddr *)&addr, &size)) != INVALID_SOCKET)
        {
            printf("accept: %d\n", _socket);
            ioctlsocket(_socket, FIONBIO, &argp);

            unsigned int thid;
            printf("pass socket: %d\n",_socket);
            _beginthreadex(0, 0, _thread_start_proc, (void *)&_socket, 0, &thid);
        }
        Sleep(1000);
    }
//пропуск кода
}


Тоесть получается данные от любого клиента отсылаются всем остальным клиентам.
ТС все верно?
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 22.02.12 09:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не похоже, судя по коду полученное от клиента сообщение отсылается всем остальным клиентам:


Так точно.

А>Тоесть получается данные от любого клиента отсылаются всем остальным клиентам.


Нет. Получается что от одного всем. На этом был акцент. Не надо придумывать.
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 22.02.12 09:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Gomes, Вы писали:


G>>У него один клиент шлёт.


А>Не похоже, судя по коду полученное от клиента сообщение отсылается всем остальным клиентам:


Так точно, но источник у меня один. То есть один шлет данные, все остальные получают.

А>Тоесть получается данные от любого клиента отсылаются всем остальным клиентам.

А>ТС все верно?
Да верно, по коду так. (просто логика кода, эдакий большой чат сервер) но на деле, у меня один источник, все остальные молча принимают данные.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 22.02.12 09:27
Оценка:
Получилось что-нибудь?
Re: Нагруженный TCP сервер как и на чем реализовать
От: 5er Россия  
Дата: 22.02.12 09:39
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Всем добрый день,


...

S>Прошу помощи. Если возможно в чем проблема в данном подходе, и есть ли более удачные варианты реализации мгновенной передачи данных от одного клиента всем. UDP не подходит. Так как клиенты сидят в интернете, а не за одной сеткой.


Посмотрите в сторону IGMP multicast.
Основным недостатком будет являться обязательная поддержка малтикаста всеми промежуточными маршрутизаторами и сетевыми картами,
но как вариант для задачи "удачные варианты реализации мгновенной передачи данных от одного клиента всем" вполне решение.
Там же IGMP snooping.
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 22.02.12 10:11
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Получилось что-нибудь?

Нет, все еще попытки сделать что-то "нормальное". В том числе с помощью твоей библы
Re[2]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 22.02.12 10:30
Оценка:
Здравствуйте, 5er, Вы писали:

5er>Здравствуйте, stronciy77, Вы писали:


S>>Всем добрый день,


5er>...


S>>Прошу помощи. Если возможно в чем проблема в данном подходе, и есть ли более удачные варианты реализации мгновенной передачи данных от одного клиента всем. UDP не подходит. Так как клиенты сидят в интернете, а не за одной сеткой.


5er>Посмотрите в сторону IGMP multicast.

5er>Основным недостатком будет являться обязательная поддержка малтикаста всеми промежуточными маршрутизаторами и сетевыми картами,
5er>но как вариант для задачи "удачные варианты реализации мгновенной передачи данных от одного клиента всем" вполне решение.
5er>Там же IGMP snooping.
Не знаю тонкостей IGMP, но для меня такой вариант к сожалению исключен, потому что клиенты (которые слушают) разбросаны по всему миру. Если бы сидели за одной сеткой, сделал бы UDP рассылку и всех делов...
Re[7]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 22.02.12 10:52
Оценка:
На вскидку:

BOOL CALLBACK OnConnect( PCONNECTION pConnection )
{
    // Постим для всех.
    PServer.PostRecv( pConnection, pConnection->pbBuffer, BUF_SIZE, NULL );
}

BOOL CALLBACK EnumConnectionsProc( PCONNECTION pConnection, PVOID pvParam )
{
    // Получаем подключение-источник.
    PCONNECTION pSource = (PCONNECTION) pvParam;

    // Шлём собственно.
    PServer.PostSend( pConnection, pSource->pbBuffer, (DWORD) pSource->pvPerConnectionUserData, NULL );
}

BOOL CALLBACK OnRecv( PCONNECTION pConnection, PIO_DATA pIoData )
{
    //
    // Возможно необходима проверка что приняли всё.
    //

    // Сохраняем количество принятых байт.
    pConnection->pvPerConnectionUserData = (PVOID) pIoData->dwBytesTransferred;

    //
    // Перечисляем подключения. Параметром передаем подключение-источник.
    //
    // Тут надо понимать, что мы занимаем целый поток из пула на перечисление и отправку.
    // Можно избавиться, используя UserPool, но, усложняя логику.
    //
    PServer.EnumConnections( EnumConnectionsProc, (PVOID) pConnection );

    // Всё отправлено.
    // Постим следующий запрос на приём.
    PServer.PostRecv( pConnection, pConnection->pbBuffer, BUF_SIZE, NULL );
}

BOOL CALLBACK OnSend( PCONNECTION pConnection, PIO_DATA pIoData )
{
    // Возвращем TRUE наверно.
}
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Crackjack Россия  
Дата: 25.02.12 08:08
Оценка:
Здравствуйте, Nikolay_Ch, Вы писали:

N_C>Здравствуйте, Crackjack, Вы писали:


C>> В итоге ты получаешь замкнутый цикл типа while(1){}, вот тебе и загрузка CPU

N_C>В принципе, маленького вызова sleep с параметром 10 должно хватить для снижения загрузки CPU до приемлемых процентов... Не?
Sleep в Win32 в любом случае делает задержку не менее 55 мс. т.к. пользуется обычным таймером величина тика которого равна 55 мс., я считаю применение Sleep — это не выход из положения в данных ситуациях. За это время, пока находимся в Sleep, можно вычитать из сокета большую порцию данных.
Re[3]: Нагруженный TCP сервер как и на чем реализовать
От: Crackjack Россия  
Дата: 25.02.12 08:15
Оценка:
Здравствуйте, stronciy77, Вы писали:

S>Здравствуйте, AltCtrlDel, Вы писали:


ACD>>я только что тестировал свой проект под нагрузкой — ок. В чём то схоже.

ACD>>Сделал на boost::asio.
ACD>>На "чистых" сокетах я тоже раньше делал, но тут быстрее получается. Если не считать чтения манула по asio.
ACD>>Но с нуля на сокетах ещё больше читать надо и дольше отлаживать.

S>Ясно, я тоже сомтрел на boost но там 60 метров библиотек ... Не суть, для дела не жалко, а как у него с "быстрой" разадчей, то есть если есть куча медленных и куча быстрых клиентов ?


В любом случае boost использует Win API. Есть вероятность конечно что ихняя реализация обмена в неблокирующем режиме будет качественней, чем ваша, но где тут заблудиться то можно в вашей задаче когда на WinSock делать, равнозначно как в 3-х березах заблудиться.
Re[4]: Нагруженный TCP сервер как и на чем реализовать
От: Crackjack Россия  
Дата: 25.02.12 08:26
Оценка:
Здравствуйте, maxlosyam, Вы писали:

M>вот тут http://www.tenouk.com/Module41.html есть пример сервера на select, все делается в одном потоке. просто почитайте поищите про select.

Вообще select введен для совместимости с кодами UNIX. Для Win родное — это OVERLAPED, а для улутшения работы с OVERLAPED применяется IOCP.
В принципе когда у машины один процессор с одним ядром, то при хорошей реализации однопоточное приложение будет работать быстрее, чем многопоточное. Только реализовать такое приложение сложнее, чем многопоточное. Это я к вопросу о тысячах подключений и по потоку на обработку каждого подключения.
Re[5]: Нагруженный TCP сервер как и на чем реализовать
От: Аноним  
Дата: 26.02.12 07:36
Оценка:
Здравствуйте, Crackjack, Вы писали:

C>Здравствуйте, maxlosyam, Вы писали:


M>>вот тут http://www.tenouk.com/Module41.html есть пример сервера на select, все делается в одном потоке. просто почитайте поищите про select.

C>Вообще select введен для совместимости с кодами UNIX. Для Win родное — это OVERLAPED, а для улутшения работы с OVERLAPED применяется IOCP.
C>В принципе когда у машины один процессор с одним ядром, то при хорошей реализации однопоточное приложение будет работать быстрее, чем многопоточное. Только реализовать такое приложение сложнее, чем многопоточное. Это я к вопросу о тысячах подключений и по потоку на обработку каждого подключения.

Вы абсолютно правы, потому что данный пример из ссылки, был переделан под винду (с минимальными изменениями) но и это не спасло "отца русской демократии" (с)
Вот к слову код

#include <winsock2.h>
#include <stdio.h>
#include <time.h>
#include <process.h>

#pragma comment(lib,"ws2_32.lib")

/*******select.c*********/

/*******Using select() for I/O multiplexing */


/* port we're listening on */

#define PORT 2020


int main(int argc, char *argv[])

{
    WSADATA lpData;
    /* master file descriptor list */
    fd_set master;
    /* temp file descriptor list for select() */
    fd_set read_fds;
    /* server address */
    struct sockaddr_in serveraddr;
    /* client address */
    struct sockaddr_in clientaddr;

    /* maximum file descriptor number */
    int fdmax;

    /* listening socket descriptor */
    int listener;

    /* newly accept()ed socket descriptor */
    int newfd;

    /* buffer for client data */
    char buf[1024];
    int nbytes;

    /* for setsockopt() SO_REUSEADDR, below */
    int yes = 1;
    int addrlen;
    int i, j;

    /* clear the master and temp sets */

    FD_ZERO(&master);
    FD_ZERO(&read_fds);
    
    WSAStartup(MAKEWORD(2, 2), &lpData);


    /* get the listener */

    if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        WSACleanup();
        printf("Server-socket() error lol!");
        /*just exit lol!*/
        exit(1);

    }

    printf("Server-socket() is OK...\n");
    /*"address already in use" error message */

    if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(int)) == -1)
    {
        printf("Server-setsockopt() error lol!");
        exit(1);
    }

    printf("Server-setsockopt() is OK...\n");

    /* bind */
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = INADDR_ANY;
    serveraddr.sin_port = htons(PORT);
    memset(&(serveraddr.sin_zero), '\0', 8);



    if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
    {
        printf("Server-bind() error lol!");
        exit(1);
    }

    printf("Server-bind() is OK...\n");

    /* listen */

    if(listen(listener, 10) == -1)
    {
        printf("Server-listen() error lol!");
        exit(1);

    }

    printf("Server-listen() is OK...\n");

    /* add the listener to the master set */

    FD_SET(listener, &master);
    /* keep track of the biggest file descriptor */
    fdmax = listener; /* so far, it's this one*/

    /* loop */
    for(;;)
    {
        /* copy it */
        read_fds = master;

        if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
        {
            printf("Server-select() error lol!");
            exit(1);
        }

        printf("Server-select() is OK...\n");

        /*run through the existing connections looking for data to be read*/
        for(i = 0; i <= fdmax; i++)
        {
            if(FD_ISSET(i, &read_fds))
            { /* we got one... */
                if(i == listener)
                {
                    /* handle new connections */
                    addrlen = sizeof(clientaddr);
                    if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
                    {
                        printf("Server-accept() error lol!");
                    }
                    else
                    {
                        printf("Server-accept() is OK...\n");
                        
                        FD_SET(newfd, &master); /* add to master set */

                        if(newfd > fdmax)
                        { /* keep track of the maximum */
                            fdmax = newfd;
                        }
                        printf("%s: New connection from %s on socket %d\n", argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
                    }
                }
                else
                {
                    /* handle data from a client */
                    if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
                    {
                        /* got error or connection closed by client */
                        if(nbytes == 0)
                            /* connection closed */
                            printf("%s: socket %d hung up\n", argv[0], i);
                        else
                            printf("recv() error lol!");

                        /* remove from master set */
                        FD_CLR(i, &master);
                    }
                    else
                    {
                        /* we got some data from a client*/
                        for(j = 0; j <= fdmax; j++)
                        {
                            /* send to everyone! */
                            if(FD_ISSET(j, &master))
                            {
                                /* except the listener and ourselves */
                                if(j != listener && j != i)
                                {
                                    if(send(j, buf, nbytes, 0) == -1)

                                        printf("send() error lol!");
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    WSACleanup();
    return 0;

}
Re[6]: Нагруженный TCP сервер как и на чем реализовать
От: Gomes Россия http://irazin.ru
Дата: 26.02.12 20:03
Оценка:
Я там ниже код давал. Не помогло?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.