Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
valeriy007
77 / 22 / 18
Регистрация: 27.10.2014
Сообщений: 420
#1

Сервер на сокетах - C++

02.10.2015, 18:10. Просмотров 794. Ответов 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
109
110
111
112
113
114
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <sstream>
#include <string>
#include <list>
 
#define MAX_BUFFER 1024
#define _WIN32_WINNT 0x501
 
#include <WinSock2.h>
#include <WS2tcpip.h>
 
#pragma comment(lib, "Ws2_32.lib")
 
using std::cerr;
using std::cout;
using std::string;
using std::endl;
using std::list;
 
int main()
{
    //getIP();
    WSADATA wsaData;
 
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
 
    if (result != 0)
    {
        cerr << "WSAStartup failed: " << result << "\n";
        return result;
    }
 
    int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
    if (listen_socket == INVALID_SOCKET)
    {
        cerr << "error at socket: " << WSAGetLastError() << "\n";
        WSACleanup();
        return 1;
    }
 
    SOCKADDR_IN server;
    server.sin_family = AF_INET;
    server.sin_port = htons(5000);
    server.sin_addr.S_un.S_addr = INADDR_ANY;
 
    result = bind(listen_socket, (SOCKADDR*)&server, sizeof(server));
 
    if (result == SOCKET_ERROR)
    {
        cerr << "bind failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR)
    {
        cerr << "listen failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    char buf[MAX_BUFFER];
    list<int> client_list;
    int client_socket = INVALID_SOCKET;
 
    while (1)
    {
        client_socket = accept(listen_socket, NULL, NULL);                //1
        if (client_socket == INVALID_SOCKET)
        {
            cerr << "accept failed: " << WSAGetLastError() << "\n";
            closesocket(listen_socket);
            WSACleanup();
            return 1;
        }       
 
        result = recv(client_socket, buf, MAX_BUFFER, 0);
 
        if (result == SOCKET_ERROR)
        {
            cerr << "recv failed: " << result << "\n";
            closesocket(client_socket);
        }
        if (result == 0)
        {
            cerr << "connecting closed...\n";
        }
        else if (result > 0)
        {
            buf[result] = '\0';
 
            cout << buf << endl;
 
            string response = "client connect!";
            result = send(client_socket, response.c_str(), response.length(), 0);
 
            if (result == SOCKET_ERROR)
            {
                cerr << "send failed: " << WSAGetLastError() << "\n";
            }
        }
        closesocket(client_socket);
    }
 
    closesocket(listen_socket);
    //freeaddrinfo(addr);
    WSACleanup();
 
    return 0;

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

http://www.cyberforum.ru/cpp-beginners/thread1234801.html

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.10.2015, 18:10
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Сервер на сокетах (C++):

Сервер на сокетах: Нельзя повторно отправить данные на сервер
Делаю сервер на сокетах. Первая отправка данных на сервер проходит успешно,...

Сервер на сокетах: невозможно повторно запустить сервер
пишу сервер на сокетах, но надо не в консоли, а на Windows Forms, значит по...

Многопоточный сервер на сокетах
Задание: Написать многопоточный сервер на сокетах.Схема работы на подобии чата:...

Клиент-сервер на сокетах
Задача стоит в написании некого подобия чата. Получение на сервер работает, но...

Многоклиентный сервер на сокетах
Нужен пример того как правильно обрабатывать клиентов и реагировать на ошибки...

5
DrOffset
7517 / 4513 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
02.10.2015, 19:29 #2
Цитата Сообщение от valeriy007 Посмотреть сообщение
Получается при второй итерации управление останавливается на строке 1
Один из вариантов - работать с сокетами в неблокирующем режиме и использовать функцию select для ожидания событий на сокетах.
Ну или можно остаться в блокирующем режиме, но клиента (recv\send) отделить в другой поток.
0
valeriy007
77 / 22 / 18
Регистрация: 27.10.2014
Сообщений: 420
03.10.2015, 00:40  [ТС] #3
Цитата Сообщение от DrOffset Посмотреть сообщение
Один из вариантов - работать с сокетами в неблокирующем режиме и использовать функцию select для ожидания событий на сокетах.
Вот попытался, только при подключении клиента спамит в консоль "connecting closed..." если убрать
if (FD_ISSET(client_socket, &fd)) то спамит об ошибке "recv failed"
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
int main()
{
    WSADATA wsaData;
 
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
 
    if (result != 0)
    {
        cerr << "WSAStartup failed: " << result << "\n";
        return result;
    }
 
    int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_socket == INVALID_SOCKET)
    {
        cerr << "error at socket: " << WSAGetLastError() << "\n";
        WSACleanup();
        return 1;
    }
 
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(listen_socket, &fd);
 
    SOCKADDR_IN server;
    server.sin_family = AF_INET;
    server.sin_port = htons(5000);
    server.sin_addr.S_un.S_addr = INADDR_ANY;
 
    result = bind(listen_socket, (SOCKADDR*)&server, sizeof(server));
 
    if (result == SOCKET_ERROR)
    {
        cerr << "bind failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR)
    {
        cerr << "listen failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    char buf[MAX_BUFFER];
    list<int> client_list;
    int client_socket = INVALID_SOCKET;
 
    struct timeval tv;
    tv.tv_sec = 10;
    while (1)
    {
        client_socket = select(listen_socket, &fd, 0, 0, &tv);
        //client_socket = accept(listen_socket, NULL, NULL);
        if (client_socket == INVALID_SOCKET)
        {
            cerr << "accept failed: " << WSAGetLastError() << "\n";
            closesocket(listen_socket);
            WSACleanup();
            return 1;
        }       
    
        if (FD_ISSET(client_socket, &fd))
            result = recv(client_socket, buf, sizeof(buf), 0);
 
        if (result == SOCKET_ERROR)
        {
            cerr << "recv failed: " << result << "\n";
            closesocket(client_socket);
        }
        if (result == 0)
        {
            cerr << "connecting closed...\n";
        }
        else if (result > 0)
        {
            buf[result] = '\0';
 
            cout << buf << endl;
 
            string response = "client connect!";
            result = send(client_socket, response.c_str(), response.length(), 0);
 
            if (result == SOCKET_ERROR)
            {
                cerr << "send failed: " << WSAGetLastError() << "\n";
            }
        }
        closesocket(client_socket);
    }
 
    closesocket(listen_socket);
    WSACleanup();
 
    return 0;
}
помогите пожалуйста
fd_set - это набор инструкций специально для select'a? я правильно понял?

Добавлено через 1 час 14 минут
Help!
0
DrOffset
7517 / 4513 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
03.10.2015, 00:51 #4
valeriy007,
1) Вновь подключенного клиента тоже нужно добавлять в FD_SET. Из-за этого условие if FD_ISSET(client_socket, &fd)) никогда не срабатывает.
2) Серверный сокет нужно в неблокирующий режим перевести
3) Событий read обрабатывать внутри if (FD_ISSET(client_socket, &fd)).
4) result некорректно выставляется (подозреваю, что спам из-за этого) обрати внимание чему равен result, если мы не зашли в if (FD_ISSET(client_socket, &fd)).
5) Не торопись.

Это навскидку. Может еще есть какие-то проблемы.
Вот тут есть примеры, думаю можно взять за основу: http://www.winsocketdotnetworkprogra...omethod5a.html
0
valeriy007
77 / 22 / 18
Регистрация: 27.10.2014
Сообщений: 420
03.10.2015, 05:02  [ТС] #5
Цитата Сообщение от DrOffset Посмотреть сообщение
1) Вновь подключенного клиента тоже нужно добавлять в FD_SET. Из-за этого условие if FD_ISSET(client_socket, &fd)) никогда не срабатывает.
C++
1
2
3
FD_SET(client_socket, &fd);
        if (FD_ISSET(client_socket, &fd))
            result = recv(client_socket, buf, sizeof(buf), 0);
Цитата Сообщение от DrOffset Посмотреть сообщение
2) Серверный сокет нужно в неблокирующий режим перевести
C++
1
2
3
4
5
u_long arg = 1;
    if (ioctlsocket(listen_socket, FIONBIO, &arg) == SOCKET_ERROR)
    {
        cerr << "nonblock failed with error: " << WSAGetLastError() << "\n";
    }
Цитата Сообщение от DrOffset Посмотреть сообщение
3) Событий read обрабатывать внутри if (FD_ISSET(client_socket, &fd)).
Это не понял. В примере был ReadSet, вы про него?
Цитата Сообщение от DrOffset Посмотреть сообщение
4) result некорректно выставляется (подозреваю, что спам из-за этого) обрати внимание чему равен result, если мы не зашли в if (FD_ISSET(client_socket, &fd)).
Добавил в начало цикла result = 0;
Цитата Сообщение от DrOffset Посмотреть сообщение
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
int main()
{
    WSADATA wsaData;
 
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0)
    {
        cerr << "WSAStartup failed: " << result << "\n";
        return result;
    }
    
    int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_socket == INVALID_SOCKET)
    {
        cerr << "error at socket: " << WSAGetLastError() << "\n";
        WSACleanup();
        return 1;
    }
 
    SOCKADDR_IN server;
    server.sin_family = AF_INET;
    server.sin_port = htons(5000);
    server.sin_addr.S_un.S_addr = INADDR_ANY;
 
    result = bind(listen_socket, (SOCKADDR*)&server, sizeof(server));
 
    if (result == SOCKET_ERROR)
    {
        cerr << "bind failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR)
    {
        cerr << "listen failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
 
    u_long arg = 1;
    if (ioctlsocket(listen_socket, FIONBIO, &arg) == SOCKET_ERROR)
    {
        cerr << "nonblock failed with error: " << WSAGetLastError() << "\n";
    }
 
    char buf[MAX_BUFFER];
    list<int> client_list;
    int client_socket = INVALID_SOCKET;
    client_list.push_back(0);
    list<int>::iterator it = client_list.begin();
 
 
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(listen_socket, &fd);
    struct timeval tv;
    tv.tv_sec = 1;
 
    while (1)
    {
        result = 0;
        client_socket = select(listen_socket, &fd, 0, 0, &tv);
        //client_socket = accept(listen_socket, NULL, NULL);
        if (client_socket == INVALID_SOCKET)
        {
            cerr << "select failed: " << WSAGetLastError() << "\n";
            closesocket(listen_socket);
            WSACleanup();
        }       
 
        FD_SET(client_socket, &fd);
        if (FD_ISSET(client_socket, &fd))
            result = recv(client_socket, buf, sizeof(buf), 0);
 
        if (result == SOCKET_ERROR)
        {
            cerr << "recv failed: " << WSAGetLastError() << "\n";
            closesocket(client_socket);
        }
        if (result == 0)
        {
            cerr << "connecting closed...\n";
        }
        else if (result > 0)
        {
            buf[result] = '\0';
 
            cout << buf << endl;
 
            string response = "client connect!";
            result = send(client_socket, response.c_str(), response.length(), 0);
 
            if (result == SOCKET_ERROR)
            {
                cerr << "send failed: " << WSAGetLastError() << "\n";
            }
        }
        closesocket(client_socket);
    }
 
    closesocket(listen_socket);
    WSACleanup();
    return 0;
}


Добавлено через 9 минут
Теперь спам идет чередуясь "select failed" и "recv failed" 10093 убрал WSACleanup(); в проверке
пошел спам 10038 closesocket(client_socket); убрал его и он прошел
тут я понял что это нерешение, и в итоге select`ом поломал и то что было(
Помогите пожалуйста

Добавлено через 27 секунд
Теперь спам идет чередуясь "select failed" и "recv failed" 10093 убрал WSACleanup(); в проверке
пошел спам 10038 closesocket(client_socket); убрал его и он прошел
тут я понял что это нерешение, и в итоге select`ом поломал и то что было(
Помогите пожалуйста
0
DrOffset
7517 / 4513 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
03.10.2015, 15:08 #6
Цитата Сообщение от valeriy007 Посмотреть сообщение
select`ом поломал и то что было
select - это не замена accept. Соверщенно зря ты его из кода убрал.
Значение, которое возвращает select - это не сокет, а количество дескрипторов, на которых произошло событие, либо индикатор ошибки.
Тебе надо в fd_set поместить серверный сокет, а также затем всех клиентов, которые подключаются. Селект будет ожидать на них событий. Для серверного сокета событие read будет означать, что подключается новый клиент, и как реакция на это нужно вызывать accept. Для клиентского сокета событие read будет означать, что пришли новые данные и нужно вызвать recv.
Инициализировать fd_set нужно внутри цикла. Туда должны попасть серверный сокет, и все подключенные клиенты. Проще всего это контролировать через твой clients_list. Если клиент подлючился, то добавлять его в этот list. Если отключился, то удалять из него. А fd_set заполнять на каждой итерации из списка подключенных клиентов.
Еще твой код лучше разбить на функции, которые бы выполняли какую-то часть работы (например заполнение fd_set, вызовы closesocket всем клиентам в конце работы, ожидание, чтение и т.п.), т.к. он постепенно превращается в месиво.

Добавлено через 25 минут
valeriy007,
Вот набросал тебе пример на основе твоего. Шапка исходника (includes и т.п.) д.б. такая же как у тебя.
Писал прямо в браузере, поэтому могут быть неточности. Но основную идею я отразил.
Кликните здесь для просмотра всего текста
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
void fillFdSet(fd_set * fdSet, std::list<SOCKET> const & clients)
{
    for(list<SOCKET>::const_iterator i = clients.begin(); i != clients.end(); ++i)
    {
        FD_SET(*i, fdSet);
    }
}
 
void readEvent(fd_set * fdSet, std::list<SOCKET> & clients)
{
    char buf[MAX_BUFFER];
    for(list<SOCKET>::iterator i = clients.begin(); i != clients.end(); )
    {
        int curFd = *i;
        if(FD_ISSET(curFd, fdSet))
        {
            int res = recv(curFd, buf, sizeof(buf), 0);
            if(res == 0 || res == SOCKET_ERROR)
            {
                closesocket(curFd);
                clients.erase(i++);
                continue;
            }
            else if(res > 0)
            {
                buf[res] = 0;
                cout << buf << endl;
 
                string response = "client connect!";
                res = send(curFd, response.c_str(), response.length(), 0);
 
                if(res == SOCKET_ERROR)
                {
                    closesocket(curFd);
                    clients.erase(i++);
                    continue;
                }
            }
        }
        ++i;
    }
}
 
void closeAll(std::list<SOCKET> & clients)
{
    for(list<SOCKET>::const_iterator i = clients.begin(); i != clients.end(); ++i)
    {
        closesocket(*i);
    }
    clients.clear();
}
 
int main()
{
    WSADATA wsaData;
 
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
 
    if(result != 0)
    {
        cerr << "WSAStartup failed: " << result << "\n";
        return result;
    }
    SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(listen_socket == INVALID_SOCKET)
    {
        cerr << "error at socket: " << WSAGetLastError() << "\n";
        WSACleanup();
        return 1;
    }
    SOCKADDR_IN server;
    server.sin_family = AF_INET;
    server.sin_port   = htons(5000);
    server.sin_addr.S_un.S_addr = INADDR_ANY;
 
    result = bind(listen_socket, (SOCKADDR*)&server, sizeof(server));
    if(result == SOCKET_ERROR)
    {
        cerr << "bind failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
    if(listen(listen_socket, SOMAXCONN) == SOCKET_ERROR)
    {
        cerr << "listen failed with error: " << WSAGetLastError() << "\n";
        closesocket(listen_socket);
        WSACleanup();
        return 1;
    }
    list<SOCKET> client_list;
 
    bool isExit = false;
    while(!isExit)
    {
        fd_set fdr;
        FD_ZERO(&fdr);
        FD_SET(listen_socket, &fdr);
        fillFdSet(&fdr, client_list);
 
        struct timeval tv = {};
        tv.tv_sec = 10;
 
        int status = select(0, &fdr, 0, 0, &tv);
        if(status > 0)
        {
            if(FD_ISSET(listen_socket, &fdr))
            {
                SOCKET client_socket = accept(listen_socket, NULL, NULL);                //1
                if(client_socket != INVALID_SOCKET)
                {
                    client_list.push_back(client_socket);
                    cout << "Client connected\n";
                }
            }
            readEvent(&fdr, client_list);
        }
        else if(status == SOCKET_ERROR)
        {
            cerr << "failed: " << WSAGetLastError() << "\n";
            isExit = true;
        }
        else
        {
            cout << "Timeout!\n";
        }
    }
    closeAll(client_list);
    closesocket(listen_socket);
 
    WSACleanup();
}
0
03.10.2015, 15:08
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.10.2015, 15:08
Привет! Вот еще темы с решениями:

FTP сервер на сокетах
Есть необходимость портировать ftp сервер на осрв с сокетами. В данном случае...

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

Сервер на сокетах TCP
Здравствуйте.Пробую по примеру сделать простенький чат на TCP. В клиенте...

Асинхронный сервер на UDP-сокетах
Хай. Я как-то писал асинх. сервер с использованием TCP-протокола и все...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru