9-17 tftp

发布于:2022-12-13 ⋅ 阅读:(508) ⋅ 点赞:(0)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define IP "192.168.31.47"
int sfd;

int do_download(struct sockaddr_in *p)
{
    struct sockaddr_in sin = *p;

    char buf[520] = "";
    bzero(buf, sizeof(buf));
    //发送读请求
    char *ptr = buf;
    unsigned short *ptr1 = (unsigned short *)ptr;
    *ptr1 = htons(1); //下载请求的网络字节序
    char *ptr2 = ptr + 2;
    strcpy(ptr2, "5.png"); //下载请求的文件名
    char *ptr3 = ptr2 + strlen(ptr2);
    *ptr3 = 0;
    char *ptr4 = ptr3 + 1;
    strcpy(ptr4, "octet"); //下载模式
    int bufsize = 2 + strlen(ptr2) + 1 + strlen(ptr4) + 1;
    //要发送给谁,则地址信息填充的就是谁的ip和端口
    if (sendto(sfd, buf, bufsize, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        perror("sendto");
        return -1;
    }
    printf("发送下载请求成功\n");
    //打开一个文件,然后写入读取的信息
    ssize_t res;
    char str[520] = "";
    struct sockaddr_in cin;          // 对端的ip 和端口
    socklen_t addrlen = sizeof(cin); //对端的地址结构体的大小
    //写入文件
    int fd = open("./1.png", O_RDWR | O_CREAT, 0664);
    unsigned short i = 0;
    while (1)
    {
        //清零
        bzero(str, sizeof(str));
        //读取数据,
        res = recvfrom(sfd, str, 516, 0, (struct sockaddr *)&cin, &addrlen);
        unsigned short *p1 = (unsigned short *)str;
        unsigned short *p2 = p1 + 1;
        unsigned char *p3 = (unsigned char *)(p1 + 2);
        printf("接收成功,操作码 %d,块编号%d\n", *p1, *p2);
        if (res < 0)
        {
            perror("recvform");
            return -1;
        }
        else if (res > 0)
        {
            if (*p1 == htons(5))
            {
                printf("errno :%s\n", p3);
                return -1;
            }
        }
        // 把正常读取的数据写入 自己要保存的文件内
        if (fd < 0)
        {
            perror("open");
            return -1;
        }
        ssize_t w = write(fd, p3, res - 4);
        if (w < 0)
        {
            perror("write");
            return -1;
        }
        if ((res - 4) < 512)
        {
            close(fd);
            break;
        }
        char ack[8] = "  ";
        bzero(ack, sizeof(ack));
        unsigned short *q1 = (unsigned short *)ack;
        *q1 = htons(4);
        unsigned short *q2 = q1 + 1;
        *q2 = *p2;
        printf(" *q2 = %d\n", *q2);
        //ACK回答
        if (sendto(sfd, ack, 4, 0, (struct sockaddr *)&cin, sizeof(cin)) < 0)
        {
            perror("sendto");
            return -1;
        }
        printf("回复ack\n");
    }
    printf("现在下载完成\n");
    return 0;
}

int do_upload(struct sockaddr_in *p)
{
    struct sockaddr_in sin = *p;
    char buf[600] = "";
    bzero(buf, sizeof(buf));
    //发送写请求
    char *ptr = buf;
    unsigned short *ptr1 = (unsigned short *)ptr;
    *ptr1 = htons(2); //下载请求的网络字节序
    char *ptr2 = ptr + 2;
    strcpy(ptr2, "8.png"); // 下载请求的文件名
    char *ptr3 = ptr2 + strlen(ptr2);
    *ptr3 = 0;
    char *ptr4 = ptr3 + 1;
    strcpy(ptr4, "octet"); // 下载模式
    int size = 2 + strlen(ptr2) + 1 + strlen(ptr4) + 1;
    //发送写请求 地址信息结构体不要填错
    if (sendto(sfd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        perror("sendto");
        return -1;
    }
    printf("发送上传请求成功\n");
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    char ack[8] = "";
    bzero(ack, sizeof(ack));
    //打开文件,获取文件描述符
    int fd = open("./8.png", O_RDWR | O_CREAT, 0664);
    if (fd < 0)
    {
        perror("open");
        return -1;
    }
    if (recvfrom(sfd, ack, 4, 0, (struct sockaddr *)&cin, &addrlen) < 0)
    {
        perror("recvfrom");
        return -1;
    }
    unsigned short *p1 = (unsigned short *)ack;
    unsigned short *p2 = p1 + 1;
    //核对ack指令,正确的话就下载
    if (*p1 == htons(5))
    {
        perror("errror5");
        return -1;
    }
    else if (*p1 = htons(4))
    {
        printf("服务器回答请求写成功,开始写入数据 %d   %d\n", *p1, *p2);
    }
    int i = 1;
    while (1)
    {
        //开始写入数据
        char str[520] = "";
        bzero(str, sizeof(str));
        unsigned short *q1 = (unsigned short *)str;
        unsigned short *q2 = q1 + 1;
        unsigned short *q3 = q2 + 1;
        *q1 = htons(3);
        *q2 = htons(i++);
        ssize_t len = read(fd, q3, 512);
        if (len <= 0)
        {
            close(fd);
            break;
        }
        if (sendto(sfd, str, len + 4, 0, (struct sockaddr *)&cin, sizeof(cin)) < 0)
        {
            perror("sendto");
            return -1;
        }
        if (len < 512)
        {
            close(fd);
            break;
        }
        if (recvfrom(sfd, ack, 4, 0, (struct sockaddr *)&cin, &addrlen) < 0)
        {
            perror("recvfrom");
            return -1;
        }
        //核对ack指令,正确的话就下载
        if (*p1 == htons(5))
        {
            perror("errror5");
            return -1;
        }
        else if (*p1 = htons(4))
        {
            printf("服务器回答请求写成功,开始写入数据 %d   %d\n", *p1, *p2);
        }
    }
    printf("上传成功\n");
    return 0;
}
int main()
{
    //创建套接字文件描述符;
    sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sfd < 0)
    {
        perror("socket");
        return -1;
    }
    //地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(69);            //服务起的端口号
    sin.sin_addr.s_addr = inet_addr(IP); // 服务器自身的IP 地址
    //展示页面
    char c;
    while (1)
    {
        printf("****************\n");
        printf("******1.下载*********\n");
        printf("******2.上传*********\n");
        printf("******3.退出*********\n");
        printf("****************\n");
        printf("请输入(1,2,3)>>>");
        c = getchar();
        while (getchar() != 10)
            ;
        switch (c)
        {
        case '1': //下载
            do_download(&sin);
            break;
        case '2': //上传
            do_upload(&sin);
            break;
        case '3': //退出
            goto END;
            break;
        default:
            printf("输入错误,请重新输入\n");
        }
    }
END:
    close(sfd);

    return 0;
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到