Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
 Аватар для NRX
22 / 19 / 9
Регистрация: 22.09.2015
Сообщений: 161

Как правильно проверить на запрос подключения к серверу (select)

03.09.2016, 19:11. Показов 2794. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, в этой теме подсмотрел, как обойти блокировку команды accept: Функция accept

Но у меня это не работает, как только вызывается select он сразу же возвращает -1. ну я подумал, так как я не запустил клиент. Запуская клиент, подключения не происходит. Что я делаю не так?(В качестве клиента использую браузер Firefox, если я не указываю таймаут, то на функции select сервер висит(Это ожидаемо) и все прекрасно подключается)
Кусочек где происходит обработка подключения
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
while (true)
    {
        int isConnect = select(0, &mainSocket, 0, 0, &contime);
        int isSend = select(0, &sockets, 0, 0, &contime);
        //if (isConnect == SOCKET_ERROR)
        //{
            //error = WSAGetLastError();
            //std::cout << "Ошибка проверки сокета на подключение " << error << std::endl;
            //system("pause");
            //return -1;
        //}
        if (isConnect > 0)
        {
            if (iu == 100) break;
            users[iu] = accept(s, (sockaddr*)&uAddr[iu], &len);
 
            if (FAILED(users[iu]))
            {
                error = WSAGetLastError();
                std::cout << "Ошибка подключения пользователя " << error << std::endl;
                system("pause");
                return -1;
            }
            else
            {
                std::cout << "Подключен пользователь ";
                printf("%s", inet_ntoa(uAddr[iu].sin_addr));
                std::cout << std::endl;
                std::cout << "Версия клиента пользователя: ";
                int y = recv(users[iu], buff, 350, 0);
                for (int i = 0; i < y; i++)
                {
                    std::cout << buff[i];
                }
                for (int i = 0; i < y; i++) buff[i] = ' ';
                std::cout << std::endl;
                u_long start = 1;
                std::cout << iu << std::endl;
                ioctlsocket(users[iu], FIONBIO, &start);
                FD_SET(users[iu], &sockets);
                iu++;
            }
        }
        if (isSend > 0)
        {
            int is = 0;
            for (int i = 0; i < iu; i++)
            {
                is = recv(users[i], buff, 350, 0);
                if (is == SOCKET_ERROR)
                {
                    error = WSAGetLastError();
                    if (error == WSAEWOULDBLOCK) continue;
                }
                else
                {
                    for (i = 0; i < iu; i++)
                    {
                        send(users[i], buff, 350, 0);
                    }
                }
            }
        }
Весь код сервера

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include<thread>
#include <iostream>
#include <winsock.h>
#pragma comment(lib, "Wsock32.lib")
//using namespace std;
fd_set sockets;// множество сокетов пользователей
fd_set mainSocket; // множество сокетов, с одиним главным сокетом s
 
int main()
{
    setlocale(0, "");
    std::cout << "Запуск сервера \n версия: 0.0.1 \n";
    // инициализация библиотеци winsock
    WSADATA ws;
    WSAStartup(MAKEWORD(1, 1), &ws);
 
    SOCKET s;//сокет соединения
    SOCKET users[2];// соединенные клиенты
    int iu = 0;
    sockaddr_in sAddr;// адрес сервера
    sockaddr_in uAddr[2];// адреса пользователей
    char buff[350];
    buff[0] = 'a';
    ZeroMemory(&sAddr, sizeof(sAddr));// обнуление адресса
    timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;
    int error = 0;
    //создание сокета
    if (INVALID_SOCKET == (s = socket(AF_INET, SOCK_STREAM, 0)))
    {
        error = WSAGetLastError();
        std::cout << "Ошибка Сокета №" << error << std::endl;
        system("pause");
        return -1;
    }
    //заполнение адресса
    sAddr.sin_family = AF_INET;
    sAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    sAddr.sin_port = htons(8080);
    //прикрепление сокета к адрессу
    if (INVALID_SOCKET == bind(s, (sockaddr*)&sAddr, sizeof(sAddr)))
    {
        error = WSAGetLastError();
        std::cout << "Ошибка Прикрепление Сокета к адрессу №" << error << std::endl;
        system("pause");
        return -1;
    }
    // отправляем всю информацию о сокете сервера
    std::cout << "Информация о сервере: \n ip: ";
    printf("%s", inet_ntoa((in_addr)sAddr.sin_addr));
    std::cout << std::endl;
    std::cout << " Порт: " << ntohs(sAddr.sin_port) << std::endl;
    //Перевод сокета в слушующий режим
    if (FAILED(listen(s, 100)))
    {
        std::cout << "Ошибка в установке сокета в слушающий режим" << std::endl;
        system("pause");
        return -1;
    }
    std::cout << "Сервер запущен\n";
 
    FD_ZERO(&sockets);
    FD_ZERO(&mainSocket);
    FD_SET(s, &mainSocket);
    //std::thread t1(&joinUsers, users, uAddr, s, buff, iu);
    //t1.detach();
    //===============Подключение пользователя======================
    int len = sizeof(uAddr[iu]);
    timeval contime;
    contime.tv_sec = 0;
    contime.tv_usec = 50000;
    u_long start = 1;
    ioctlsocket(s, FIONBIO, &start);
    while (true)
    {
        int isConnect = select(0, &mainSocket, 0, 0, &contime);
        int isSend = select(0, &sockets, 0, 0, &contime);
        //if (isConnect == SOCKET_ERROR)
        //{
            //error = WSAGetLastError();
            //std::cout << "Ошибка проверки сокета на подключение " << error << std::endl;
            //system("pause");
            //return -1;
        //}
        if (isConnect > 0)
        {
            if (iu == 100) break;
            users[iu] = accept(s, (sockaddr*)&uAddr[iu], &len);
 
            if (FAILED(users[iu]))
            {
                error = WSAGetLastError();
                std::cout << "Ошибка подключения пользователя " << error << std::endl;
                system("pause");
                return -1;
            }
            else
            {
                std::cout << "Подключен пользователь ";
                printf("%s", inet_ntoa(uAddr[iu].sin_addr));
                std::cout << std::endl;
                std::cout << "Версия клиента пользователя: ";
                int y = recv(users[iu], buff, 350, 0);
                for (int i = 0; i < y; i++)
                {
                    std::cout << buff[i];
                }
                for (int i = 0; i < y; i++) buff[i] = ' ';
                std::cout << std::endl;
                u_long start = 1;
                std::cout << iu << std::endl;
                ioctlsocket(users[iu], FIONBIO, &start);
                FD_SET(users[iu], &sockets);
                iu++;
            }
        }
        if (isSend > 0)
        {
            int is = 0;
            for (int i = 0; i < iu; i++)
            {
                is = recv(users[i], buff, 350, 0);
                if (is == SOCKET_ERROR)
                {
                    error = WSAGetLastError();
                    if (error == WSAEWOULDBLOCK) continue;
                }
                else
                {
                    for (i = 0; i < iu; i++)
                    {
                        send(users[i], buff, 350, 0);
                    }
                }
            }
        }
    //==========================================================
}
    
    system("pause");
 
}


Добавлено через 4 минуты
при обработке ошибки WSAGetLastError(); возвращает WSAEINVAL
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
03.09.2016, 19:11
Ответы с готовыми решениями:

Как правильно сделать запрос к серверу
Создаю https строку - запрос для сервера VK, вставляю в браузер и получаю ответ в формате JSON. А как это реализоватьм непосредственно в...

Как правильно составить запрос “К серверу”?
Используется - Access - 2016 - MySql 5.5 x 64 - Odbc - mysql-connector-odbc-5.3.7-winx64 При подключении Access - Odbc - MySql...

Как правильно написать SELECT запрос?
Имеется таблица ID recipe_index recipe_ingrid --- ------------ ------------- 1 1 1 ...

5
1263 / 977 / 384
Регистрация: 02.09.2012
Сообщений: 3,021
04.09.2016, 02:25
похоже что sockets пустой при первом вхождении в цикл, получается у вас все три fd_set пустые, а это EINVAL.
0
 Аватар для NRX
22 / 19 / 9
Регистрация: 22.09.2015
Сообщений: 161
04.09.2016, 12:35  [ТС]
grgdvo, Если я уберу таймаут (NULL) то все работает. Или если я поставлю таймаут на 10 секунд и успею запустить клиент, то тоже все работает, по прошествии указанного времени, сервер опять не принимает соединение. В интернете нашел, что это "возможно" баг winsock (из-за не лицензионной ОС)) и фикс к нему. Вот тут Но это меня не устраивает. Обхожу эту проблему с помощью std::thread.

Цитата Сообщение от grgdvo Посмотреть сообщение
похоже что sockets пустой при первом вхождении в цикл
перед вход в цикл у меня прописано это
C++
1
2
FD_ZERO(&mainSocket);
    FD_SET(s, &mainSocket);
Да sockets пустой, но вопрос был про проверку подключения
int isConnect = select(0, &mainSocket, 0, 0, &contime);
mainSocket не может быть пустой, или я не прав?
Может быть такое, что из-за того что sockets пустой при проверке множества mainSocket тоже вылезает ошибка (Да не, бред какой-то)

Проверку я на подключенных пользователей поставил и ни чего не изменилось.
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
05.09.2016, 15:15
Лучший ответ Сообщение было отмечено NRX как решение

Решение

Зачем делать два FD_SET в контексте одного потока?
В двух словах. Заводим контейнер для клиентских подключений, кидаем в fd_set сокет-аксептор и вызываем select. select вернул управление, если больше нуля, то проверяем FD_ISSET для аксептора, в случае успеха делаем accept и полученный сокет добавляем в контейнер, после проверяем, остались ли ещё необработанные сокеты (результат select - это кол-во сокетов готовых к работе, и при каждом удачном FD_ISSET уменьшаем его), если да, то пробегаем по контейнеру клиентов проверяя каждый FD_ISSET.

Добавлено через 1 час 5 минут
грубый примерчик
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
107
108
#ifndef _TCPSERVER_H
#define _TCPSERVER_H
 
#include <WinSock2.h>
#include <list>
#include <memory>
 
#pragma comment(lib, "Ws2_32.lib")
 
class TcpServer
{
    typedef std::list<SOCKET > clients_t;
public:
    TcpServer()
    {
        WSADATA wsaData;
 
        if (WSAStartup(WINSOCK_VERSION, &wsaData)) {
            throw std::runtime_error("winsock not bi initialized !");
        }
    }
    ~TcpServer()
    {
        if (INVALID_SOCKET != _acceptor)
            closesocket(_acceptor);
        WSACleanup();
    }
 
    void Init(int port)
    {
        _acceptor = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (INVALID_SOCKET == _acceptor) {
            throw std::runtime_error("create socket is failed!");
        }
 
        sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
 
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 
        if (bind(_acceptor, (const sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
            throw std::runtime_error("socket bind is failed!");
        }
    }
 
    void Run(int backlog = SOMAXCONN)
    {
        if (listen(_acceptor, backlog) == SOCKET_ERROR) {
            throw std::runtime_error("socket listen is failed!");
        }
 
        const size_t max_len = 1024;
        auto buf = std::make_unique<char[]>(max_len);
 
        fd_set set;
        sockaddr_in addr;
        int addr_len = sizeof(addr);
        memset(&addr, 0, addr_len);
        
        for (;;) {
            FD_ZERO(&set);
            FD_SET(_acceptor, &set);
            for (const auto& s : _clients)
                FD_SET(s, &set);
            auto count = select(0, &set, NULL, NULL, NULL);
            if (count) {
                if (FD_ISSET(_acceptor, &set)) {
                    --count;
                    SOCKET new_s = accept(_acceptor, (sockaddr*)&addr, &addr_len);
                    if (INVALID_SOCKET != new_s) {
                        _clients.push_back(new_s);
                    }
                    else {
                        // ошибка
                    }
                }
                auto it = _clients.begin();
                while (it != _clients.end() && count)
                    if (FD_ISSET(*it, &set)) {
                        --count;
                        // читаем данные
                        auto res = recv(*it, buf.get(), max_len - 1, 0);
                        if (SOCKET_ERROR == res) {
                            _clients.erase(it++);
                        }
                        if (0 == res) {
                            _clients.erase(it++);
                        }
                        if (0 < res) {
                            // ОК! работаем
                            ++it; // не забываем инкримировать
                        }
                }
            }
            else {
                // ошибка
            }
        }
    }
 
private:
    SOCKET _acceptor{ INVALID_SOCKET };
    clients_t _clients;
};
 
#endif  /*_TCPSERVER_H*/
1
 Аватар для NRX
22 / 19 / 9
Регистрация: 22.09.2015
Сообщений: 161
05.09.2016, 19:47  [ТС]
Operok, спасибо за код, только есть ошибка, к сожалению нету времени разбираться. Сервер уходит в бесконечный цикл на 80 строчке когда подключается второй клиент. Появится время обязательно посижу подумаю, как исправить.
1
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
05.09.2016, 21:13
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (FD_ISSET(*it, &set)) {
    --count;
    auto res = recv(*it, buf.get(), max_len - 1, 0);
    if (SOCKET_ERROR == res) {
        _clients.erase(it++);
    }
    if (0 == res) {
        _clients.erase(it++);
    }
    if (0 < res) {
        // ОК! работаем
         ++it; // не забываем инкремировать
    }
}
else {
    ++it; //это забыл
}
нужно немного изменить логику удаления сокета из контейнера, чтобы не городить инкременты в каждом ответвлении
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
05.09.2016, 21:13
Помогаю со студенческими работами здесь

Как правильно составить запрос select
Есть запрос : SELECT contracts.name, registrators.name AS registrator, contracts.contr_number, contracts.pay_date,...

Как правильно выполнить запрос Insert.Into.Select.From.Where
Доброго утра всем, пытаюсь записать данные с лэйбла в последнюю строку БД, но выдает ошибку в данном методе. Dim Com = New...

Ошибка подключения к серверу: Конечный компьютер отверг запрос на подключение
Ку. В общем, столкнулся с таковой проблемой: Запускаю на локалке сервер, например сервер SA:MP'а и коннекчусь к нему следующим кодом: ...

Правильно составить запрос к веб-серверу
Подскажите, как правильно составить запрос к веб-серверу, если сервер ожидает получение запроса вот с такими данными: GET...

Не правильно работает sql select запрос
Мой запрос выводит всего 1 поле, а их несколько. Тот же запрос в phpmyadmin выдает правильную информацию. $connect =...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru