Проблема с accept() сокеты С++

142
26 февраля 2018, 01:59

main

...
CreateListenSocket();
Accept();
...

server.cpp

...
void MCServer::CreateListenSocket() {
    // Create a socket and bound it as listening socket
    _ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (_ListenSocket == INVALID_SOCKET) {
        cerr << "Can't create a socket!\tError >> " << WSAGetLastError() << endl;
    }
    // Bind the ip address and port to a socket
    sockaddr_in hint = { 0 };
    hint.sin_family = AF_INET;
    hint.sin_port = htons(_port);
    hint.sin_addr.S_un.S_addr = INADDR_ANY;
    bind(_ListenSocket, (sockaddr*)&hint, sizeof(hint));
    // Tell Winsock the socket is for listening 
    listen(_ListenSocket, SOMAXCONN);
    cout << "Listen socket ready\t\tsocket: " << _ListenSocket << endl;
}
...
void MCServer::Accept() {
    _Client = accept(_ListenSocket, 0, 0);       //<<<<<<<<<< PROBLEM
}
...

server.h

class MCServer {
...
private:
    int                     _port;
    char*                   _buf;
    int                     _size = 4096;
    SOCKET                  _ListenSocket;
    SOCKET                  _Client;
    fstream                 _file;
    string                  _time;
    string                  _skt;
...

При запуске сервера _Client получает верное значение. 128 или 126 или 132 например. Дойдя до

_Client = accept(_ListenSocket, 0, 0);

честно ждет входящего соединения. Когда клиент стучится - срабатывает. Затем, когда работа с этим клиентом завершена, сервер закрывает сокет и снова вызывает

...
CreateListenSocket();
Accept();
...

Но, дойдя во второй раз до

_Client = accept(_ListenSocket, 0, 0);

_Client присваивается космическое число... Типо 99895919816189 и accept() принимает соединение без входящего клиента, когда должен по идее ждать реальный вызов. Но клиент еще не коннектился. В чем дело?

Answer 1

Нашел ошибку и хочу поделиться. Надеюсь, поможет кому-нибудь. Дебагером нашел проблему:

Возвращает -1 функция bind(_ListenSocket, (sockaddr*)&hint, sizeof(hint));

Читая MSDN, нашел решение.Необходимо настроить эту функцию:

BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt(_ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);

теперь bind() может связывать сокеты, по которым уже передавались данные.

Но проблема не ушла. bind(), listen() и accept() работают так как надо. accept() уходит в ожидание как положено, но при новом входящем соединении не принимает его. Ничего не происходит. Нашел в итоге ошибку: Вот тут, в собственном методе:

void MCServer::Accept() {
    _Client = accept(_ListenSocket, 0, 0);       //<<<<<<<<<< PROBLEM
}

После назначения нового сокета клиенту я не закрываю "слушающий порт". И при повторном вызове метода

void MCServer::CreateListenSocket() {
    // Create a socket and bound it as listening socket
    _ListenSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (_ListenSocket == INVALID_SOCKET) {
        cerr << "Can't create a socket!\tError >> " << WSAGetLastError() << endl;
    }
    // Bind the ip address and port to a socket
    sockaddr_in hint = { 0 };
    hint.sin_family = AF_INET;
    hint.sin_port = htons(_port);
    hint.sin_addr.S_un.S_addr = INADDR_ANY;
    bind(_ListenSocket, (sockaddr*)&hint, sizeof(hint));
    // Tell Winsock the socket is for listening 
    listen(_ListenSocket, SOMAXCONN);
    cout << "Listen socket ready\t\tsocket: " << _ListenSocket << endl;
}

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

Решение - либо закрывать "слушающий порт" после каждого accept() либо не пытаться создавать его заново. Повторный вызов метода CreateListenSocket(); ошибочен.

READ ALSO
Какую базу данных лучше выбрать

Какую базу данных лучше выбрать

Мне нужно создать некий накопитель информаци к которому будет доступ разных приложений

169
Показ старых и новых данных и вектора

Показ старых и новых данных и вектора

Пытаюсь сделать следующию логику1

168
Шаблоны. Специализация

Шаблоны. Специализация

Верные ли утверждения: 1Полная специализация есть для функций и классов 2

164