简体   繁体   English

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

[英]reliable data transfer using udp in c

I am writing a socket program for reliable data transfer using udp.我正在编写一个使用 udp 进行可靠数据传输的套接字程序。 I am sending image file from client to the server in chunks of 1024 bytes.我正在以 1024 字节的块将图像文件从客户端发送到服务器。 Below are my codes.They do work fine for large strings and smaller image files.But when I transfer image of 2.3 MB the server will only receive till 2 MB.下面是我的代码。它们对于大字符串和较小的图像文件工作正常。但是当我传输 2.3 MB 的图像时,服务器只会接收到 2 MB。 Say if the total number ofpackets sent was 2271. The server will only receive till 2211 or less and will terminate abruptly.假设发送的数据包总数为 2271。服务器只会接收到 2211 或更少,并且会突然终止。 I am not knowing the reasson.我不知道原因。 Can you please explain me this?你能解释一下吗? and suggest any solution.并提出任何解决方案。 Below is my client code下面是我的客户端代码

#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;
}

And my server code:还有我的服务器代码:

#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;
}
 n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));

You are transferring binary data, ie data which might contain \\0 .您正在传输二进制数据,即可能包含\\0 strlen cannot be used with binary data since it just determines the length of the data by looking for a \\0 inside the data. strlen不能用于二进制数据,因为它只是通过查找数据中的\\0来确定数据的长度。 If a \\0 is in the middle of buff only the part until but not including this \\0 will be sent.如果\\0buff的中间,则只会发送直到但不包括此\\0的部分。

Apart from that:除此之外:

reliable data transfer using udp in c在c中使用udp进行可靠的数据传输

While you are doing a data transfer you don't care about reliability at all.在进行数据传输时,您根本不关心可靠性。 Packets might be reordered, duplicated or get lost and you will not notice it in most cases.数据包可能会被重新排序、复制或丢失,并且在大多数情况下您不会注意到。 UDP does not provide any reliability at all by its own, contrary to TCP.与 TCP 不同,UDP 本身根本不提供任何可靠性。

If a reliable transmission is expected then TCP socket is recommended.如果需要可靠传输,则建议使用 TCP 套接字。
But still, if you want to go with UDP sockets then you have to implement some sort of custom protocol where you have to wait till receiver has not acknowledged the reception of the packet.但是,如果你想使用 UDP 套接字,那么你必须实现某种自定义协议,你必须等到接收器没有确认接收到数据包。

In your client and server code, the client is blindly sending data to the server without caring for missed packets that is happening currently at the server side.在您的客户端和服务器代码中,客户端盲目地向服务器发送数据,而不关心当前在服务器端发生的丢失数据包。

For a simple workaround, you can add a对于一个简单的解决方法,您可以添加一个
recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&server,sizeof(struct sockaddr)); immediately after紧随其后
n= sendto(sock,buff,strlen(buff),0,(struct sockaddr *)&server,sizeof(struct sockaddr));
in your client.c and在您的client.c
n= sendto(sock,"ACK",strlen("ACK"),0,(struct sockaddr *)&from,&fromlen); immediately after紧随其后
n = recvfrom(sock,buf,sizeof (buf),0,(struct sockaddr *)&from,&fromlen); in server.cserver.c 中

And you have to take care of handling the file properly because improper file handling can cause input and output file mismatch.并且您必须注意正确处理文件,因为不正确的文件处理会导致输入和输出文件不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM