C ++ winsock server функция принятия возвращает ошибку 10022 - PullRequest
0 голосов
/ 05 июня 2019

Я избавился от ошибки, теперь, похоже, застрял на чем-то другом.

У меня есть отдельные клиентские и серверные программы Winsock на Code :: Blocks. Я пытаюсь отправить сообщение от клиента на сервер, но серверная программа, кажется, зависает перед функцией accept (), не делая ничего, кроме «прослушивания входящих соединений». выход. Сообщение в буфере клиента никогда не отображается в консоли сервера.

Похоже, что что-то происходит с функцией accept в программе сервера. Это, кажется, где серверная программа зависает. После этого я попытался набрать случайную строчку, и для нее не было вывода.

Клиент, кажется, тоже зависает после "Отправленного сообщения". Но затем, через несколько минут, я получаю «recv failed», затем «Reply Received» и затем строку того, что кажется смайликами. Я думаю, что у меня есть изображение, связанное ниже.

введите описание изображения здесь

Вот мой код клиента:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main()
{

    WSADATA wsaData;
    SOCKET sock;
    sockaddr_in server;
    char *buffer, server_reply[2000];
    int recv_size;

    int iResult;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
    printf("WSAStartup failed: %d\n", iResult);
} else {
     printf("WSAStartup successful!: %d\n", iResult);
}

sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET){
    printf("Socket not created.\n");
} else {
    printf("Socket created.\n");
}

    server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons(80);

    if(connect(sock, (SOCKADDR *)&server, sizeof(server)) != 0){
        printf("Connect Error : %d" , WSAGetLastError());
    } else {
        printf("Connected\n");
    };

    buffer = "Hello there!";
    send(sock, buffer, sizeof(buffer), 0);

        printf("Message Sent.\n");


    if((recv_size = recv(sock , server_reply , 2000 , 0)) == SOCKET_ERROR)
    {
        puts("recv failed");
    }

    puts("Reply received\n");
    //Add a NULL terminating character to make it a proper string before printing
    server_reply[recv_size] = '\0';
    puts(server_reply);


    closesocket(sock);
    WSACleanup();

    return 0;
}

Вот мой код сервера:

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main()
{

    WSADATA wsaData;
    SOCKET server1, client;
    sockaddr_in serverAddr, clientAddr;


    int iResult;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
    printf("WSAStartup failed: %d\n", iResult);
} else {
     printf("WSAStartup successful!: %d\n", iResult);
}

server1 = socket(AF_INET, SOCK_STREAM, 0);
if (server1 == INVALID_SOCKET){
    printf("Socket not created.\n");
} else {
    printf("Socket created.\n");
}

    serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);

    if(bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){
        printf("Bind failed. : %d" , WSAGetLastError());
    } else {
        printf("Bind successful.\n");
    }

    if(listen(server1, SOMAXCONN) != 0){
        printf("Server not listening. : %d" , WSAGetLastError());
    } else {
        cout << "Listening for incoming connections..." << endl;
    }



    char buffer[1024];
    int clientAddrSize = sizeof(clientAddr);
    if((client = accept(server1, (SOCKADDR *)&clientAddr, &clientAddrSize)) == INVALID_SOCKET)
    {
        printf("Connect Error : %d" , WSAGetLastError());
    } else {
        cout << "Client connected!" << endl;
        recv(client, buffer, sizeof(buffer), 0);
        cout << "Client says: " << buffer << endl;
        memset(buffer, 0, sizeof(buffer));

        closesocket(client);
        closesocket(server1);
        cout << "Client disconnected." << endl;
    }
    WSACleanup();

    return 0;
}

Я пытаюсь собрать серверную программу Winsock для использования с моей клиентской программой на C ++ в CodeBlocks. Однако функция accept возвращает код ошибки 10022, который из того, что я прочитал, означает недопустимый аргумент. Я не вижу, как какой-либо из моих аргументов в функции accept недействителен Спасибо за любую помощь!

int main()
{

    WSADATA wsaData;
    SOCKET server1, client;
    sockaddr_in serverAddr, clientAddr;


    int iResult;

iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
    printf("WSAStartup failed: %d\n", iResult);
} else {
     printf("WSAStartup successful!: %d\n", iResult);
}

server1 = socket(AF_INET, SOCK_STREAM, 0);
if (server1 == INVALID_SOCKET){
    printf("Socket not created.\n");
} else {
    printf("Socket created.\n");
}

    serverAddr.sin_addr.S_un.S_addr = inet_addr(INADDR_ANY);
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);

    bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr));
    listen(server1, SOMAXCONN);

    cout << "Listening for incoming connections..." << endl;

    char *buffer;
    int clientAddrSize = sizeof(clientAddr);
    if((client = accept(server1, (SOCKADDR *)&clientAddr, &clientAddrSize)) == INVALID_SOCKET)
    {
        printf("Connect Error : %d" , WSAGetLastError());
    } else {
        cout << "Client connected!" << endl;
        recv(client, buffer, sizeof(buffer), 0);
        cout << "Client says: " << buffer << endl;
        memset(buffer, 0, sizeof(buffer));

        closesocket(client);
        closesocket(server1);
        cout << "Client disconnected." << endl;
    }
    WSACleanup();

    return 0;
}

Ответы [ 2 ]

2 голосов
/ 06 июня 2019

10022 - WSAEINVAL. Согласно документации accept():

WSAEINVAL
Функция listen не была вызвана до accept.

Коды ошибок Windows Socket Документация также гласит:

WSAEINVAL
10022

Неверный аргумент.

Указан недопустимый аргумент (например, задан недопустимый уровень для функции setsockopt). В некоторых случаях это также относится к текущему состоянию сокета - например, вызывает accept для сокета, который не прослушивает .

ОК, так что давайте посмотрим на ваш listen() звонок:

listen(server1, SOMAXCONN);

Там нет ничего необычного, если предположить, что server1 является допустимым сокетом (который вы проверяете, но не останавливаете свою программу, если socket() не удался).

Вы не проверяете наличие ошибок listen(). Согласно документации listen() одна из возможных ошибок:

WSAEINVAL
Сокет не был связан с bind.

Хорошо, давайте посмотрим на ваш bind() вызов:

bind(server1, (SOCKADDR *)&serverAddr, sizeof(serverAddr));

Опять же, вы не проверяете ошибки bind(). Согласно документации bind(), одна из возможных ошибок:

WSAEADDRNOTAVAIL
Запрошенный адрес недопустим в своем контексте.

Эта ошибка возвращается, если указанный адрес, на который указывает параметр name, не является действительным локальным IP-адресом на этом компьютере.

Что вы, скорее всего, получите, потому что вы неправильно заполняете serverAddr, особенно в этой строке:

serverAddr.sin_addr.S_un.S_addr = inet_addr(INADDR_ANY);

INADDR_ANY определяется как 0, поэтому вы устанавливаете в поле S_addr результат inet_addr(0), который недопустим, поэтому возвращается INADDR_NONE (0xFFFFFFFF), что опять же не является проверка на. Правильное назначение - использовать INADDR_ANY как есть:

serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;

Итак, в заключение, ваша обработка ошибок неадекватна, что позволяет накапливать ошибки до тех пор, пока вы, наконец, не решите делать ошибки на всем протяжении accept(), что слишком поздно. Вам необходимо проверить КАЖДЫЙ результат функции на предмет неисправности в пути и ОСТАНОВИТЬ, если вы все же обнаружите ошибку.

1 голос
/ 05 июня 2019

inet_addr принимает const char*, который представляет IPv4-адрес в цифрах и точках.Вы передаете INADDR_ANY этой функции, она компилируется, но не работает должным образом, потому что INADDR_ANY равно 0, поэтому inet_addr вызывается с нулевым указателем.Вы должны проверить код возврата этой функции, -1 указывает на ошибку.И я предполагаю, что вы его получили.

Если вы хотите связать любой локальный адрес, вы должны использовать INADDR_ANY с htonl:

serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

This

char *buffer;
recv(client, buffer, sizeof(buffer), 0);

ведет к неопределенному поведению.буфер неинициализирован.Этот вызов recv хочет прочитать 4/8 байтов - sizeof(buffer) и записать в неинициализированный указатель buffer .Вам нужно создать буфер с некоторым начальным размером, например, вызвав malloc / calloc:

char * buffer = malloc(10);
recv(client,buffer,10,0);
// free buffer after data was read
...