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


Автор: sofen 28.5.2012, 13:52
Поясните, плиз, как правильно написать сервер для работы с несколькими клиентами через сокеты (с++, линукс) ?

Автор: boostcoder 28.5.2012, 14:08
Цитата(sofen @  28.5.2012,  13:52 Найти цитируемый пост)
с++

например так: http://code.google.com/p/netclasses/source/browse/trunk/tests/server/server2.cpp

Автор: baldina 28.5.2012, 14:22
http://www.proklondike.com/books/unix/robachevsky_unix.html

а если кратко, после каждого соединения нужно отдавать обработку отдельному потоку или процессу, что бы освободить поток, слушающий на порту. иначе другие клиенты, кроме текущего, не смогут подсоединиться.
с другой стороны, нужно использовать неблокирующие функции типа select, epool, iocp.
в C++ есть высокоуровневые библиотеки, скрывающие всю эту мутотень внутри, напр. boost::asio

Автор: boostcoder 28.5.2012, 14:44
по той ссылке что я привел, 'struct server_impl' правильней назвать session. ибо это объект сессии создаваемый сервером для каждого входящего соединения.
каждый такой объект, имеет ссылку на 'struct global_context', в которой реализована глобальная логика + глобальные данные.

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

Автор: sofen 28.5.2012, 14:53
Цитата(baldina @ 28.5.2012,  12:22)
http://www.proklondike.com/books/unix/robachevsky_unix.html

а если кратко, после каждого соединения нужно отдавать обработку отдельному потоку или процессу, что бы освободить поток, слушающий на порту. иначе другие клиенты, кроме текущего, не смогут подсоединиться.
с другой стороны, нужно использовать неблокирующие функции типа select, epool, iocp.
в C++ есть высокоуровневые библиотеки, скрывающие всю эту мутотень внутри, напр. boost::asio

boost - это, конечно, интересно, но хотел разобраться в самом механизме...

вот здесь http://www.rsdn.ru/article/unix/sockets.xml нашёл следующий код сервера

Код

int main()
{
    int sock, listener;
    struct sockaddr_in addr;
    char buf[1024];
    int bytes_read;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        exit(1);
    }
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }

    listen(listener, 1);
    
    while(1)
    {
        sock = accept(listener, NULL, NULL);
        if(sock < 0)
        {
            perror("accept");
            exit(3);
        }

        while(1)
        {
            bytes_read = recv(sock, buf, 1024, 0);
            if(bytes_read <= 0) break;
            send(sock, buf, bytes_read, 0);
        }
    
        close(sock);
    }
    
    return 0;
}


получается так:

1. вначале создаём listener - слушающий сокет
2. потом sock - сокет для получения/передачи данных
3. читаю сервером данные, обрабатываю и отсылаю ответ

и теперь возникают непонятки - зачем закрывать сокет?  

close(sock); 

и потом опять его создавать, переходя по циклу while (1) ?

sock = accept(listener, NULL, NULL);

Автор: boostcoder 28.5.2012, 14:56
Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
хотел разобраться в самом механизме

увольте. я не могу такое объяснять smile 
даже http://forum.vingrad.ru/forum/topic-336344.html по этому поводу написал. эх...закончить бы ее еще..

Добавлено через 12 минут и 3 секунды
ладно...
Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
зачем закрывать сокет?

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

Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
и потом опять его создавать, переходя по циклу while (1) ?

потому что переходя к началу цикла, программа остановится на аксепте в ожидании нового подключившегося. и после его подключения, снова начнется чтение/запись в/из сокета.

Автор: baldina 28.5.2012, 15:09
Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
хотел разобраться в самом механизме

читайте Робачевского, там все просто и понятно.

Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
зачем закрывать сокет

Цитата

Это приведёт к разрыву соединения

accept - прием запроса на соединение (от очередного клиента)
пример этого эхо-сервера - простейший, он обслуживает только одного клиента в единицу времени.

Добавлено через 13 минут и 41 секунду
Цитата(sofen @  28.5.2012,  14:53 Найти цитируемый пост)
получается так:

1. вначале создаём listener - слушающий сокет
2. потом sock - сокет для получения/передачи данных
3. читаю сервером данные, обрабатываю и отсылаю ответ

не совсем.
1. socket() - создаем сокет как набор параметров соединения (протокол, тип)
2. bind() - связываем его с сервером (т.е. захватываем ресурс в нашей системе) - адрес, порт
3. listen() - инициируем процесс "прослушивания" входящих соединений
для очередного входящего соединения (инициированного клиентом)
4. accept() - принимаем запрос на соединение [пакет с флагом SYN], с этого момента соединение установлено
5. read/write читаем/пишем в стиле обычного файлового ввода/вывода [пакеты с флагом SYN-ASK/ASK]
6. close() - закрываем соединение, соединение разрывается [пакет с флагом FIN]

Автор: baldina 28.5.2012, 15:27
Цитата(baldina @  28.5.2012,  15:09 Найти цитируемый пост)
4. accept() - принимаем запрос на соединение [пакет с флагом SYN], с этого момента соединение установлено
5. read/write читаем/пишем в стиле обычного файлового ввода/вывода [пакеты с флагом SYN-ASK/ASK]
6. close() - закрываем соединение, соединение разрывается [пакет с флагом FIN] 

accept возвращает дескриптор (socket) - аналог дескриптора файла

Автор: sofen 28.5.2012, 16:05
Цитата

читайте Робачевского, там все просто и понятно.


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

Автор: boostcoder 28.5.2012, 16:26
Цитата(sofen @  28.5.2012,  16:05 Найти цитируемый пост)
решение моей задачи

а разве где-то в теме озвучена ваша задача? оО

Добавлено через 32 секунды
перечитал тему еще раз. и правда, нигде не озвучена.
а телепаты нынче в дефиците.

Автор: baldina 28.5.2012, 16:56
Цитата(boostcoder @  28.5.2012,  14:56 Найти цитируемый пост)
до строки закрытия сокета программа досдет только в случае обрыва соединения.

только в данном случае, т.е. только в паре с данным клиентом
в общем случае она туда доедет и просто в случае конца файла.
и тогда инициатором разрыва будет сервер, а не клиент.

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