Я использую Winsock и C ++ для программирования клиента и сервера для возврата смещения от времени NTP и времени ящика. Моя проблема при отладке заключается в том, что клиент не может отправить запрос на сервер. Конкретная функция, которая не работает, это моя sendto
функция в моем NtpClientThread.cpp
Вот мой сервер:
#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, '\0', 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, '\0', 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, '\0', 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 *)¤t_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. inet_pton
преобразовать строку, представляющую IP-адрес, в двоичный IP-адрес. Он не разрешает имена, поэтому не будет работать с именем хоста, например localhost
, который должен быть решен.
Вы должны использовать определенную функцию для разрешения имени, например getaddrinfo
(рекомендуется) или gethostbyname
(Устарел).
Других решений пока нет …