Сокеты vs Пайпы
От: Аноним  
Дата: 21.08.07 19:11
Оценка:
Столкнулся со следующей проблемой. Написал простейший клиент-сервер на сокетах и на пайпах. Все отлично работает, но не совсем понятен следующий момент:

пересылаю по сокетам 1Мб за 1цикл ~16мс
пересылаю по сокетам 1Кб за 1000 циклов ~300мс
это localhost. по локалке до нескольких минут может передаваться.., про инет можно догадаться..
включал\отключал TCP_NODELAY, не помогло.
сокет создается 1 раз и потом в цикле идут send\recv

на пайпах: 0 и 30 мс соответственно, причем по сети не намного медленнее..

В чем проблема?
Re: Сокеты vs Пайпы
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.08.07 02:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Столкнулся со следующей проблемой. Написал простейший клиент-сервер на сокетах и на пайпах. Все отлично работает, но не совсем понятен следующий момент:


А>пересылаю по сокетам 1Мб за 1цикл ~16мс

А>пересылаю по сокетам 1Кб за 1000 циклов ~300мс
А>это localhost. по локалке до нескольких минут может передаваться.., про инет можно догадаться..
А>включал\отключал TCP_NODELAY, не помогло.
А>сокет создается 1 раз и потом в цикле идут send\recv

А>на пайпах: 0 и 30 мс соответственно, причем по сети не намного медленнее..


А>В чем проблема?



Код покажи
Re[2]: Сокеты vs Пайпы
От: Аноним  
Дата: 22.08.07 05:49
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Код покажи


Сервер и клиент работают с сокетами через один и тот же класс.
Метод инициализации сокетов одинаковый для клиента и сервера:


WSADATA wsadata;
           void Initialize()
           {
        if(WSAStartup(MAKEWORD(2,2),&wsadata)){
            throw new СIOException(WSAGetLastError());
        }
        mMainSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(mMainSocket==INVALID_SOCKET){
            throw new СIOException(WSAGetLastError());
        }

        bool opt = true;
        if(::setsockopt(mMainSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt))==SOCKET_ERROR){
            throw new СIOException(WSAGetLastError());
        }

        BOOL noDelay=TRUE;
        if(::setsockopt(mMainSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(BOOL))==SOCKET_ERROR){
            throw new СIOException(WSAGetLastError());
        }    
            }


Дальше инициализация идет для сервера:

       void Listen()
           {
        SOCKADDR_IN addr;
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=inet_addr("192.168.1.3");
        addr.sin_port=htons(33657);

        if(bind(mMainSocket,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR){
            throw new СIOException(WSAGetLastError());
        }

        if(listen(mMainSocket, SOMAXCONN)==SOCKET_ERROR){
            throw new СIOException(WSAGetLastError());
        }

        SOCKADDR tmpAddr;
        int len = sizeof(tmpAddr);

        mActiveSocket=accept(mMainSocket,(sockaddr*)&tmpAddr,(int*)&len);
        if(mActiveSocket==INVALID_SOCKET){
            throw new СIOException(WSAGetLastError());

             }
            }


И для клиента:

            void Send()
            {
        SOCKADDR_IN addr;
        addr.sin_family=AF_INET;
        addr.sin_addr.s_addr=inet_addr("192.168.1.3");
        addr.sin_port=htons(33657);

        mActiveSocket=mMainSocket;
        if(connect(mActiveSocket,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR){
            throw new СIOException(WSAGetLastError());
        }
            }


и два метода чтения и записи:


    CData Read()
    {
        CData data;
        if(mActiveSocket){
                        
                        // получаем размер пакета
            ULONG dataLen=0;
            int rcvLen=recv(mActiveSocket, (char*)&dataLen, sizeof(ULONG), 0);
            if(rcvLen==0){
                throw new CIOException("Соединение разорвано()");
            }else if(rcvLen==SOCKET_ERROR){
                    throw new CIOException(WSAGetLastError());
                }

                        //выделям память под пакет
                        data.AllocData(dataLen)
            char* dataAddr=data.GetDataAddr();

                        // принимаем пакет
            while(dataLen>0){
                rcvLen=recv(mActiveSocket, dataAddr, dataLen, 0);
                if(rcvLen==0){
                              throw new СIOException(WSAGetLastError());
                }else if(rcvLen==SOCKET_ERROR){
                          throw new СIOException(WSAGetLastError());
                }
                dataAddr+=rcvLen;
                dataLen-=rcvLen;
            }
        }
        return data;
    };

         void Write(CData& data)
    {
        if(mActiveSocket){
                          
                        // передаем размер пакета
            ULONG size=data.GetDataSize();    
            if(send(mActiveSocket,(char*)&size,sizeof(ULONG),0)==SOCKET_ERROR){
                      throw new СIOException(WSAGetLastError());
            }            
            char* dataAddr=data.GetDataAddr();
            ULONG  dataSize=data.GetDataSize();

                        // передаем пакет
            while(dataSize>0){
                int sentLen=0;
                if((sentLen=send(mActiveSocket,dataAddr,dataSize,0))==SOCKET_ERROR){
                                throw new СIOException(WSAGetLastError());
                }
                dataSize-=sentLen;
                dataAddr+=sentLen;
            }
        }
    };




ну и собственно основной код для сервера и клиента:


void ClientCore(СIOCtrl* cio)
{
    try
    {
        cio->Initialize();
        cio->Send();
        
        SendRain(cio,100,1000);
        SendRain(cio,1000,1000);

        cio->Write(_stopFlag);
        cio->CloseConnection();
        cio->ShutDown();
    }
    catch (CIOException* e)
    {
        cio->ShutDown();
        delete e;
    }
}

void SendRain(СIOCtrl* cio,ULONG size,int iterations)
{
    CData data;
    data.AllocData(size);

    DWORD ticks=::GetTickCount();
    int i;
    for(i=0; i < iterations; i++){
        cio->Write(data);
        if(vio->Read()!=size){
            echo("Ошибка при передаче данных");
            break;
        }
    }

    ticks=::GetTickCount()-ticks;
    printf("Передано %d блоков данных по %d байт за %d мс\r\n",i,size,ticks);
}


void ServerCore(СIOCtrl* cio)
{
    try
    {
        cio->Initialize();
        cio->Listen();

                   while(true){
            CData data=cio->Read();
            
            if(data ==_stopFlag){
                echo("Режим завершен успешно.");
                                break;
            }else{
                                CData size=data.GetDataSize();
                cio->Write(size);
            }
        }
        cio->ShutDown();
    }
    catch (CIOException* e)
    {
        cio->ShutDown();
        delete e;    
    }
}
Re: Сокеты vs Пайпы
От: TarasCo  
Дата: 22.08.07 06:45
Оценка:
1. Если при измерениях получены "волшебные" числа — 0мс, 15мс, 30мс — это свидетельства потери квантов времени исполняющим потоком. Квант у нас обычно 10 или 15 мс ( на десктопах )
2. Разное поведение свидетельствует о разной логике интерфейса драйвер-пользовательское приложение. Возможны следующие модели:
— синхронный драйвер — управление не будет возвращено до тех пор пока драйвер реально не обработает запрос ( возможно, просто скопирует пользовательский буфер ). Допустим пользовательское приложение в цикле обращается к драйверу. В таком случае за отведенный квант времени пользовательское приложение успеет выполнить фиксированное количество запросов и соответственно передать фиксированный объем данных
— асинхронный драйвер — если запрос не может быть обработан немедленно ( например для TCP/IP драйвера ситуация когда буфер передачи уже заполнен ), управление возвращается пользовательскому приложению со статусом PENDING, буфера блокируются в памяти ( если только ввод/ввод не буферизированный ). Когда операция оканчивается — система уведомляет пользовательское приложение об этом. И вот тут возможны два варианта поведения приложения:
а) Приложение работает с драйвером как с синхронным. Вот тут важно! В этом случае система сама организует синхронный режим — переходит в режим ожидания завершения операции. А каждый переход в режим ожидания приводит к перепланировке задач и потери кванта времени. Т.е если ваш поток в самом начале своего кванта выполнения выполнит синхронную операцию, то в лучшем случае он получит управления, когда операция будет выполнена ( если нет активных задач ), в худшем — потеряет несколько квантов времени ( на серверных платформах квант может быть и 50мс, так что терять их довольно накладно ). В результате в передачи могут быть внушительные дыры.
б) Приложение работает с драйвером как с асинхронным. В Вашем случае это могло бы выглядить так: вызов в цикле операции WSASend даже если она вернула код ошибки ( конечно, нужно убедиться, что код ошибки WSA_IO_PENDING ), а потом ожидание окончания всех операций. В этом случае можно получить максимальную производительность.

Это так сказать теория.....
Да пребудет с тобою сила
Re[3]: Сокеты vs Пайпы
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.08.07 18:20
Оценка:
Здравствуйте, Аноним, Вы писали: ...

Для сокетов результат очевиден. send и recv тяжелые операции из-за копирования данных в ядро и назад, recv чаще всего вызывает переключение потока.
При передачи по сети без TCPNODELAY результат вообще будет ужасным.

А вот с пайпами интереснее. Возможно пайпы на локальном компьютере вообще не используют сокеты. Хотя хотелось бы увидеть код с пайпами.
Re: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 06:57
Оценка:
А>В чем проблема?
Я по неопытности думал что сокеты это достаточно просто... оказалось все совсем наоборот... Тогда подскажите, раз такие грабли с сокетами, и они появились не сегодня ( и грабли и сокеты , может быть есть относительно доступные библиотеки в которых учтены все эти тонкости и на которых можно организовать наиболее эффективную работу сервера и клиента? Первоначально предпологалось выявить наиболее производительный способ связи между сервером и клиентом в локальной сети. Пайпы взяли чисто для сравнения, думая что сокеты это есть круто, но есть ощущение что это не совсем так..
Re[2]: Сокеты vs Пайпы
От: TarasCo  
Дата: 23.08.07 08:40
Оценка:
А>Пайпы взяли чисто для сравнения, думая что сокеты это есть круто, но есть ощущение что это не совсем так..

Это только ощущение. Сокеты — это всего лишь интерфейс к транспортному драйверу. Сам транспортный драйвер, будте уверены, работает очень быстро и эффективно. Интерфейс тоже не самый медленный — например, FTP клиент может запросто скачивать файл со скоростью в 80% от пропускной способности сети. По поводу пайпов — они по разному реализованы для локального и для сетевого варианта использования. Если идет локальный обмен, используется ( вроде ) LPC, что в конце концов сводится просто к разделяемой области памяти. При работе через сеть используется все тот же транспортный драйвер. Вообще, если сеть 100МБ, то основное ограничение в скорости — пропускная способность а не тонкости устройства драйверов.
Да пребудет с тобою сила
Re[2]: Сокеты vs Пайпы
От: Michael Chelnokov Украина  
Дата: 23.08.07 09:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Первоначально предпологалось выявить наиболее производительный способ связи между сервером и клиентом в локальной сети.


Для чего?
Re[2]: Сокеты vs Пайпы
От: Gomes Россия http://irazin.ru
Дата: 23.08.07 10:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>может быть есть относительно доступные библиотеки в которых учтены все эти тонкости и на которых можно организовать наиболее эффективную работу сервера и клиента?

Есть то они есть, но для понимания процесса неплохо бы и литературку какую полистать. Например: A. Jones, J. Ohlund, "Network Programming for Windows" и Й. Снейдер, "Эффективное программирование TCP/IP". Т.к. ссылки на книги здесь не приветствуются, то скажу, что у меня на сайте их нет
Re[4]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 11:50
Оценка:
G>А вот с пайпами интереснее. Возможно пайпы на локальном компьютере вообще не используют сокеты. Хотя хотелось бы увидеть код с пайпами.
Не испульзуют. Локально пайпы работают сразу через shared memory и потому локально конечно на порядок шустрее сокетов.
Re[5]: Сокеты vs Пайпы
От: TarasCo  
Дата: 23.08.07 13:39
Оценка:
G>>Локально пайпы работают сразу через shared memory и потому локально конечно на порядок шустрее сокетов.

Это кстати не факт абсолютно. Локальные соединения создаются без использования на самом деле TCP стека и передача блока данных в наилучшем случае будет сводиться к одному копированию — из пользовательского буфера передающего приложения в буфер принимающего. И проигрыша на порядок по сравнению с пайпами быть не должно. При оптимальном использовании совкетов производительность должна быть примерно равна.
Да пребудет с тобою сила
Re[3]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 13:59
Оценка:
Здравствуйте, TarasCo, Вы писали:

А>>Пайпы взяли чисто для сравнения, думая что сокеты это есть круто, но есть ощущение что это не совсем так..


TC>Это только ощущение. Сокеты — это всего лишь интерфейс к транспортному драйверу. Сам транспортный драйвер, будте уверены, работает очень быстро и эффективно. Интерфейс тоже не самый медленный — например, FTP клиент может запросто скачивать файл со скоростью в 80% от пропускной способности сети.


Да, передавал 5мегов. send отработал мгновенно, причем за один раз. Качал через интернет. Канал был загружен на всю катушку 500кб\сек. Смотрел через файрвол, он показывал какое приложение с какой скоростью принимает\отсылает данные. Как только стал отсылать мелочь по 100 байт. сразу скорость упала до 0.5 кб на прием и отправку. т.е. 1 цикл: отправил 5мб принял 4б выполнился за ~200мс через интернет. 1000 циклов: отправил 100 байт принял 4 байта выполнились за 7 минут. реально передано 100кб... т.е тупой send\receive непрокатывает для мелких запросов ответов. надо обязательно делать асинхронную обвеску для них...
Re[6]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 14:08
Оценка:
TC>Это кстати не факт абсолютно. Локальные соединения создаются без использования на самом деле TCP стека и передача блока данных в наилучшем случае будет сводиться к одному копированию — из пользовательского буфера передающего приложения в буфер принимающего. И проигрыша на порядок по сравнению с пайпами быть не должно. При оптимальном использовании совкетов производительность должна быть примерно равна.
Не следует забывать еще и про пачку LSP через которые прогоняется трафик. Мало ли что там..
Re[3]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 14:08
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


А>>Первоначально предпологалось выявить наиболее производительный способ связи между сервером и клиентом в локальной сети.


MC>Для чего?


Как и говорил, для того чтобы определить, какой наиболее эффективный способ (по скорости двунаправленной передачи данных, независимо от размера передаваемых пакетов) связать в локальной сети два приложения. А так же связать 2 приложения запущенных на одной машине. В этом случае наверное разделяемая память вне конкуренции.
Вопрос возник когда по сокетам, в приведенном примере, стал передавать мелкие пакеты. Передавая большие объемы по сокетам и пайпам имели примерно одинаковую производительность на локальной машине ( с приемуществом пайпов ). Но при массовой пересылке мелких пакетов сокеты стали в 10 раз медленнее пайпов...
Re[7]: Сокеты vs Пайпы
От: TarasCo  
Дата: 23.08.07 14:13
Оценка:
А>Не следует забывать еще и про пачку LSP через которые прогоняется трафик. Мало ли что там..

Ну, во-первых, на чистой системе их нет. Во-вторых, никто не мешает приложению явно указывать SPI провайдера и тем самым избегать фильтрации.
Да пребудет с тобою сила
Re[3]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 14:14
Оценка:
Здравствуйте, Gomes, Вы писали:

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


А>>может быть есть относительно доступные библиотеки в которых учтены все эти тонкости и на которых можно организовать наиболее эффективную работу сервера и клиента?

G>Есть то они есть, но для понимания процесса неплохо бы и литературку какую полистать. Например: A. Jones, J. Ohlund, "Network Programming for Windows" и Й. Снейдер, "Эффективное программирование TCP/IP". Т.к. ссылки на книги здесь не приветствуются, то скажу, что у меня на сайте их нет
Жаль что нет ссылочки Теперь понятно что придется вникать в тонкости сокетов. Я как-то видел две тоненькие книженции 1 и 2-ю части про какую-то библиотеку для разработки клиент-серверных приложений, основанную на сокетах. Но тогда это мне совсем небыло нужно.. Может кто поймет про что я говорю. Может подскажет имеет смысл ее использовать ?
Re[4]: Сокеты vs Пайпы
От: Аноним  
Дата: 23.08.07 14:18
Оценка:
А>Да, передавал 5мегов. send отработал мгновенно, причем за один раз. Качал через интернет. Канал был загружен на всю катушку 500кб\сек. Смотрел через файрвол, он показывал какое приложение с какой скоростью принимает\отсылает данные. Как только стал отсылать мелочь по 100 байт. сразу скорость упала до 0.5 кб на прием и отправку. т.е. 1 цикл: отправил 5мб принял 4б выполнился за ~200мс через интернет. 1000 циклов: отправил 100 байт принял 4 байта выполнились за 7 минут. реально передано 100кб... т.е тупой send\receive непрокатывает для мелких запросов ответов. надо обязательно делать асинхронную обвеску для них...


Странно. А TCPNODELAY случайно не был включен? Изза него как раз такое может быть.
Re[4]: Сокеты vs Пайпы
От: Michael Chelnokov Украина  
Дата: 23.08.07 14:18
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как и говорил, для того чтобы определить, ...


Ради спортивного интереса что ли?
Re[5]: Сокеты vs Пайпы
От: freelancer.malma  
Дата: 23.08.07 14:23
Оценка:
Здравствуйте, Аноним, Вы писали:

А>>Да, передавал 5мегов. send отработал мгновенно, причем за один раз. Качал через интернет. Канал был загружен на всю катушку 500кб\сек. Смотрел через файрвол, он показывал какое приложение с какой скоростью принимает\отсылает данные. Как только стал отсылать мелочь по 100 байт. сразу скорость упала до 0.5 кб на прием и отправку. т.е. 1 цикл: отправил 5мб принял 4б выполнился за ~200мс через интернет. 1000 циклов: отправил 100 байт принял 4 байта выполнились за 7 минут. реально передано 100кб... т.е тупой send\receive непрокатывает для мелких запросов ответов. надо обязательно делать асинхронную обвеску для них...



А>Странно. А TCPNODELAY случайно не был включен? Изза него как раз такое может быть.


BOOL noDelay=TRUE;
if(::setsockopt(mMainSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(BOOL))==SOCKET_ERROR){
throw new СIOException(WSAGetLastError());
}

BOOL noDelay=FALSE;
if(::setsockopt(mMainSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(BOOL))==SOCKET_ERROR){
throw new СIOException(WSAGetLastError());
}

Непомогло никак.
Re[5]: Сокеты vs Пайпы
От: freelancer.malma  
Дата: 23.08.07 14:24
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали:

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


А>>Как и говорил, для того чтобы определить, ...


MC>Ради спортивного интереса что ли?


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