#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;
}