客户端无法使用 udp 连接向服务器发送请求

Client failing to send request to server with udp connection

我正在使用 winsock 和 c++ 将客户端和服务器编程为 return NTP 时间和框时间的偏移量。我调试时的问题是客户端无法将请求发送到服务器。失败的具体功能是我的 NtpClientThread.cpp 中的 sendto 功能这是我的服务器:

#pragma once
#include <iostream>
#include "NtpServer.h"
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winsock.h>
#include <errno.h>


using std::chrono::system_clock;

namespace ntp
{


struct sockaddr_in server;
struct sockaddr_storage client;



//constructor to create ntp server
NtpServer::NtpServer(u_short portnum, const std::chrono::nanoseconds desiredOffset) : portnum(0), client_length(0), bytes_received(0), current_time(0), desiredOffset(0)
{

    WSADATA wsaData;

    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if (iResult != 0)
    {
        throw std::runtime_error("Could not start windows connections."); 

    }

    memset((void *)&server, '[=10=]', sizeof(struct sockaddr_in));
    server.sin_family = AF_INET;
    server.sin_port = htons(portnum);
    server.sin_addr.s_addr = htonl(INADDR_ANY);


    sd = WSASocket(AF_INET, SOCK_DGRAM, 17, NULL, 0, NULL);

    if (sd == INVALID_SOCKET)
    {
        throw std::runtime_error("Could not create socket."); 
        WSACleanup();

    }



if (bind(sd, reinterpret_cast<SOCKADDR *>(&server),
        sizeof(server)) == -1)
    {
        throw std::runtime_error("Could not bind name to socket.");
        closesocket(sd);
        WSACleanup();

    }




}

NtpServer::~NtpServer()
{
    closesocket(sd);
    WSACleanup();

}   

void NtpServer::getResult()
{
    ntp_data ntpData = ntp_data();

    //set up timeout with blocking
    fd_set fds;
    int n;
    struct timeval tv;
    FD_ZERO(&fds);
    FD_SET(sd, &fds);
    tv.tv_sec = 10;  // 10 Secs Timeout 
    tv.tv_usec = 0;
    n = select(sd, &fds, NULL, NULL, &tv);
    if (n == 0)
    {
        exit(0);
    }

    while (1)
    {
        //client_length = sizeof(client); 
        int len = (int)sizeof(struct sockaddr_in);

        /* Receive bytes from client */
        bytes_received = recvfrom(sd, sendBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &len);

        if (bytes_received == SOCKET_ERROR)
        {
            throw std::runtime_error("Could not receive datagram."); 
            closesocket(sd);
            WSACleanup();

        }
        if (bytes_received < NTP_PACKET_MIN)
        {
            continue; 
        }



        /* Check for time request */
        if (strcmp(readBuffer, "GET TIME\r\n") == 0)
        {
            /* Get current time */
            system_clock::time_point now = std::chrono::system_clock::now();
            auto timepointoffset = (now + desiredOffset).time_since_epoch();
            double current_value = std::chrono::duration_cast<std::chrono::duration<double>>(timepointoffset).count();

            unpack_ntp(&ntpData, (unsigned char *)readBuffer, bytes_received);
            make_packet(&ntpData, NTP_CLIENT, current_value);
            pack_ntp((unsigned char *)sendBuffer, NTP_PACKET_MIN, &ntpData);


            /* Send data back */
            if (sendto(sd, sendBuffer,
                (int)sizeof(sendBuffer), 0,
                (struct sockaddr *)&client, client_length) !=
                SOCKET_ERROR)
            {
                throw std::runtime_error("Error sending datagram."); 
                closesocket(sd);
                WSACleanup();

            }
        }
    }
    closesocket(sd);
    WSACleanup();

}



}

这是我的客户端代码:

NTPClientThread::NTPClientThread(Config config) : stopRequested(false), currentOffset((nanoseconds)0), time_point(NULL) {

    WORD wVersionRequested;
    wVersionRequested = MAKEWORD(2, 2);
    WSADATA wsaData;
    //INT hp;



    try
    {
        if (WSAStartup(wVersionRequested, &wsaData) != 0)
        { 
            throw std::runtime_error("Could not open Windows connection."); 
        }

        /* Open a datagram socket */
        sd = WSASocket(AF_INET, SOCK_DGRAM, 17, NULL, 0, NULL);
        if (sd == INVALID_SOCKET)
        {

            WSACleanup();
            throw std::runtime_error("Failed to create socket.");
        }

        /* Clear out server struct */
        memset((void *)&server, '[=11=]', sizeof(struct sockaddr_in));


        /* Set family and port */
        server.sin_family = AF_INET;
        inet_pton(AF_INET, config.getValue("NtpHost").c_str(), &(server.sin_addr));
        server.sin_port = htons(boost::lexical_cast<u_short>(config.getValue("NtpPort")));


        //clear out client struct
        memset((void *)&client, '[=11=]', sizeof(struct sockaddr_in));

        /* Set family and port */
        client.sin_family = AF_INET;
        //inet_pton(AF_INET, config.getValue("NtpHost").c_str(), &(client.sin_addr));
        client.sin_addr.s_addr = htonl(INADDR_ANY); 
        client.sin_port = htons(0); 



        if (bind(sd, reinterpret_cast<SOCKADDR *>(&client)/*result->ai_addr*/,/* result->ai_addrlen*/sizeof(client)) == -1)
        {
            closesocket(sd); 
            WSACleanup();
            throw std::runtime_error("Failed to bind socket."); 

        }
         ntp_data ntpData = ntp_data();
        make_packet(&ntpData, NTP_CLIENT, 0);
        pack_ntp((unsigned char *)sendBuffer, NTP_PACKET_MIN, &ntpData);


        /* Tranmsit data to get time */
        server_length = sizeof(struct sockaddr_in);
        if (sendto(sd, (const char *)sendBuffer, sizeof(sendBuffer), 0, (struct sockaddr *)&server/*result->ai_addr*/, server_length/*result->ai_addrlen*/) == -1)
        {
            throw std::runtime_error("Failed to send request to server."); 

        }

        int bytes_received = recvfrom(sd, (char *)&current_time, (int)sizeof(current_time), 0, (struct sockaddr *)&server, &server_length);
        /* Receive time */
        if (bytes_received < 0)
        {
            throw std::runtime_error("Failed to recieve data from server.");

        }
        if (bytes_received < NTP_PACKET_MIN)
        {
            throw std::runtime_error("Received bad responde from server.");
        }



        unpack_ntp(&ntpData, current_time, server_length);




        typedef duration<double, std::ratio<1>>d_seconds;
        d_seconds since_epoch_full(ntpData.transmit);
        auto since_epoch = duration_cast<system_clock::duration> (since_epoch_full);

        system_clock::time_point ntpTime(since_epoch);
        system_clock::time_point boxTime = system_clock::now();

        currentOffset = ntpTime - boxTime;

    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

看看inet_pton documentationinet_pton 将表示 IP 地址的字符串转换为二进制 IP 地址。它不解析名称,因此它不适用于必须解析的主机名,例如 localhost

您应该使用特定函数来解析名称,例如 getaddrinfo(推荐)或 gethostbyname(已废弃)。