C语言中的UDP客户端实现-发送数据报问题

我必须使用DGRM套接字实现UDP客户端,同时仅修改/***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,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],&msg_size) != 1 || msg_size < MINSIZE || msg_size > MAXUDPSIZE)
       fail("Wrong message size");

   /*** Specify TCP socket options ***/
   memset(&gai_hints,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],&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,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",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,&pong_port);
   printf(" ... Pong server agreed to ping-pong using port %d :-)\n",pong_port);
   sprintf(answer,pong_port);
   shutdown(ask_socket,SHUT_RDWR);
   close(ask_socket);

   ping_socket = prepare_udp_socket(argv[1],answer);

   {
       char message[msg_size];
       memset(&message,(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,UDP_TIMEOUT);
           printf("Round trip time was %6.3lf milliseconds in repetition %d\n",ping_times[repeat],repeat + 1);
       }
       memset((void *)(&zero),sizeof(struct timespec));
       if (clock_getres(CLOCK_TYPE,&resolution) != 0)
           fail_errno("UDP Ping could not get timer resolution");
       print_statistics(stdout,"UDP Ping: ",ping_times,timespec_delta2milliseconds(&resolution,&zero));

   }

   close(ping_socket);
   exit(EXIT_SUCCESS);
}
loveldj13ldj 回答:C语言中的UDP客户端实现-发送数据报问题

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/3150429.html

大家都在问