UDP 通信不工作。使用 WinSock2 库

UDP communication is not working. Using the WinSock2 library

我写了两个简单的程序,都使用UDP。其中一个发送数据包,另一个接收数据包。

我运行这两个程序都在以下情况下:

我在使用本地主机时对其进行了测试,运行 这两个程序在同一台计算机上。但是没用。

发送程序:

#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 键。

我也很欣赏此类程序的示例。

在发件人上,您根本没有对 sendto() 进行任何错误处理。

在接收器上,您的读取循环在每次调用 recvfrom() 时都没有正确设置 fromlen,这可能会使 recvfrom() 失败并出现 WSAEFAULT 错误,您没有处理或报告。如果 recvfrom() 失败,您将陷入无限循环。此外,您的 std::cout 输出应该在读取循环内,仅当 recvfrom() 成功时才将数据写入控制台。此外,recvfrom() 返回 0 不是错误条件,因为与 TCP 不同,UDP 允许 0 字节消息。

试试这个:

#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;
}