У меня есть некоторый код, который запрашивает главные серверы Steam , чтобы получить список IP-адресов игровых серверов:
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
struct timeval timeout = {1, 0};
char master[256];
char reply[1500];
uint16_t port;
uint8_t query[] = {0x31, 0x03, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e,
0x30, 0x3a, 0x30, 0x00, 0x00};
uint8_t replyHeader[] = {0xff, 0xff, 0xff, 0xff, 0x66, 0x0a};
int gotResponse = 0;
int bytesRead = 0;
int verbosity = 0;
int main(int argc, char** argv)
{
strcpy(master, "hl2master.steampowered.com");
port = 27011;
int opt;
while ((opt = getopt(argc, argv, "s:p:v")) != -1)
{
switch (opt)
{
case 's':
strcpy(master, optarg);
break;
case 'p':
port = atoi(optarg);
break;
case 'v':
verbosity++;
break;
}
}
int sockFD;
struct sockaddr_in server;
struct hostent* hostInfo;
sockFD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockFD == -1)
{
perror("socket");
exit(EXIT_FAILURE);
}
if ((setsockopt(sockFD, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)))
!= 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
if ((setsockopt(sockFD, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)))
!= 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
server.sin_family = AF_INET;
server.sin_port = htons(port);
hostInfo = gethostbyname(master);
if (hostInfo == NULL)
{
fprintf(stderr, "Unknown host %s\n", master);
exit(EXIT_FAILURE);
}
server.sin_addr = *(struct in_addr*) hostInfo->h_addr_list[0];
while (gotResponse == 0)
{
if ((sendto(sockFD, query, 15, 0, (struct sockaddr*) &server,
sizeof(server))) == -1)
{
perror("sendto");
exit(EXIT_FAILURE);
}
socklen_t serverSize = sizeof(server);
if ((bytesRead = recvfrom(sockFD, reply, 1500, 0,
(struct sockaddr*) &server, &serverSize)) == -1)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
fprintf(stderr, "TIMEOUT\n");
}
else
{
perror("recvfrom");
exit(EXIT_FAILURE);
}
}
else
gotResponse = 1;
}
if ((close(sockFD)) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
if ((strncmp(reply, replyHeader, 6)) != 0)
{
fprintf(stderr, "Bad reply from master server\n");
exit(EXIT_FAILURE);
}
uint32_t i = 6;
while (i < bytesRead)
{
if (verbosity > 0)
fprintf(stderr, "%u <= %d\n", i, bytesRead);
uint8_t ip[4] = {reply[i], reply[i + 1], reply[i + 2], reply[i + 3]};
printf("%hu.%hu.%hu.%hu:", ip[0], ip[1], ip[2], ip[3]);
uint16_t thisPort = reply[i + 4] + (reply[i + 5] << 8);
printf("%hu\n", ntohs(thisPort));
i += 6;
}
return EXIT_SUCCESS;
}
(обратите внимание на одну секунду timeout
.)
Это нормально, если не считать странного поведения в общении. Кажется, или работают в первый раз или постоянно снова и снова, и снова, и никогда не будет успешным.
Способ исправить это просто запустить его снова, и он может работать, но я не понимаю, почему он произвольно не работает.
Любой вклад будет оценен!