3.16 网络编程

#include <myhead.h>
#define SER_IP "192.168.117.71"
#define SER_PORT 69
//下载函数
int download(int cfd,struct sockaddr_in sin)
{
	char name[128]={0};
	printf("请输入文件名\n");
	scanf("%s",name);
	getchar();
	//组建下载包
	char buf[516]="";
	//组装数据
	short *p1=(short*)buf;
	*p1=htons(1);//1表示下载请求
	char *p2=buf+2;
	strcpy(p2,name);
	char *p4=p2+strlen(p2)+1;
	strcpy(p4,"octet");
	//计算请求包大小
	int buf_size=4+strlen(p2)+strlen(p4);
	//将请求包发给服务器
	if(sendto(cfd,buf,buf_size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		printf("sendto error");
		return -1;
	}
	//打开文件用于接收收据
	int fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fd<0)
	{
		printf("open error\n");
		return -1;
	}
	//设置块编号为1
	int num=1;
	socklen_t addrlen=sizeof(sin);
	ssize_t recv_len;//收到数据包大小
	while(1)
	{
		bzero(buf,516);
		recv_len=recvfrom(cfd,buf,516,0,(struct sockaddr*)&sin,&addrlen);
		if(recv_len<0)
		{ 
			printf("recvfrom error");
			return -1;
		}
		if(buf[1]==3)//判断是否是数据包
		{
			if(htons(num)==*(unsigned short*)(buf+2))//判断块编号是否对应
			{
				if(write(fd,buf+4,recv_len-4)<0)//将数据包内容写入文件
				{
					printf("write error");
					break;
				}
				//返回一个ACK包
				buf[1]=4;
				//ACK包只要将数据包操作码改为4,发送数据包前4字节
				if(sendto(cfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0)
				{
					printf("sendto error");
					break;
				}
				//判断数据包是否小于516,小于516说明文件下载完毕
				if(recv_len<516)
				{
					printf("文件下载完毕\n");
					break;
				}
				//块编号加1
				num++;
			}
		}
	}
	close(fd);

}
//上传函数
int upload(int cfd,struct sockaddr_in sin)
{
	char name[128]={0};
	printf("请输入文件名\n");
	scanf("%s",name);
	getchar();
	//组装上传请求
	char buf[516]="";
	short *p1=(short*)buf;
	*p1=htons(2);//2表示上传请求
	char *p2=buf+2;
	strcpy(p2,name);
	char *p4=p2+strlen(p2)+1;
	strcpy(p4,"octet");
	//计算请求包大小
	int buf_size=4+strlen(p2)+strlen(p4);
	//将请求包发给服务器
	if(sendto(cfd,buf,buf_size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		printf("sendto error");
		return -1;
	}
	//以读模式打开文件
	int fd=open(name,O_RDONLY);
	if(fd<0)
	{
		printf("文件打开失败");
		return -1;
	}
	//循环接收发送数据包
	int recv_len;
	unsigned short num=0;
	socklen_t addrlen=sizeof(sin);
	while(1)
	{
		bzero(buf,516);
		//接收服务器返回的ACK包
		recv_len=recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
		if(recv_len<0)
		{
			printf("recvfrom error");
			return -1;
		}
		//判断块编号是否对应
		if(num==ntohs(*(unsigned short*)(buf+2)))
		{
			//将操作码改为3
			buf[1]=3;
			num++;
			//将块编号转化为客户端字节序
			*(unsigned short*)(buf+2)=htons(num);
			//读取文件
			int res=read(fd,buf+4,512);
			if(res<0)
			{
				printf("read error");
				return -1;
			}
			else if(res==0)
			{
				printf("文件上传成功\n");
				break;
			}
			if(sendto(cfd,buf,res+4,0,(struct sockaddr*)&sin,sizeof(sin))<0)
			{
				printf("sendto error\n");
				return -1;
			}

		}
		//块编号不对应
		else
		{
			printf("文件上传失败\n");
		}
	}
	return 0;
}

//主函数
int main(int argc, const char *argv[])
{
	//1、创建用于通信的套接字文件描述符
	int cfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}
	printf("socket success cfd = %d\n", cfd);

	//2、数据收发
	char wbuf[128] = "";
	//填充要发送的对端的地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SER_PORT);
	sin.sin_addr.s_addr = inet_addr(SER_IP);
	int ctl;
	while(1)
	{
		printf("1.下载  2.上传  3.退出\n");
		scanf("%d",&ctl);
		switch(ctl)
		{
		case 1:
			download(cfd,sin);
			break;
		case 2:
			upload(cfd,sin);
			break;
		case 3:
			goto END;
			break;
		default:
			printf("输入错误\n");
		}
	}
END:
	//3、关闭套接字
	close(cfd);

	return 0;
}

效果

相关推荐

  1. 嵌入式学习——网络编程(TCP)——day31

    2024-03-16 18:36:03       8 阅读
  2. 网络编程!

    2024-03-16 18:36:03       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-16 18:36:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-16 18:36:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-16 18:36:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-16 18:36:03       20 阅读

热门阅读

  1. c# 循环内使用匿名函数关联变量的问题

    2024-03-16 18:36:03       19 阅读
  2. uniapp实现我的订单页面无感 - 删除数据

    2024-03-16 18:36:03       20 阅读
  3. 为什么租用的服务器经常出现宕机的情况?

    2024-03-16 18:36:03       22 阅读
  4. 获取iOS和Android的app下载渠道和相关参数的方式

    2024-03-16 18:36:03       21 阅读
  5. 【TypeScript系列】声明合并

    2024-03-16 18:36:03       26 阅读
  6. python前端开发

    2024-03-16 18:36:03       26 阅读
  7. 数据智能——企业从业务数据化走向业务智能化

    2024-03-16 18:36:03       23 阅读
  8. 游戏测试 - 二面 - 创梦天地二面

    2024-03-16 18:36:03       24 阅读