基于UDP的TFTP文件传输

cs 复制代码
#include <myhead.h>
#define SER_PORT 69
#define SER_IP "192.168.0.149"
#define CLI_PORT 5555
#define CLI_IP "192.168.0.150"

int main(int argc,const char *argv[])
{
    //1.创建用于通信的服务器套接字文件描述符
    int cfd = socket(AF_INET,SOCK_DGRAM,0);
    if(cfd==-1)
    {
        perror("socket error");
        return -1;
    }

    int menu = 0;
    while(1)
    {
        printf("****************\n");
        printf("****1.下载*******\n");
        printf("****2.上传*******\n");
        printf("****3.退出*******\n");
        printf("****************\n");
        printf("请输入>>>");
        scanf("%d",&menu);
        getchar();
        if(menu==1)
        {
            char buf[516]="";
            struct sockaddr_in sin;
            socklen_t addrlen = sizeof(sin);
            sin.sin_family = AF_INET;
            sin.sin_port = htons(SER_PORT);
            sin.sin_addr.s_addr = inet_addr(SER_IP);

            char filename[128]="";
            printf("请输入要下载的文件名>>>");
            fgets(filename,sizeof(filename),stdin);
            filename[strlen(filename)-1]=0;

            //发送下载请求
            short *p1 = (short *)buf;
            *p1 = htons(1);
            char *p2 = buf+2;
            strcpy(p2,filename);
            char *p3 = p2+strlen(p2)+1;
            strcpy(p3,"octet");
            int size = 2+strlen(p2)+strlen(p3)+2;
            sendto(cfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin));

            //打开或创建下载文件
            int fd = open(filename,O_WRONLY|O_CREAT,0644);
            if(fd==-1)
            {
                perror("open error");
                return -1;
            }

            while(1)
            {
                //接收服务器发来的信息
                ssize_t n = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&sin,&addrlen);
                //判断是否为数据包
                short *p4 = (short *)buf;
                if(ntohs(*p4)==3)
                {
                    //将收到的数据写入文件
                    write(fd,buf+4,n-4);

                    //向服务器发送ACK包
                    *p4 = htons(4);
                    sendto(cfd,buf,4,0,(struct sockaddr *)&sin,addrlen);

                    //判断发来的数据是否小于516,小于表示数据已经传完了
                    if(n<516)
                    {
                        printf("下载成功\n");
                        break;
                    }
                }
            }
        }
        else if(menu==2)
        {
            char buf[516]="";
            struct sockaddr_in sin;
            //socklen_t addrlen = sizeof(sin);
            sin.sin_family = AF_INET;
            sin.sin_port = htons(SER_PORT);
            sin.sin_addr.s_addr = inet_addr(SER_IP);

            char filename[128]="";
            printf("请输入要上传的文件名>>>");
            fgets(filename,sizeof(filename),stdin);
            filename[strlen(filename)-1]=0;

            //发送上传请求
            short *p1 = (short *)buf;
            *p1 = htons(2);
            char *p2 = buf+2;
            strcpy(p2,filename);
            char *p3 = p2+strlen(p2)+1;
            strcpy(p3,"octet");
            int size = 2+strlen(p2)+strlen(p3)+2;
            sendto(cfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin));  

            //打开上传的文件
            int fd = open(filename,O_RDONLY);
            if(fd==-1)
            {
                perror("open error");
                return -1;
            }

            //定义传递时的编号
            short x=1;
            struct sockaddr_in addr;
            socklen_t addrlen = sizeof(addr);
            while(1)
            {
                memset(buf,0,sizeof(buf));
                //封装数据并发送给服务器
                short *q1 = (short *)buf;
                *q1 = htons(3);
                short *q2 = p1+1;
                *q2 = htons(x);
                ssize_t n = read(fd,buf+4,512);
                sendto(cfd,buf,n+4,0,(struct sockaddr *)&addr,sizeof(addr));
                
                //接收服务器发来的数据
                memset(buf,0,sizeof(buf));
                recvfrom(cfd,buf,4,0,(struct sockaddr *)&addr,&addrlen);

                //判断发来的是ACK包并且编号正确
                if(ntohs(*q2)==x && ntohs(*q1)==4)
                {
                    //判断文件有没有读取完毕
                    if(n<512)
                    {
                        printf("上传成功\n");
                        break;
                    }
                    x++;   //编号加1,然后进行下一次发送
                }
                else if(ntohs(*q2)!=x && ntohs(*q1)==4)
                {
                    //将光标移动到这一次读取之前
                    lseek(fd,-n,SEEK_CUR);  
                }
            }
        }
        else if(menu==3)
        {
            break;
        }
    }
    close(cfd);
    return 0;
}
相关推荐
OpenLoong 开源社区2 小时前
打破 NAT 限制,零侵入跨网络通信:基于 WebRTC 的透明 TCP 隧道跨网络通信方案
网络协议·tcp/ip·开源·webrtc·openloong开源社区
从琳开始9892 小时前
从Socket到UDP回显服务器:Java网络编程完整指南
java·网络·网络协议·udp·java-ee
明天也要努力学习12 小时前
HTTP 协议的基本格式和 fiddler 的用法
网络协议·http·fiddler
Tel1992530800418 小时前
温度湿度信号转WiFi/MQTT/Modbus TCP采集模块 无线传输
网络·网络协议·tcp/ip·工业自动化·工控设备
lazy H21 小时前
【计算机网络】第 13 篇:NAT 和端口映射是什么?为什么本地服务外网访问不了?
java·网络·网络协议·学习·计算机网络·408
低慢小uav1 天前
(已解决)Zynq芯片lwip协议栈,使用tcp作为服务器Service,接收大量数据时,长度接收正常,接收对数据校验,校验和异常分析
网络协议·tcp/ip·fpga开发
|_⊙1 天前
应用层协议HTTP与HTTPS
网络·网络协议·http
byte轻骑兵1 天前
【PBAP】规范精讲[9]: 蓝牙PBAP的互联互通法则——GOEP互操作性要求深度解析
网络协议·人机交互·蓝牙协议·pbap
路由侠内网穿透.1 天前
本地部署开源 WSGI HTTP 服务器 Gunicorn 并实现外部访问
运维·服务器·网络·网络协议·http·开源
箓维1 天前
TCP Socket的基础实现
网络·网络协议·tcp/ip