Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.77/48: Рейтинг темы: голосов - 48, средняя оценка - 4.77
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80

Клиент-сервер.. IP-адрес подключившегося

12.08.2011, 15:35. Показов 9732. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Взял за основу такой сервер (эхо):

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <algorithm>
#include <set>
 
using namespace std;
 
int main()
{
    int 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);
    }
    
    fcntl(listener, F_SETFL, O_NONBLOCK);
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(13425);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }
 
    listen(listener, 2);
    
    set<int> clients;
    clients.clear();
 
    while(1)
    {
        // Заполняем множество сокетов
        fd_set readset;
        FD_ZERO(&readset);
        FD_SET(listener, &readset);
 
        for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
            FD_SET(*it, &readset);
 
        // Задаём таймаут
//        timeval timeout;
//        timeout.tv_sec = 15;
//        timeout.tv_usec = 0;
 
        // Ждём события в одном из сокетов
        int mx = max(listener, *max_element(clients.begin(), clients.end()));
        if(select(mx+1, &readset, NULL, NULL, 0) <= 0) //  if(select(mx+1, &readset, NULL, NULL, &timeout) <= 0)
        {
            perror("select");
            exit(3);
        }
        
        // Определяем тип события и выполняем соответствующие действия
        if(FD_ISSET(listener, &readset))
        {
            // Поступил новый запрос на соединение, используем accept
            int sock = accept(listener, NULL, NULL);
            if(sock < 0)
            {
                perror("accept");
                exit(3);
            }
            
            fcntl(sock, F_SETFL, O_NONBLOCK);
 
            clients.insert(sock);
        }
 
        for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
        {
            if(FD_ISSET(*it, &readset))
            {
                // Поступили данные от клиента, читаем их
                bytes_read = recv(*it, buf, 1024, 0);
 
                if(bytes_read <= 0)
                {
                    // Соединение разорвано, удаляем сокет из множества
                    close(*it);
                    clients.erase(*it);
           printf(buf);
                    continue;
                }
 
                // Отправляем данные обратно клиенту
                send(*it, buf, bytes_read, 0);
            }
        }
    }
    
    return 0;
}
Подскажите, как выделить IP-адрес каждого отдельно подключившегося клиента. Хочу сделать, чтоб это выглядело в виде лога в файл.
Полагаю, с этой строчкой надо экспериментировать:
C++
1
int sock = accept(listener, NULL, NULL);
но вместо этих NULL както не выходит нужное подставить, чтоб адреса куда-нибудь писались.

Есть строчка, где переданные данные от клиента сохраняются:
C++
1
bytes_read = recv(*it, buf, 1024, 0);
..в переменную buf. И вот бы так же само в другую переменную адрес вписать
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
12.08.2011, 15:35
Ответы с готовыми решениями:

Клиент сервер через mac адрес
Всем привет. Ребят помогите пожалуйста. Нужно написать мини прогу клиент и сервер которые используют mac адрес. У меня есть пример с Ip...

Получить ip адрес клиента (асинхронный клиент - сервер)
Не могу получить ip адрес клиента (асинхронный клиент - сервер) при получении сообщения на стороне клиента. Помогите пожалуйста если кто...

TCP клиент-сервер - Требуемый адрес для своего контекста не верен
Реализован клиент и сервер. Сервер - консольное приложение. Клиент - приложение WinForms СЕРВЕР public Socket...

18
 Аватар для pomkalk
365 / 247 / 24
Регистрация: 03.04.2011
Сообщений: 558
Записей в блоге: 1
12.08.2011, 18:32
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <arpa/inet.h>
 
...
//Также создаешь структуру как для хоста
struct sockaddr_in peer;
//вторым параметром передаешь саму структуру, третьим ее размер(возможно нужно будет в socklen_t переделать)
sock = accept(socket,(struct sockaddr*)&peer,sizeof(peer));
или так
int size = sizeof(peer);
sock = accept(socket,(struct sockaddr*)&peer,(socklen_t)size);
//так получаешь адрес, в char*
printf("%s\n",inet_ntoa(peer));
Bash
1
2
man inet_addr
man accept
там все есть!


может что то не работать, код не проверял, может ошибку сделал
1
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
12.08.2011, 19:33  [ТС]
Добавил Ваш код. Вот компилируется в таком варианте:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <algorithm>
#include <set>
 
using namespace std;
 
int main()
{
    int listener;
    struct sockaddr_in addr;
    struct sockaddr_in peer;
    int size = sizeof(peer);
    char buf[1024];
    int bytes_read;
 
    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        exit(1);
    }
    
    fcntl(listener, F_SETFL, O_NONBLOCK);
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(13425);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }
 
    listen(listener, 2);
    
    set<int> clients;
    clients.clear();
 
    while(1)
    {
        // Заполняем множество сокетов
        fd_set readset;
        FD_ZERO(&readset);
        FD_SET(listener, &readset);
 
        for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
            FD_SET(*it, &readset);
 
        // Задаём таймаут
//        timeval timeout;
//        timeout.tv_sec = 15;
//        timeout.tv_usec = 0;
 
        // Ждём события в одном из сокетов
        int mx = max(listener, *max_element(clients.begin(), clients.end()));
        if(select(mx+1, &readset, NULL, NULL, 0) <= 0) //  if(select(mx+1, &readset, NULL, NULL, &timeout) <= 0)
        {
            perror("select");
            exit(3);
        }
        
        // Определяем тип события и выполняем соответствующие действия
        if(FD_ISSET(listener, &readset))
        {
            // Поступил новый запрос на соединение, используем accept
            int sock = accept(listener, (struct sockaddr*)&peer, (socklen_t*)size);
            if(sock < 0)
            {
                perror("accept");
                exit(3);
            }
            
            fcntl(sock, F_SETFL, O_NONBLOCK);
 
            clients.insert(sock);
        }
 
        for(set<int>::iterator it = clients.begin(); it != clients.end(); it++)
        {
            if(FD_ISSET(*it, &readset))
            {
                // Поступили данные от клиента, читаем их
                bytes_read = recv(*it, buf, 1024, 0);
 
                if(bytes_read <= 0)
                {
                    // Соединение разорвано, удаляем сокет из множества
                    close(*it);
                    clients.erase(*it);
                    continue;
                }
 
                // Отправляем данные обратно клиенту
                send(*it, buf, bytes_read, 0);
            }
        }
    }
    
    return 0;
}
..вместо (socklen_t)size надо было только (socklen_t*)size и выражение "sock = ..." изменил.
Но теперь есль допустим просто браузером подключиться к этому порту - программа сразу с ошибкой выходит:
accept: Bad address

Что подправить?
0
 Аватар для pomkalk
365 / 247 / 24
Регистрация: 03.04.2011
Сообщений: 558
Записей в блоге: 1
12.08.2011, 19:44
Да да, точно, и исправлял, где то накосячил, вот тут нежно добавить &
C++
1
int sock = accept(listener, (struct sockaddr*)&peer, (socklen_t*)&size);//Для size
1
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
12.08.2011, 20:52  [ТС]
Урра.. огромное спасибо! Ещё вот тут в выводе адреса надо было добавить ".sin_addr":
C++
1
printf("%s\n", inet_ntoa(peer.sin_addr));
как я понимаю, это чтоб не всю структуру в Char переделывать, а только сам адрес
1
 Аватар для pomkalk
365 / 247 / 24
Регистрация: 03.04.2011
Сообщений: 558
Записей в блоге: 1
12.08.2011, 20:58
Ага, правильно, совсем забыл))
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
12.08.2011, 23:47
also
man getpeername
0
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
13.08.2011, 01:27  [ТС]
SYNOPSIS
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


А в чём существенное различие?
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
13.08.2011, 03:24
столько говнокода нагородили)
socket.remote_endpoint()
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
13.08.2011, 10:37
Цитата Сообщение от Alexoy Посмотреть сообщение
SYNOPSIS
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


А в чём существенное различие?
в том, что accept заполняет структуру после соединения (подключения клиента).
getpeername может получить удаленный узел (адрес подключенной точки) в любой момент, пока жив сокет.
0
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
13.08.2011, 22:34  [ТС]
Цитата Сообщение от niXman Посмотреть сообщение
столько говнокода нагородили)
socket.remote_endpoint()
Так всё плохо с кодом?) Я где-то читал, что дополнительными библиотеками можно более удобно и быстро писать что-то на основе клиент-сервер.. может даже больше производительность будет - это так?

А так предполагалось, что получение адреса дополнительная возможность.. главное сам сервер. Можете предложить как-то улучшить сервер?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
13.08.2011, 22:41
можно более удобно и быстро писать что-то на основе клиент-сервер
можно, если эти библиотеки знать. А можно и наоборот завалить все.
Можете предложить как-то улучшить сервер?
убрать хардкод номера порта, например.
А вообще от задачи зависит. Сперва неплохо б протокол разработать, потом от него плясать.
0
 Аватар для pomkalk
365 / 247 / 24
Регистрация: 03.04.2011
Сообщений: 558
Записей в блоге: 1
13.08.2011, 22:51
Цитата Сообщение от villu Посмотреть сообщение
Сперва неплохо б протокол разработать, потом от него плясать.
Че за чушь, зачем эти грабли и велосипеды, чет TCP не устроил??
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
13.08.2011, 22:52
> Че за чушь, зачем эти грабли и велосипеды, чет TCP не устроил??

OMG!
http://ru.wikipedia.org/wiki/%... %D1%8C_OSI

Читать до просветления.
0
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
13.08.2011, 23:01  [ТС]
Цитата Сообщение от villu Посмотреть сообщение
убрать хардкод номера порта, например
Вы же не про то место, где указан порт на котором слушает сервер?! А где еще?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
13.08.2011, 23:08
Ну, если я правильно понял, то предполагается некий сервер, который будет что-то делать, ага?
порт можно, например, в параметр командной строки вынести...да и адрес туда же.

Еще убрать sockaddr_in, да и вообще не привязываться к конкретному семейству (AF_INET в данном случае).

Ну и если писать все на С++ (а не на чистом Си), то лучше пользоваться механизмами языка.
0
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
13.08.2011, 23:16  [ТС]
аа.. "хардкод" у Вас это когда конкретное значение буквально приварено и не поменяешь уже?!

Цитата Сообщение от villu Посмотреть сообщение
Еще убрать sockaddr_in, да и вообще не привязываться к конкретному семейству (AF_INET в данном случае).
Ну и если писать все на С++ (а не на чистом Си), то лучше пользоваться механизмами языка.
..это как тогда?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
13.08.2011, 23:41
"хардкод" у Вас это когда конкретное значение буквально приварено и не поменяешь уже?!
Ага. Для тестовых работ годится, но вообще даже в начале реального проекта этот подход очень плохо.
..это как тогда?
Смотри.
Есть такая структура
struct sockaddr_storage;
описана в sys/socket.h
Эта структура - "общая" для всех (sockaddr_in, sockaddr_in6, sockaddr)
У этой структуры есть поле ss_family
Далее пользуемся теми самыми возможностями языка.

пишем
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct sockaddr_storage_t: public sockaddr_storage {
    unsigned int    size_;
 
    sockaddr_storage_t()
        :size_(sizeof(sockaddr_storage))
    {
        memset(this, 0, size_);
    }
// вызов для преобразования 
    template <typename T>
    inline T get() {
        return reinterpret_cast<T>(this);
    }
    inline
    sockaddr * get() {
        return get<sockaddr *>();
    }
 
};
теперь у нас в одном месте есть структура, которая содержит инфу о семействе и о размере.
можно, например добавить ей метод для инициализации, который сам установит и семейство, и адрес, и порт, и размер
например
C++
1
2
3
4
sockaddr_storage_t::init(const std::string &_addr, const std::string &srv) {
..... 
тут, например можно поюзать getaddrinfo и выбрать конкретную точку привязки, либо выкинуть исключение.
}
далее создание и инициализация:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
....
int accepter = -1;
sockaddr_storage_t local;
 
try {
//    local.init("127.0.0.1", "12345"); для IPv4
    local.init("::1", "12345"); // для IPv6 
 
    accepter = checker = socket(local.ss_family, SOCK_STREAM, 0);
...
    checker = bind(accepter, local.get(), local.size_);
...
} catch (const common_net_error_t &err) {
    log << err.func() << ": " << err.what();
}
checker это "проверщик", опрератор (=) которого проверяет -1 и выбрасывает исключение common_net_error_t. Это так, чтоб не смущало.

Вот как-то так. далее в эту структуру можно прикрутить, например, метод получение строки из адреса (см inet_ntop).
1
5 / 5 / 0
Регистрация: 07.07.2010
Сообщений: 80
14.08.2011, 16:15  [ТС]
даа.. боюсь не потяну так сразу) ..пока соберу все эти кусочки воедино..
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.08.2011, 16:15
Помогаю со студенческими работами здесь

Взаимодействие WinCC с Labview 2013, как сервер-клиент, так и клиент-сервер
Здравствуйте. Интересует информация о взаимодействии WinCC с Labview 2013, как сервер-клиент, так и клиент-сервер через ОРС-инфтерфейс. ...

Клиент-сервер в один клик!(элемет сервер, клиент)
Вот решил поделиться с вами своей идеей и её реализацией. Всегда написание Сервера и Клиента к нему занимало много времени. Сначала хотел...

Клиент-Серверное приложение. Как сделать, чтобы сервер сам отправлял сообщения на клиент
Добрый день всем. Проблема заключается в следующем: Есть клиент-серверное приложение, хочу реализовать своего рода защиту, чтобы при...

Клиент-сервер: клиент требует повторно сгенерировать массив
Здравствуйте, есть программы клиент и сервер, клиент после требуемого ввода IP, пароля и генерации элементов массива всё равно требует...

Клиент-серверное приложение. Сервер - ПК, клиент - телефон (Android)
Здравствуйте, решил для обучения написать программу для выключения ПК с телефона, используя компонент TIdTCPServer. Подскажите, как...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20%
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru