2023.4.21

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#define ERR_MSG(msg)do{\
    fprintf(stderr,"line:%d\n",__LINE__);\
    perror(msg);\
}while(0)
#define SER_PORT 69
#define SER_IP "192.168.31.111"
int  download_cli(char filename[])
{
    //创建报式套接字
    int cfd= socket(AF_INET,SOCK_DGRAM,0);
    if(cfd<0)
    {
        ERR_MSG("socket");
        return -1;
 
    }
    printf("socket suceess=%d__%d__\n",cfd,__LINE__);
 
    /*//填充服务器的地址信息结构体,绑定到套接字上 给下面的sendto使用*/
    struct sockaddr_in sin;
    sin.sin_family =AF_INET;
    sin.sin_port   =htons(SER_PORT);
    sin.sin_addr.s_addr=inet_addr(SER_IP);//tftp服务器所在的ip
    socklen_t addrlen=sizeof(sin);
    //发送下载请求协议
       char buf[516]={0};
    short* p1=(short *)buf;
    *p1=htons(1);//操作码
    char* p2=buf+2;
    strcpy(p2,filename);//要下载的文件名
    char* p3=p2+strlen(p2);
    *p3=0;
    char* p4=p3+1;
    strcpy(p4,"octet");//模式
    char* p5=strlen(p4)+p4;
    *p5=0;
    int size=4+strlen(p2)+strlen(p4);
    if(sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
    {
        ERR_MSG ("send");
        return -1;
    }
    printf("发送成功\n");
    //打开文件
    int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);//只写
    if(fd<0)
    {
        ERR_MSG("open");
        return -1;
    }
    char buf2[128]="";
    ssize_t res;
 
    while(1){
        //接受服务器发送的数据包、
        //提取数据包中的数据(buf+4),另存到文件里
        //给服务器回复ack,组ACK包,快编号与接收到的数据包的快编号一致
        //如果收到回复的是错误包,则打印错误码+错误信息,退出
        bzero(buf,sizeof(buf));
        res =recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
        if(res<0)
        {
            ERR_MSG("recvfrom");
            return -1;
        }
        printf("len:%ld\n",res);
        //判断操作码是否是ERR
        if(buf[1]==0x03)
        {
            printf("正在写入文件\n");
            //写入文件
            char *p=buf+4;
            write(fd,p,res-4);
            /* {*/
            /*ERR_MSG("write");*/
            /*return -1;*/
            /*}*/
        }
        //发送应答包
        int size=sprintf(buf2,"%c%c%c%c",0x00,0x04,buf[2],buf[3]);
        printf("端口号 %d\n",sin.sin_port);
        if(sendto(cfd,buf2,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
        {
            ERR_MSG("snedto");
            return -1;
        }
        if(res-4<512)
        {
            printf("下载成功\n");
            return 0;
        }
 
        printf("[%s :%d]:%s\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),buf);
    }
    //关闭套接字
    close(cfd);
    close(fd);
 
 
 
}
 
int uploading_cli(char filename[])//上传
{
    //创建报式套接字
    int cfd= socket(AF_INET,SOCK_DGRAM,0);
    if(cfd<0)
    {
        ERR_MSG("socket");
        return -1;
 
    }
    printf("socket suceess=%d__%d__\n",cfd,__LINE__);
    
    struct sockaddr_in sin;
    sin.sin_family =AF_INET;
    sin.sin_port   =htons(SER_PORT);
    sin.sin_addr.s_addr=inet_addr(SER_IP);//tftp服务器所在的ip
    
 
    //向这服务器发送上传请求
        char buf[516] = "";
       memset(buf,0,sizeof(buf));
        int size = sprintf(buf,"%c%c%s%c%s%c",0x00,0x02,filename,0,"octet",0);
        if(sendto(cfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin)) < 0){
            ERR_MSG("sendto");
            return -1;
        }
        printf("sendto success\n");
 
        struct sockaddr_in ser_sin;//ser_sin表示服务器回复时的IP和随机端口
        socklen_t addrlen = sizeof(ser_sin);
        ssize_t res = 0;
        int size_ACK = 0;        
        int fd = open(filename,O_RDONLY,0666);
        char r_buf[512] = "";
        int read_res = 0;
        char buf_ACK[4] = "";
                             
        while(1){
            //接受服务器回复的ACK包
            memset(buf_ACK,0,sizeof(buf_ACK));
            memset(buf,0,sizeof(buf));
            res = recvfrom(cfd,buf_ACK,sizeof(buf_ACK),0,(struct sockaddr *)&ser_sin,&addrlen);
            if(res < 0){
                ERR_MSG("recvfrom");
                return -1;
            }
            printf("[%s:%d]\n",inet_ntoa(ser_sin.sin_addr),ntohs(ser_sin.sin_port));
            printf("%d%d%d%d\n",buf_ACK[0],buf_ACK[1],buf_ACK[2],buf_ACK[3]);
            //根据服务器回复的ACK包封装数据包
            buf_ACK[1] = 0x03;
            buf_ACK[3] = buf_ACK[3]+1;
            buf[0] = buf_ACK[0];
            buf[1] = buf_ACK[1];
            buf[2] = buf_ACK[2];
            buf[3] = buf_ACK[3];
            char *p = buf+4;
            read_res = read(fd,r_buf,sizeof(r_buf));    
            strcat(p,r_buf);
            printf("buf =%ld\n",sizeof(buf));
            if(sendto(cfd,buf,read_res+4,0,(struct sockaddr *)&ser_sin,sizeof(ser_sin)) < 0){
                ERR_MSG("sendto");
                return -1;
            }
            printf("sendto success\n");
            if(read_res < 512){
                break;
            }
        }    
    //关闭套接字
    close(cfd);
 
 
}
int main (int argc, const char *argv[])
{
    printf("--------请输入你要执行的操作-------\n");
    printf("---------1下载--------------\n");
    printf("----------2上传--------------\n");
    int flag=0;
    char filename[20]={0};
    scanf("%d",&flag);
    if(flag!=1&&flag!=2)
    {
        printf("请重新输入\n");
        return -1;
    }else if(flag==1)//下载
    {
        printf("请输入你要下载的文件\n");
        scanf("%s",filename);
        download_cli(filename); //封装下载函数
    }else if(flag==2)//上传
    {
        printf("请输入你要上传的文件\n");
        scanf("%s",filename);
        uploading_cli(filename); //封装上传函数
    }
 
    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值