UDP связь не работает. Использование библиотеки WinSock2 - PullRequest
0 голосов
/ 19 марта 2020

Я написал две простые программы, обе с использованием UDP. Один из них отправляет пакеты данных, а другой получает их.

Я запустил обе эти программы в следующих случаях:

  • Брандмауэр был отключен.
  • Я переадресовал соответствующий порт, хотя я проверял его в локальной сети.

Я тестировал его при использовании localhost, запустил обе программы на одном компьютере. Но это не работает.

Программа отправителя:

#include <iostream>

#include <WinSock2.h>
#include <WS2tcpip.h>

#pragma comment(lib, "Ws2_32.lib")

#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"

#define CYCLECOUNT 100

#define MESS "Hello world!"

int main()
{
    /// True if the socket is initialized.
    bool bSockInit = false;

    /// Initialization.
    WSADATA wsaData;
    if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
        std::cout << "Failed the startup with error: " << err << '\n';
        goto END;
    }

    /// Creating the socket.
    SOCKET sock;
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
    {
        std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
        goto END;
    }
    bSockInit = true;

    /// Creating the address, to which data is sent.
    sockaddr_in remoteAddr;
    ZeroMemory((PVOID) &remoteAddr, sizeof(remoteAddr));

    // Setting the address familiy to ipv4.
    remoteAddr.sin_family = AF_INET;

    // Setting the port in network byte order.
    remoteAddr.sin_port = htons(PORT);

    // Setting the address from a c-style string.
    InetPton(AF_INET, TEXT(IPSTR), (PVOID) &remoteAddr.sin_addr);

    /// Sending the messages.
    while (std::cin.get() == '\n')
    {
        int byteCount = 0;
        for (int i = 0; i < CYCLECOUNT; ++i)
        {
            byteCount += sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
        }

        /// Print the number of bytes sent.
        std::cout << "Sent " << byteCount << " bytes times to " IPSTR ":" PORTSTR << ".";
    }

END:
    // If the socket was initialized successfully then dispose of it.
    if (bSockInit)
    {
        std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
    }

    std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';

    std::cin.get();
    return 0;
}

Программа получателя:

#include <iostream>

#include <WinSock2.h>

#pragma comment(lib, "Ws2_32.lib")

// The port where data is to be received.
#define PORT 1243

int main(int argc, char** argv)
{
    /// True if the socket is initialized.
    bool bSockInit = false;

    /// Initialization.
    WSADATA wsaData;
    if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
        std::cout << "Failed the startup with error: " << err << '\n';
        goto END;
    }

    /// Creating the socket.
    SOCKET sock;
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
    {
        std::cout << "Failed the socket with error: " << WSAGetLastError() << '\n';
        goto END;
    }
    bSockInit = true;

    /// Creating the address.
    sockaddr_in thisAddr;
    ZeroMemory((PVOID) &thisAddr, sizeof(thisAddr));

    // Setting the address familiy to ipv4.
    thisAddr.sin_family = AF_INET;

    // Setting the port in network byte order.
    thisAddr.sin_port = htons(PORT);

    // Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
    thisAddr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);

    if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
    {
        std::cout << "Failed the bind with error: " << WSAGetLastError() << '\n';
        goto END;
    }

    // Buffer to store incoming bytes.
    char buf[1024];

    // The number of bytes that were received.
    int len;

    // Data about the sender.
    sockaddr from;
    int fromlen;
    fromlen = 0;
    // ~Data about the sender.

    // Waiting for a message, containing at least one byte to arrive.
    while ((len = recvfrom(sock, buf, sizeof(buf), NULL, &from, &fromlen)) <= 0);

    // Printing the message that was just received and placed into the buffer.
    for (int i = 0; i < len; ++i)
    {
        std::cout << buf[i];
    }

END:
    // If the socket was initialized successfully then dispose of it.
    if (bSockInit)
    {
        std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';
    }

    std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';

    std::cin.get();
    return 0;
}

Если у вас есть свободное время, запустите обе программы и посмотрите, что произойдет.

Для отправки данных с помощью программы отправителя вам необходимо нажать клавишу ENTER / RETURN.

Буду также признателен за примеры таких программ, которые работают.

1 Ответ

1 голос
/ 19 марта 2020

На отправителе вы вообще не обрабатываете ошибки на sendto().

На получателе ваше чтение l oop неправильно устанавливает fromlen при каждом вызове на recvfrom(), что может привести к сбою recvfrom() с ошибкой WSAEFAULT, которую вы не обрабатываете или не сообщаете. Если recvfrom() терпит неудачу, вы застреваете в бесконечном l oop. Кроме того, ваш вывод std::cout должен быть внутри показания l oop, запись данных на консоль только тогда, когда recvfrom() успешен. Кроме того, recvfrom(), возвращающий 0, не является ошибкой, поскольку UDP допускает 0-байтовые сообщения, в отличие от TCP.

Попробуйте вместо этого:

#include <iostream>

#include <WinSock2.h>
#include <WS2tcpip.h>

#pragma comment(lib, "Ws2_32.lib")

#define PORT 1243
#define PORTSTR "1243"
#define IPSTR "127.0.0.1"

#define CYCLECOUNT 100

#define MESS "Hello world!"

int main()
{
    SOCKET sock = INVALID_SOCKET;

    /// Initialization.
    WSADATA wsaData;
    if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
        std::cerr << "Failed the startup with error: " << err << '\n';
        goto FINISHED;
    }

    /// Creating the socket.
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
    {
        std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
        goto CLEANUPWSA;
    }

    /// Creating the address, to which data is sent.
    sockaddr_in remoteAddr;
    ZeroMemory(&remoteAddr, sizeof(remoteAddr));

    // Setting the address familiy to ipv4.
    remoteAddr.sin_family = AF_INET;

    // Setting the port in network byte order.
    remoteAddr.sin_port = htons(PORT);

    // Setting the address from a c-style string.
    inet_pton(AF_INET, IPSTR, &remoteAddr.sin_addr);

    /// Sending the messages.
    while (std::cin.get() == '\n')
    {
        int byteCount = 0;
        for (int i = 0; i < CYCLECOUNT; ++i)
        {
            int sent = sendto(sock, MESS, sizeof(MESS), 0, (sockaddr*) &remoteAddr, sizeof(remoteAddr));
            if (sent == SOCKET_ERROR)
            {
                std::cerr << "Failed the send with error: " << WSAGetLastError() << '\n';
                goto CLEANUPSCKT;
            }
            byteCount += sent;
        }

        /// Print the number of bytes sent.
        std::cout << "Sent " << byteCount << " bytes to " << IPSTR << ":" << PORTSTR << ".";
    }

CLEANUPSCKT:
    // If the socket was initialized successfully then dispose of it.
    std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';

CLEANUPWSA:
    std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';

FINISHED:
    std::cin.get();
    return 0;
}
#include <iostream>

#include <WinSock2.h>

#pragma comment(lib, "Ws2_32.lib")

// The port where data is to be received.
#define PORT 1243

int main(int argc, char** argv)
{
    SOCKET sock = INVALID_SOCKET;

    /// Initialization.
    WSADATA wsaData;
    if (int err; (err = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
    {
        std::cerr << "Failed the startup with error: " << err << '\n';
        goto FINISHED;
    }

    /// Creating the socket.
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
    {
        std::cerr << "Failed the socket with error: " << WSAGetLastError() << '\n';
        goto CLEANUPWSA;
    }

    /// Creating the address.
    sockaddr_in thisAddr;
    ZeroMemory(&thisAddr, sizeof(thisAddr));

    // Setting the address familiy to ipv4.
    thisAddr.sin_family = AF_INET;

    // Setting the port in network byte order.
    thisAddr.sin_port = htons(PORT);

    // Setting the address to any, so that incoming data, whichever the ipv4-address is, is accepted.
    thisAddr.sin_addr.s_addr = htonl(ADDR_ANY);

    if (bind(sock, (sockaddr*)&thisAddr, sizeof(thisAddr)) == SOCKET_ERROR)
    {
        std::cerr << "Failed the bind with error: " << WSAGetLastError() << '\n';
        goto CLEANUPSCKT;
    }

    // Buffer to store incoming bytes.
    char buf[1024];

    // The number of bytes that were received.
    int len;

    // Data about the sender.
    sockaddr_in from;
    int fromlen;

    // Waiting for a message, containing at least one byte to arrive.    
    do
    {
        fromlen = sizeof(from);
        len = recvfrom(sock, buf, sizeof(buf), NULL, (sockaddr*)&from, &fromlen);
        if (len == SOCKET_ERROR)
        {
            std::cerr << "Failed the recv with error: " << WSAGetLastError() << '\n';
            goto CLEANUPSCKT;
        }

        std::cout << "Received " << len << " byte(s) from " << inet_ntoa(from.sin_addr.s_addr) << ":" << ntohs(from.sin_port);

        if (len > 0)
        {
            // Printing the message that was just received and placed into the buffer.
            std::cout << ": ";
            std::cout.write(buf, len);
            std::cout << '\n';
            break;
        }

        std::cout << ", still waiting" << '\n';
    }
    while (true);

CLEANUPSCKT:
    // If the socket was initialized successfully then dispose of it.
    std::cout << "closesocket finished with code: " << closesocket(sock) << '\n';

CLEANUPWSA:
    std::cout << "WSACleanup finished with code: " << WSACleanup() << '\n';

FINISHED:
    std::cin.get();
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...