实现UDP的可靠文件传输 练习

来源:互联网 发布:linux 图形库 编辑:程序博客网 时间:2024/05/25 19:58
# include <stdio.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <unistd.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <stdlib.h>
# include <errno.h>
# include <fcntl.h>
# include <netdb.h>
# include <stdarg.h>
# include <string.h>
# define PORT 8000
# define BUFFER_SIZE 1024
# define FILE_NAME_MAX_SIZE 512
typedef struct
{
    int id;/*数据包的编号*/
    int buf_size;/*数据包的大小*/
} Packinfo;
struct Sendpack
{
    Packinfo head;/*数据识别信息*/
    char buf[BUFFER_SIZE];/*用于存放文件数据*/
} data;


int main(void)
{
    int send_id = 0;
    int receive_id = 0;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1 == sockfd)
    {
        perror("socket failed");
        return -1;
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    inet_aton("176.3.14.80", &server_addr.sin_addr);
    int ret = bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(-1 == ret)
    {
        perror("bind failed");
        return -1;
    }
    while(1)
    {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        char buffer[FILE_NAME_MAX_SIZE] = {0};
        if(-1 == recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_addr_len))
        {
            perror("recvfrom failed");
            return -1;
        }
        printf("客户端地址为:%s  %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        char file_name[FILE_NAME_MAX_SIZE + 1] = {0};//为什么要+1?
        strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
        printf("服务器处理过后的文件名称为:%s\n", file_name);
        int fd = open(file_name, O_RDONLY);
        if(-1 == fd)
        {
            perror("open failed");
            return -1;
        }
        else
        {
            printf("打开文件成功!\n");
            int len = 0;
            Packinfo pack_info;//定义数据包头结构体变量
            while(1)
            {
                if(receive_id == send_id)//此时都为0
                {
                    ++send_id;
                    len = read(fd, data.buf, sizeof(data.buf));
                    printf("len = %d\n", len);
                    if(len > 0)
                    {
                        printf("第%d次读取到的内容为:%s\n", send_id, data.buf);
                        data.head.id = send_id;
                        data.head.buf_size = len;
                        if(sendto(sockfd, &data, sizeof(data), 0, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
                        {
                            perror("sendto failed");
                            return -1;;
                        }
                        printf("向客户端发送数据成功\n");
                        if(recvfrom(sockfd, &pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_len)<0)
                        {
                            perror("recvfrom failed");
                            return -1;
                        }
                        printf("从客户端读到的内容为:id = %d buf_size = %d\n", pack_info.id, pack_info.buf_size);
                        receive_id = pack_info.id;
                    }
                    else if(len < 0)
                    {
                        perror("read failed");
                        return -1;
                    }
                    else
                    {
                        break;
                    }
                }
                else/*如果receive_id 不等于 send_id 即客户端接收到的数据和服务器发送的数据不一致的话就重新发送*/
                {
                    if(sendto(sockfd, &data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_len<0))
                    {
                        perror("sendto failed");
                        return -1;
                    }
                    printf("重新向客户端发送数据成功\n");
                    /*重新接收客户端反馈信息*/
                    if(recvfrom(sockfd, &pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_len)<0)
                    {
                        perror("recvfrom failed");
                        return -1;
                    }
                    printf("从客户端读到的内容为:id = %d buf_size = %d\n", pack_info.id, pack_info.buf_size);
                    printf("-----------------------------------\n");
                    receive_id = pack_info.id;
                }
            }
            /*关闭文件*/
            close(fd);
            printf("File:%s Transfer Successful!\n", file_name);
            break;
        }
    }
    /*关闭套接字*/
    close(sockfd);
    return 0;

}


# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <errno.h>
# define PORT 8000
# define BUFFER_SIZE 1024
# define FILE_NAME_MAX_SIZE 512
typedef struct
{
    int id;
    int buf_size;
} Packinfo;
struct package
{
    Packinfo head;
    char buf[BUFFER_SIZE];
} data;


int main(void)
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1 == sockfd)
    {
        perror("socket failed");
        exit(-1);
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    inet_aton("176.3.14.80", &server_addr.sin_addr);
    socklen_t server_addr_len = sizeof(server_addr);
    char file_name[FILE_NAME_MAX_SIZE + 1] = {0};
    printf("请输入文件名称:");
    gets(file_name);
    char str[FILE_NAME_MAX_SIZE] = {0};
    strncpy(str, file_name, strlen(file_name)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(file_name));
    printf("--------------------------------------------\n");
    printf("客户端处理过后的文件名称为:%s\n", str);
    int fd = open(file_name, O_RDWR|O_CREAT|O_TRUNC, 0664);
    if(fd < 0)
    {
        perror("open failed");
        exit(-1);
    }
    printf("客户端创建文件成功:\n");
    if(sendto(sockfd, str, sizeof(file_name), 0, (struct sockaddr*)&server_addr, server_addr_len)<0)
    {
        perror("sendto failed");
        exit(-1);
    }
    printf("向服务器发送文件名称成功\n");
    int id = 1;
    int len = 0;
    Packinfo pack_info;
    while(1)
    {
        printf("客户端等待接收服务器信息\n");
        len = recvfrom(sockfd, &data, sizeof(data), 0, (struct sockaddr*)&server_addr, &server_addr_len);
        printf("len = %d\n", len);
        if(len > 0)
        {
            printf("从服务器接收到的数据为:%s\n", data.buf);
            if(data.head.id == id)//如果数据的编号相等
            {
                pack_info.id = data.head.id;
                pack_info.buf_size = data.head.buf_size;
                ++id;
                if(sendto(sockfd, (char*)&pack_info, sizeof(Packinfo), 0, (struct sockaddr*)&server_addr, server_addr_len)<0)
                {
                    perror("pick_info sendto failed");
                    break;
                }
                printf("向服务器发送确认信息成功\n");
                if(write(fd, data.buf, sizeof(data.buf))<data.head.buf_size)
                {
                    perror("write failed");
                    return -1;
                }
                printf("向文件中写入的数据为:%s\n", data.buf);
                memset(data.buf, 0, sizeof(data.buf));
            }
            else if(data.head.id != id)
            {
                pack_info.id = data.head.id;
                pack_info.buf_size = data.head.buf_size;
                if(sendto(sockfd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&server_addr, server_addr_len)<0)
                {
                    perror("重发数据包sendto failed");
                    return -1;;
                }
                printf("重新向服务器发送数据成功\n");
            }
        }
        else if(len < 0)
        {
            perror("recvfrom failed");
            return -1;
        }
        else
            break;
    }
    printf("Receive File :\t%s From Server IP Successful!\n", file_name);
    close(fd);
    close(sockfd);
    return 0;
}


























































0 0