C++ TCP Server (Winsock) Соединение (неверный клиент) Мгновенно затем закрывается

Изменить: Работа над решением - оказывается, поиск в Google 204.204.204.204 дает мне больше, чем более описательные запросы.

Честно. Остроумие конец. Я понятия не имею, как я могу провести целый день, занимаясь чем-то, что заняло 10 минут во Flask (сервер) и Javascript (клиент). Мне нужно, чтобы это работало в C++ и позволяло клиенту подключаться через порт BlueStacks на той же машине. Клиент не важен, потому что я даже не могу зайти так далеко.

Я пробовал WinSocks, пробовал сетевую реализацию WxWidget, я даже пробовал какую-то случайную оболочку C++. Все они потерпели неудачу (как правило, в ПРИМЕРЕ! Как, например, копирование, вставка и ошибки везде). В итоге я вернулся к WinSockets и последовал учебному пособию на YouTube.

int ServerStuff() {
WSADATA WsData;
WORD ver = MAKEWORD(2, 2);

int wsOK = WSAStartup(ver, &WsData);
if (wsOK != 0) {
    wxLogMessage("Can't initialize Winsock! Quitting");
    return false;
}

//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
    wxLogMessage("Can't create a socket! Quitting");
    return false;
}

//Bind the ip and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; //Could also use inet_pton

bind(listening, (sockaddr*)&hint, sizeof(hint));

//Tell winsock the socket is for listening
listen(listening, SOMAXCONN);

//Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);

SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
//if (clientSocket == INVALID_SOCKET) {
//  wxLogMessage("Client Invalid Socket");
//  return false;
//}

char host[NI_MAXHOST];  //Client's remote name
char service[NI_MAXHOST]; //Service (port) the client is connected on

ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST);

if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
    wxLogMessage("Can't initialize Winsock! Quitting");
}
else {
    inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
    wxLogMessage(host);
    int wut = client.sin_port;
    wxString mystring = wxString::Format(wxT("%i"), wut);
    wxLogMessage("Connected on port");
    wxLogMessage(mystring);
    //wxLogMessage(to_string(ntohs(client.sin_port)));
}
wxLogMessage("Got this far somehow");
//Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
closesocket(listening);

//while loop: accept and echo message back to client
char buf[4096];

while (true)
{
    ZeroMemory(buf, 4096);

    //Wait for client to send data
    int bytesReceived = recv(clientSocket, buf, 4096, 0);

    if (bytesReceived == SOCKET_ERROR) {
        //wxLogMessage("ERROR in recv");
        break;
    }

    if (bytesReceived == 0) {
        wxLogMessage("Client Disconnected");
        break;
    }

    //Echo back to client
    send(clientSocket, buf, bytesReceived + 1, 0);

    //Close the socket
    closesocket(clientSocket);

    //Cleanup winsock
    WSACleanup();
    wxLogMessage("Welp");
}
}

// event handlers

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
// true is to force the frame to close

ServerStuff();
//Close(true);
}

На видео YouTube ("Создание TCP-сервера в C++" - запрещено публиковать ссылки) это работает! Окно команд открывается, остается пустым бесконечно, пока он не подключит клиента, а затем клиент отправит сообщение, и сервер ответит тем же самым точным сообщением в ответ.

Не мой. Мой просто бросается через все, а затем закрывается. Мой журнал использовался для немедленного выхода из закомментированного кода, где говорится, что клиентский сокет недействителен, поэтому я закомментировал его. Теперь мой вывод: 204.204.204.204 подключен через порт 52428

Я не знаю что делать. Я просто пытаюсь отправить данные по TCP-соединению на одной машине. Я озадачен тем, как это так сложно. Кажется, какой-то случайный процесс немедленно пытается подключиться как клиент к моему серверу? Но почему разрешено подключение к порту 52428, если я явно размещаюсь на 54000?

Моя цель: запустить сервер Подключение к серверу с помощью приложения Java в BlueStacks. Отправка данных с сервера на клиент.

Для компьютера имеет больше смысла быть сервером, потому что будет несколько экземпляров BlueStacks, и я бы предпочел не "порождать" несколько программ / серверов для того, что я делаю.

1 ответ

Решение

Я вижу несколько ошибок в вашем коде сокета.

  • не звонит WSACleanup() если WSAStartup() успешно, а потом что-то пойдет не так.

  • не звонит closesocket() если socket() успешно, а потом что-то пойдет не так.

  • не обнуляя sockaddr_in что вы передаете bind(), Случайные байты в структуре могут вызвать bind() терпеть неудачу.

  • игнорируя возвращаемые значения bind(), listen(), accept(), а также send(),

  • не лечить возвращаемое значение getnameinfo() правильно. Возвращает 0 в случае успеха, а не неудачи.

  • отправив +1 дополнительный байт обратно клиенту, чем вы получили от клиента. Если клиент отправляет меньше байтов, чем может вместить ваш буфер, этот дополнительный байт будет 0x00 из-за вашего ZeroMemory() вызов. Но если клиент фактически отправляет достаточно байтов, чтобы полностью заполнить ваш буфер, то вы бы отправили дополнительный байт из памяти, которой вы не владеете. Если вы действительно хотите отправить нулевой терминатор после всего, что вы видите, сделайте это явно. В противном случае настоящий эхо-сервер должен отправлять только то, что получает, не больше и не меньше.

Попробуйте что-то вроде этого:

void ServerStuff() {
    WSADATA WsData;
    int ret = WSAStartup(MAKEWORD(2, 2), &WsData);
    if (ret != 0) {
        wxLogMessage("Can't initialize Winsock! Error: %d", ret);
        return;
    }

    //Create a socket
    SOCKET listening = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listening == INVALID_SOCKET) {
        wxLogMessage("Can't create a socket! Error: %d", WSAGetLastError());
        WSACleanup();
        return;
    }

    //Bind the ip and port to a socket
    sockaddr_in hint = {};
    hint.sin_family = AF_INET;
    hint.sin_port = htons(54000);
    hint.sin_addr.s_addr = INADDR_ANY; //Could also use inet_pton

    ret = bind(listening, (sockaddr*)&hint, sizeof(hint));
    if (ret == SOCKET_ERROR) {
        wxLogMessage("Can't bind socket! Error: %d", WSAGetLastError());
        closesocket(listening);
        WSACleanup();
        return;
    }

    //Tell winsock the socket is for listening
    ret = listen(listening, SOMAXCONN);
    if (ret == SOCKET_ERROR) {
        wxLogMessage("Can't listen on socket! Error: %d", WSAGetLastError());
        closesocket(listening);
        WSACleanup();
        return;
    }

    //Wait for a connection
    sockaddr_in client = {};
    int clientSize = sizeof(client);

    SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
    if (clientSocket == INVALID_SOCKET) {
        wxLogMessage("Can't accept a client! Error: %d", WSAGetLastError());
        closesocket(listening);
        WSACleanup();
        return;
    }

    char host[NI_MAXHOST] = {};  //Client's remote name

    ret = getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, NULL, 0, 0);
    if (ret != 0) {
        wxLogMessage("Can't get client name info! Error: %d", ret);
        inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
    }

    wxLogMessage("Client: %s, Connected on port: %hu", host, ntohs(client.sin_port));

    //Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
    closesocket(listening);

    //while loop: accept and echo message back to client
    char buf[4096];
    int bytesReceived;

    while (true)
    {
        //Wait for client to send data
        bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);

        if (bytesReceived == SOCKET_ERROR) {
            wxLogMessage("Can't read from client! Error: ", WSAGetLastError());
            break;
        }

        if (bytesReceived == 0) {
            wxLogMessage("Client Disconnected");
            break;
        }

        //Echo back to client
        ret = send(clientSocket, buf, bytesReceived, 0);
        if (ret == SOCKET_ERROR) {
            wxLogMessage("Can't send to client! Error: ", WSAGetLastError());
            break;
        }
    }

    //Close the socket
    closesocket(clientSocket);

    //Cleanup winsock
    WSACleanup();

    wxLogMessage("Welp");
}
Другие вопросы по тегам