【问题标题】:reliable data transfer using udp in c在 c 中使用 udp 进行可靠的数据传输
【发布时间】:2020-07-22 04:22:19
【问题描述】:

我正在编写一个使用 udp 进行可靠数据传输的套接字程序。我以 1024 字节的块将图像文件从客户端发送到服务器。下面是我的代码。它们适用于大字符串和较小的图像文件。但是当我传输 2.3 MB 的图像时,服务器只能接收到 2 MB。假设发送的数据包总数为 2271。服务器将只接收到 2211 或更少,并将突然终止。我不知道原因。你能解释一下吗?并提出任何解决方案。 下面是我的客户端代码

#include<stdio.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<arpa/inet.h>

char *itoa(long i,char *s,int dummy_radix)
{
    sprintf(s,"%ld",i);
    return s;
}

int main(int argc, int *argv[])
{
    int sock,length,n;
    struct sockaddr_in server,from;
    struct hostent *hp;
    long int packets =0;
    unsigned char buff[1024] = {0};


    // checking if hostname and the port address is provided //
    if(argc!=3)
    {
        printf("insufficient arguments\n");
        exit(1);
    }

    //create a socket//
    sock = socket(AF_INET,SOCK_DGRAM,0);

    if(sock<0)
    {
        printf("error in opening socket\n");
        return 1;
    }

    //to get  the hostname of the system or the machine//
    hp= gethostbyname(argv[1]);

    if(hp==0)
    {
        printf("Unknown host\n");
        return 1;
    }
    //build the server's IP address //
    bzero((char *)&server,sizeof(server));
    bcopy((char*)hp->h_addr,(char *)&server.sin_addr,hp->h_length);
    server.sin_family = AF_INET;
    server.sin_port =  htons(atoi(argv[2]));
    length = sizeof(server);

    /*open the file that we wish to transfer*/
    FILE *fp = fopen("landscape.jpeg","rb");
    if(fp==NULL)
    {
        printf("file open error");
        return 1;
    }
    fseek(fp,0,SEEK_END); //if exists read the size of the file 
    size_t file_size = ftell(fp);
    fseek(fp,0,SEEK_SET); 

    printf("size of the file is %d\n", file_size);

    /*find the number of packets*/

    packets = (file_size/1024)+1 ;

    /*send the number of packets to the server*/

     itoa(packets,buff,10);
    n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
        if(n<0)
        {
            printf("error in sending message to the serveR");
        return 1;
    }




    /*Read data from file and send it*/
    int packetNum = 0;
    while(1)
    {
        /*First read file in chunks of  1024  bytes */

        int nread = fread(buff,1,1024,fp);
        //printf("Bytes read %d\n",nread);

        /*if read was success ,send data*/
        if(nread>0)
        {
            //printf("data sent now is %s\n",buff);
            n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
            printf("Sending %d, numBytes sent: %d\n", packetNum, n);
            packetNum++;
                    if(n<0)
                    {
                      printf("error in sending message to the server");
                  fclose(fp);
                  return 1;
            }

        }

        /*There is something tricky going on with the read..
         * Either there was error ,or we reached end of  file.
         */
        if(nread<1024)
        {
            if(feof(fp))
                printf("End of file\n");

            if(ferror(fp))
                printf("Error reading\n");
            break;
        }

    }
    close(sock);
    fclose(fp);

    return 0;
}

还有我的服务器代码:

#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<arpa/inet.h>

int main(int argc, char *argv[])
{
    int sock,length,fromlen,n;
    struct sockaddr_in server;
    struct sockaddr_in from;
    char buf[1024];
    char file_buf[1024];
    int packets = 0;
    int received = 0;
    FILE *newfp;
    newfp = fopen("output.jpeg","wb");
    if(newfp==NULL)
    {
        printf("error opening the file\n");
            return 1;
    }   
    if(argc<2)
    {
        fprintf(stderr, "no port number specified\n");

        exit(0);
    }
    sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock<0)
    {
        printf("error in opening socket\n");
        return 1;
    }
    length = sizeof(server);
    bzero(&server,length);
    server.sin_family= AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(atoi(argv[1]));
    if(bind(sock,(struct sockaddr*)&server,length)<0)
    {
        printf("cannot bind\n");
        return 1;
    }
    fromlen  =sizeof(struct sockaddr_in);
        n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
    if(n<0)
    {
            printf("recvfrom  error\n");
            return 1;
    }


    packets = atoi(buf);
    printf("Num packets expected: %d\n", packets);


    while(received<packets)
    {

        n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&from,&fromlen);    

            //printf ("%d\n", n);
        printf("Packet num %d, numBytes received: %d\n", received, n);

        if(n<0)
        {
            printf("recvfrom  error\n");
            return 1;
        }
        //printf("%s",buf);
        if((fwrite(buf,1,n,newfp)) < n)
        {
            printf("error in writing to the file\n");
            return 1;
        }
        received++;

    }
    printf("Finished\n");
    fclose(newfp);
    return 0;
}

【问题讨论】:

  • 你需要设计一个protocol放在UDP之上,增加“可靠性”。诸如序列号和接收数据包的确认之类的东西。或者可能研究基于 UDP 的现有可靠文件传输协议,看看是否可以使用其中之一。
  • 我没有看到任何代码使这个可靠?..
  • 使用 UDP 的任何具体原因?如果在这种场景下使用 TCP 会更合适。此外,当请求过多时,UDP 服务器可能会在您不知道的情况下丢弃请求。添加序列号,确认等已经在 TCP 中处理
  • @NipunTalukdar 可能是因为 OP 在某处读到 UDP 可能具有更高的吞吐量(通常是这样)。这就是 UDP 经常用于 VOIP 或视频流等的原因。
  • 它通常没有可靠性功能。一旦将它们添加到与 TCP 相同的标准中,根据定义,它并不比 TCP 更好。

标签: c sockets


【解决方案1】:

如果需要可靠的传输,建议使用 TCP 套接字。
但是,如果你想使用 UDP 套接字,那么你必须实现某种自定义协议,你必须等到接收者没有确认接收到数据包。

在您的客户端和服务器代码中,客户端盲目地向服务器发送数据,而不关心当前在服务器端发生的丢失数据包。

对于一个简单的解决方法,您可以在
n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&amp;server,sizeof(struct sockaddr));
之后立即添加一个
recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&amp;server,sizeof(struct sockaddr)); 在您的 client.c
n= sendto(sock,"ACK",strlen("ACK"),0,(struct sockaddr *)&amp;from,&amp;fromlen);
n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&amp;from,&amp;fromlen);server.c

之后立即

并且您必须注意正确处理文件,因为不正确的文件处理会导致输入和输出文件不匹配。

【讨论】:

    【解决方案2】:
           n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
    

    您正在传输二进制数据,即可能包含\0 的数据。 strlen 不能用于二进制数据,因为它只是通过在数据中查找 \0 来确定数据的长度。如果\0buff 的中间,则只会发送直到但不包括\0 的部分。

    除此之外:

    在 c 中使用 udp 进行可靠的数据传输

    在进行数据传输时,您根本不关心可靠性。数据包可能会重新排序、重复或丢失,在大多数情况下您不会注意到它。与 TCP 不同,UDP 本身根本不提供任何可靠性。

    【讨论】:

      猜你喜欢
      • 2013-08-26
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-04
      • 1970-01-01
      相关资源
      最近更新 更多