Мне нужно реализовать UDP-клиент с DGRM-сокетами, при этом изменяя только части между /***TO BE DONE START***/
и /***TO BE DONE END***/
, для реализации ping.
Нам дали адрес сервера и порт для тестирования наших программ - и адрес, и порт были одинаковыми для реализации TCP (уже сделано и работает правильно), но мы могли проверить его на других портах, какЧто ж.
Вот как должен выглядеть пример вывода:
UDP Ping trying to connect to server webdev.dibris.unige.it (130.251.61.30) on TCP port 1491
… connected to Pong server: asking for 501 repetitions of 16 _bytes UDP messages
Request = UDP 16 501
… Pong server agreed to ping-pong using port 62831 :-)
… about to connect socket 3 to IP address 130.251.61.30, port 62831
… sending message 1
Round trip time was 38.232 milliseconds in repetition 1
… sending message 2
и т. Д. До повторения 501.
Однако вот как выглядит мой вывод (яукажите в комментариях недостающие части):
UDP Ping trying to connect to server webdev.dibris.unige.it (130.251.61.30) on TCP port 1491
… connected to Pong server: asking for 601 repetitions of 16 _bytes UDP messages
… Pong server agreed to ping-pong using port 62831 :-)
… sending message 1
и затем он останавливается, не давая никаких предупреждений или ошибок, и при этом не хватает "Request = UDP 16 501", "… about to connect socket 3 to IP address 130.251.61.30, port 62831"
и, самое главное, каждого повторения.
Мои лучшиепредположение, что в отправляющей части моей реализации есть ошибка;однако я не смог его идентифицировать.
Вот полный код:
/*
#include "pingpong.h"
/*
* This function sends and wait for a reply on a socket.
* char message[]: message to send
* int messagesize: message length
*/
double do_ping(size_t msg_size, int msg_no, char message[msg_size], int ping_socket, double timeout)
{
int lost_count = 0;
char answer_buffer[msg_size];
ssize_t recv_bytes, sent_bytes;
struct timespec send_time, recv_time;
double roundtrip_time_ms;
int re_try = 0;
/*** write msg_no at the beginning of the message buffer ***/
/*** TO BE DONE START ***/
sprintf(message, "%d\n", msg_no);
/*** TO BE DONE END ***/
do {
debug(" ... sending message %d\n", msg_no);
/*** Store the current time in send_time ***/
/*** TO BE DONE START ***/
if(clock_gettime(CLOCK_REALTIME, &send_time)!=0) fail_errno("clock_gettime");
/*** TO BE DONE END ***/
/*** Send the message through the socket ***/
/*** TO BE DONE START ***/
sent_bytes = send(ping_socket, message, msg_size, 0);
if(sent_bytes!=msg_size) fail_errno("send");
/*** TO BE DONE END ***/
/*** Receive answer through the socket (non blocking mode) ***/
/*** TO BE DONE START ***/
for (int offset = 0; (offset + (recv_bytes = recv(ping_socket, answer_buffer + offset, sent_bytes - offset, MSG_WAITALL))) < msg_size; offset += recv_bytes) {
debug(" ... received %zd bytes back\n", recv_bytes);
if (recv_bytes < 0)
fail_errno("Error receiving data");
}
/*** TO BE DONE END ***/
/*** Store the current time in recv_time ***/
/*** TO BE DONE START ***/
if(clock_gettime(CLOCK_REALTIME, &send_time)!=0) fail_errno("clock_gettime");
/*** TO BE DONE END ***/
roundtrip_time_ms = timespec_delta2milliseconds(&recv_time, &send_time);
for (;
recv_bytes < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)
&& roundtrip_time_ms < timeout;) {
recv_bytes = recv(ping_socket, answer_buffer, sizeof(answer_buffer), 0);
clock_gettime(CLOCK_TYPE, &recv_time);
roundtrip_time_ms = timespec_delta2milliseconds(&recv_time, &send_time);
}
if (recv_bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
fail_errno("UDP ping could not recv from UDP socket");
if (recv_bytes < sent_bytes) { /*time-out elapsed: packet was lost */
lost_count++;
if (recv_bytes < 0)
recv_bytes = 0;
printf("\n ... received %zd bytes instead of %zd (lost count = %d); re-trying ...\n", recv_bytes, sent_bytes, lost_count);
if (++re_try > MAXUDPRESEND) {
printf(" ... giving-up!\n");
fail("too many lost datagrams");
}
printf(" ... re-trying ...\n");
}
} while (sent_bytes != recv_bytes);
return roundtrip_time_ms;
}
int prepare_udp_socket(char *pong_addr, char *pong_port)
{
struct addrinfo gai_hints, *pong_addrinfo = NULL;
int ping_socket;
int gai_rv;
/*** Specify the UDP sockets' options ***/
memset(&gai_hints, 0, sizeof gai_hints);
/*** TO BE DONE START ***/
gai_hints.ai_family = AF_INET;
gai_hints.ai_socktype = SOCK_DGRAM;
gai_hints.ai_protocol = 17;
/*** TO BE DONE END ***/
if ((ping_socket = socket(gai_hints.ai_family, gai_hints.ai_socktype, gai_hints.ai_protocol)) == -1)
fail_errno("UDP Ping could not get socket");
/*** change socket behavior to NONBLOCKING ***/
/*** TO BE DONE START ***/
if(fcntl(ping_socket, F_SETFD, O_RDWR|O_NONBLOCK)!=0) fail_errno("fcntl");
/*** TO BE DONE END ***/
/*** call getaddrinfo() in order to get Pong Server address in binary form ***/
/*** TO BE DONE START ***/
gai_rv = getaddrinfo(pong_addr, pong_port, &gai_hints, &pong_addrinfo);
if(gai_rv<0) fail_errno("getaddrinfo");
/*** TO BE DONE END ***/
#ifdef DEBUG
{
char ipv4str[INET_ADDRSTRLEN];
const char * const cp = inet_ntop(AF_INET, &(((struct sockaddr_in *)(pong_addrinfo-> ai_addr))->sin_addr), ipv4str, INET_ADDRSTRLEN);
if (cp == NULL)
printf(" ... inet_ntop() error!\n");
else
printf(" ... about to connect socket %d to IP address %s, port %hu\n",
ping_socket, cp, ntohs(((struct sockaddr_in *)(pong_addrinfo->ai_addr))->sin_port));
}
#endif
/*** connect the ping_socket UDP socket with the server ***/
/*** TO BE DONE START ***/
struct sockaddr_in *ipv4;
ipv4 = (struct sockaddr_in *)pong_addrinfo->ai_addr;
if(connect(ping_socket, (struct sockaddr *) ipv4, sizeof(*ipv4))<0) fail_errno("connect");
/*** TO BE DONE END ***/
freeaddrinfo(pong_addrinfo);
return ping_socket;
}
int main(int argc, char *argv[])
{
struct addrinfo gai_hints, *server_addrinfo;
int ping_socket, ask_socket;;
int msg_size, norep;
int gai_rv;
char ipstr[INET_ADDRSTRLEN];
struct sockaddr_in *ipv4;
char request[40], answer[10];
ssize_t nr;
int pong_port;
if (argc < 4)
fail("Incorrect parameters provided. Use: udp_ping PONG_ADDR PONG_PORT MESSAGE_SIZE [NO_REPEAT]\n");
for (nr = 4, norep = REPEATS; nr < argc; nr++)
if (*argv[nr] >= '1' && *argv[nr] <= '9')
sscanf(argv[nr], "%d", &norep);
if (norep < MINREPEATS)
norep = MINREPEATS;
else if (norep > MAXREPEATS)
norep = MAXREPEATS;
if (sscanf(argv[3], "%d", &msg_size) != 1 || msg_size < MINSIZE || msg_size > MAXUDPSIZE)
fail("Wrong message size");
/*** Specify TCP socket options ***/
memset(&gai_hints, 0, sizeof gai_hints);
/*** TO BE DONE START ***/
gai_hints.ai_family = AF_INET;
gai_hints.ai_socktype = SOCK_STREAM;
/*** TO BE DONE END ***/
/*** call getaddrinfo() in order to get Pong Server address in binary form ***/
/*** TO BE DONE START ***/
if(getaddrinfo(argv[1], argv[2], &gai_hints, &server_addrinfo)!=0) fail_errno("getaddrinfo");
/*** TO BE DONE END ***/
/*** Print address of the Pong server before trying to connect ***/
ipv4 = (struct sockaddr_in *)server_addrinfo->ai_addr;
printf("UDP Ping trying to connect to server %s (%s) on TCP port %s\n", argv[1], inet_ntop(AF_INET, &ipv4->sin_addr, ipstr, INET_ADDRSTRLEN), argv[2]);
/*** create a new TCP socket and connect it with the server ***/
/*** TO BE DONE START ***/
ask_socket = socket(AF_INET, SOCK_STREAM, 0);
if(ask_socket<0) fail_errno("socket");
if(connect(ask_socket, (struct sockaddr *) ipv4, sizeof(*ipv4))<0) fail_errno("connect");
/*** TO BE DONE END ***/
freeaddrinfo(server_addrinfo);
printf(" ... connected to Pong server: asking for %d repetitions of %d _bytes UDP messages\n", norep, msg_size);
sprintf(request, "UDP %d %d\n", msg_size, norep);
/*** Write the request on the TCP socket ***/
/** TO BE DONE START ***/
if(write(ask_socket, request, strlen(request))<0) fail_errno("write");
/*** TO BE DONE END ***/
nr = read(ask_socket, answer, sizeof(answer));
if (nr < 0)
fail_errno("UDP Ping could not receive answer from Pong server");
if (nr==sizeof(answer))
--nr;
answer[nr] = 0;
/*** Check if the answer is OK, and fail if it is not ***/
/*** TO BE DONE START ***/
if(strncmp(answer, "OK ", 3)!=0) fail_errno("No answer from Pong :-(");
/*** TO BE DONE END ***/
/*** else ***/
sscanf(answer + 3, "%d\n", &pong_port);
printf(" ... Pong server agreed to ping-pong using port %d :-)\n", pong_port);
sprintf(answer, "%d", pong_port);
shutdown(ask_socket, SHUT_RDWR);
close(ask_socket);
ping_socket = prepare_udp_socket(argv[1], answer);
{
char message[msg_size];
memset(&message, 0, (size_t)msg_size);
double ping_times[norep];
struct timespec zero, resolution;
int repeat;
for (repeat = 0; repeat < norep; repeat++) {
ping_times[repeat] = do_ping((size_t)msg_size, repeat + 1, message, ping_socket, UDP_TIMEOUT);
printf("Round trip time was %6.3lf milliseconds in repetition %d\n", ping_times[repeat], repeat + 1);
}
memset((void *)(&zero), 0, sizeof(struct timespec));
if (clock_getres(CLOCK_TYPE, &resolution) != 0)
fail_errno("UDP Ping could not get timer resolution");
print_statistics(stdout, "UDP Ping: ", norep, ping_times, msg_size, timespec_delta2milliseconds(&resolution, &zero));
}
close(ping_socket);
exit(EXIT_SUCCESS);
}