udp socket编程文件传输

Posted

技术标签:

【中文标题】udp socket编程文件传输【英文标题】:udp socket programming file transfer 【发布时间】:2017-10-31 09:07:57 【问题描述】:

服务器端代码............

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUFLEN 503
#define PORT 8885

void die(char *s)

    perror(s);
    exit(1);


int main(void)

    struct sockaddr_in si_me, si_other;

    int s, i,j, slen = sizeof(si_other) , recv_len;
    char buf[BUFLEN];

    if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    
        die("socket");
    

    memset((char *) &si_me, '1', sizeof(si_me));
    //printf("%d",si_me);

    si_me.sin_family = AF_INET;
    si_me.sin_port = PORT;
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);

    if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
    
        die("bind");
    
    //memset(buf,0,503);
    char fname[20];
    FILE *fp;
    recv_len = recvfrom(s, buf, 20, 0, (struct sockaddr *) &si_other, &slen);

    char fna[100];
    memset(buf,0,503);

    recv_len = recvfrom(s, buf, 20, 0, (struct sockaddr *) &si_other, &slen);

    strcpy(fna,buf);
    //printf("%c\n",fna);
    int len= strlen(fna);
    printf("%d",len);

    unsigned long mm = atoi(buf);
    //printf("mm value: %ld\n",mm);

    fp=fopen(fna,"wb");
    int itr=1;
    memset(buf,0,503);
    while(itr*503<mm)
    
        if ((recv_len = recvfrom(s, buf, 503, 0, (struct sockaddr *)&si_other,          &slen)) == -1)
        
            die("recvfrom()");
        
        fwrite(buf,503, 1, fp);
        memset(buf,0,503);
        //printf("Loop no: %d",i)
        //for(i=0;i<=itr;i++);

        itr++;
    

    //printf("Loop no: %d\n",i);
    printf("%d",(mm%503));
    recv_len = recvfrom(s, buf, (mm%503), 0, (struct sockaddr *) &si_other, &slen);

    fwrite(buf,(mm%503), 1, fp);
    memset(buf,0,503);
    fclose(fp);
    close(s);

    return 0;

客户端代码.......

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define SERVER "127.0.0.1"
#define BUFLEN 503
#define PORT 8885

void die(char *s)

    perror(s);
    exit(1);

unsigned long fsize(char* file)

    //String bbb=file;
    FILE * f = fopen(file, "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    printf("Total size: %d \n",len);
    fclose(f);
    return len;


int main(void)

    struct sockaddr_in si_other;
    int s, i, slen=sizeof(si_other);
    char buf[BUFLEN];
    char message[BUFLEN];

    if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    
        die("socket");
    

    memset((char *) &si_other, '1', sizeof(si_other));
    si_other.sin_family = AF_INET;
    si_other.sin_port = PORT;
    //printf("Htons= %d \n",htons(PORT));

    if (inet_aton(SERVER , &si_other.sin_addr) == 0)
    
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    
    //memset(message,0,503);
    char fname[20];
    printf("Enter Filename with extension: ");
    scanf("%s",&fname);
    sendto(s, fname, 20 , 0 , (struct sockaddr *) &si_other, slen);

    memset(message,0,503);

    unsigned long siz = fsize(fname);
    printf("siz: %ld\n",siz);

    char str[10];
    sprintf(str, "%d", siz);
    int send1=sendto(s, str, 20 , 0 , (struct sockaddr *) &si_other, slen);
    printf("value of send1= %d",send1);

    FILE *f;

    f=fopen(fname,"rb");
    memset(message,0,503);
    fread(message, 503,1,f);

    int itr =1;
    while(itr*503<siz)

        if (sendto(s, message, 503 , 0 , (struct sockaddr *) &si_other, slen)==-1)
        
            die("sendto()");
        
        memset(message,0,503);
        fread(message, 503,1,f);
        itr++;
    
    fread(message, (siz % 503),1,f);
    int send2=sendto(s, message, (siz % 503) , 0 , (struct sockaddr *) &si_other, slen);
    printf("\n value of send 2= %d",send2);

    memset(message,0,503);
    fclose(f);
    close(s);

    return 0;

这是在 UDP 套接字编程中传输图像、视频、文本文件等文件的代码。(从客户端到服务器端文件夹)。

谁能向我解释为什么两边都使用WHILE 循环,它的目的是什么? 另外,一个问题是使用这个程序,文件从客户端正确发送到服务器,但在到达服务器端后,文件名正在更改。

unsigned long len = (unsigned long)ftell(f);
    printf("Total size: %d \n",len);

经过测试我发现服务器端更改的文件名设置为客户端len变量中的文件指针的当前位置。(len的值与变量@987654327相同@ 在服务器端,变量 'siz' 在客户端。

例如:

如果我从服务器端发送“Wallpaper.png”,它将到达服务器端,并且文件以名称“164101”保存。但是图像显示正常。

为什么 memset 使用了这么多次?它的实际用途是什么??

【问题讨论】:

您应该编辑您的问题以使其更清晰。如果我理解正确,您是在问“为什么从客户端发送到服务器的对象的文件名会在服务器上更改?” 在服务器端你让服务器给他收到的文件随机取一个名字,你可以自己设置 给定#define PORT 8885,代码si_other.sin_port = PORT; 是错误的。端口必须按网络字节顺序排列,因此代码应为si_other.sin_port = htons(PORT); 此外,发布的代码不会进行任何错误检查。 是的。这正是我要问的@DanielLane 好的。但是为什么服务器端总是选择也是文件指针位置的文件名??(或者更具体地说,它将名称设置为文件指针结束的位置)。你能帮我如何自己设置文件名吗? @SPSP 【参考方案1】:

您的客户端和服务器使用相同的文件传输协议,定义如下:

前 20 个字节包含文件名 20 字节包含文件长度 实际字节由 503 个字节的块发送和接收 最终块(小于 503 字节)在末尾获取

在服务器端,您弄乱了应该存储文件名fname 的变量和应该存储文件长度fna 的变量。您可能应该将后者重命名为 flen ,如下面的 sn-p :

...
char fname[20]; // variable to store file name
FILE *fp;
recv_len = recvfrom(s, buf, 20, 0, (struct sockaddr *) &si_other, &slen);
strcpy(fname, buf); // got 20 bytes in buf, copy to fname : this is the file  name 
printf("File name : %s\n", fname);

char flen[20];
memset(buf,0,503); // reset NULL bytes to buf

recv_len = recvfrom(s, buf, 20, 0, (struct sockaddr *) &si_other, &slen);
strcpy(flen, buf); // got 20 bytes, copy to flen : this is the file length (as a string)
printf("Length as string : %s\n", flen);
printf("Length as integer : %d\n", atoi(flen));

unsigned long mm = atoi(buf); // convert file length as a string to an integer variable
printf("mm value: %ld\n",mm);

fp=fopen(fname,"wb"); // use the proper variable as the file name
int itr=1;
...

希望这会有所帮助!

【讨论】:

很高兴看到它有效。学习C语言套接字编程的愉快旅程,我很享受!如果您认为应该被接受,请不要忘记接受答案:-)【参考方案2】:

while 循环用于将文件拆分为较小的块,这些块适合 UDP 数据报,其大小有限。与 TCP 不同,UDP 不处理这些细节,因此您必须自己实现所有这些。

最终,您还必须实现超时和重传、重复数据报检测以及可能某种形式的拥塞控制。在 UDP 之上编写一个优于基于 TCP 的解决方案的良好文件传输协议是相当困难的。

【讨论】:

这有帮助。你能解释一下吗? @弗洛里安

以上是关于udp socket编程文件传输的主要内容,如果未能解决你的问题,请参考以下文章

请问android用两个模拟器udp通信传输音频文件要怎么做?

网络编程Socket网络编程

Python网络编程—socket套接字编程(UDP)

socket编程:简单UDP服务器/客户端编程

通过 Socket 实现 UDP 编程

java 25 - 4 网络编程之 UDP协议传输思路