飞鸽传书

飞鸽传书
1.功能实现
发送协议:发送/接收,广播包,确认包,文件包,文件下载包
用户之间的聊天系统,
用户之间的文件下载系统。
(由于仓促,代码全在一个.c文件下)

2.程序分析
bash 命令行,通过获取各种命令实现不同的处理方式

void deal(char *s)
{
	Infor *p = read_infor();
	char *s1,*s2;
	char buf1[10];
	char buf2[20];
	char buf3[20];
	//display_infor(p);
	if(!strcmp(s,"get name"))		//获取个人姓名
		printf("%s\n",p->name);
	else if(!strcmp(s,"get sign"))		//获取昵称
		printf("%s\n",p->sign);
	else if(!strcmp(s,"get depart"))		//单位
		printf("%s\n",p->depart);
	else if(!strcmp(s,"get tel"))		//电话
		printf("%s\n",p->tel);
	else if(!strcmp(s,"get email"))		//e-mail
		printf("%s\n",p->email);
	else if(!strcmp(s,"get ip"))		//ip地址
		printf("%s\n",p->ip);
	else if(!strcmp(s,"get mac"))		//网管
		printf("%s\n",p->mac);
	else if(!strcmp(s,"list"))			//好友列表
		display_user();
	else if(!strcmp(s,"free"))			//删除好友
		free(head);
	else if(!strncmp(s,"sendto",6))		//发送信息
		send_message(s);
	else if(!strncmp(s,"sendfile",8))		//发送文件
	{
		sscanf(s,"%s %s %s",buf1,buf2,buf3);
		send_file(buf2,buf3);			//发送文件名
		send_filenew(buf3);				//发送文件里的信息
	}
	else if(!strncmp(s,"set name",8))		//重设姓名
	{
		s1 = s + 9;
		s2 = p->name + 5;
		strcpy(s2,s1);
		printf("%s\n",p->name);
		rewrite_infor(p);	
	}
}

发送广播包,创建udp服务器,不断发送广播包

void *send_broadcast_pack(void *arg)
{
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,"192.168.186.255",&addr.sin_addr.s_addr);
//以上创建udp服务器
	char buf[1024];
	while(1)
	{
		int packsize = 0;
		int len = 0;
		num++;
		packsize = sprintf(buf,"%s:%u:%s:%s:1025:","5.1.180210",num,"wanglu","wanglu-VirtualBox");
		len = sprintf(buf+packsize,"%s%c%s%c%s%c%c%s%c%s%c%c91%c","wanglu01",0,"WorkGroup",0,"08-00-27-1F-09-CD",0,0,"15252435862",0,"[email protected]",0,0,0);
		packsize += len;
		len = sprintf(buf+packsize,"%s%c%c16%c10000001%c%s%c%s","192.168.186.149",0,0,0,0,"yilushunfeng",0,"wanglu-VirtualBox");
		packsize += len;
//以上广播包打包
		sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
		//发送广播包
		memset(buf,0,sizeof(buf));
		sleep(5);
	}
	close(sock);
}

接收包信息并通过解包后的信息,确定是何包,是否发送特定的包;

void *recv_broadcast_pack(void *arg)
{
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	User *p;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	addr.sin_addr.s_addr = INADDR_ANY;
	//以上创建服务器
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	if(bind(sock,(struct sockaddr *)&addr,sizeof(addr)))
	{
		perror("bind error\n");
		close(sock);
		return NULL;
	}
	char buf[1024]={0};
	struct sockaddr_in ad;
	char *q;
	unsigned int len = sizeof(ad);
	while((ret = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&ad,&len))>0)
	{
		/*for(int i=0;i<ret;i++)
		{
			printf("%c",buf[i]);
		}
		printf("%s\n",buf);*/
		p = analysis_broadcast_pack(buf);			//解包函数
		if(!strncmp(p->cmd,"1025",4))					//是否是1025(广播包)包,是发送3确认包
			judge_send_3_pack(p);
		else if(!strncmp(p->cmd,"487",3))				//是否是487(消息包)包,是发送33确认包
			send_33_pack(p);
		else if(!strncmp(p->cmd,"288",3))				//是否是288包,是发送33确认包
		{
			q = strchr(p->name,'[');
			*q = '\0';
			printf("%s\n",p->name);
			send_33_pack(p);
		}
		else if(!strncmp(p->cmd,"2097440",7))		//是否是2097440(文件包)包,是发送33确认包和96包
		{
			send_33_pack(p);
			send_96_pack(p);
		}
		memset(buf,0,sizeof(buf));
	}
	return NULL;
}

解析包函数:碰到‘:’将其变成‘/0’,然后按字符串处理,碰到‘/0’,字符串处理,解析出包编号,版本,mac,姓名,ip等;

User *analysis_broadcast_pack(char *p)
{
	char *q;
	User *pr;
	pr = (User *)malloc(sizeof(User));
	pr->next =NULL;
	for(int i=0;i<5;i++)
	{
		q = strchr(p,':');
		*q = '\0';
		switch(i)
		{
			case 1://printf("0:%s\n",p);
			strcpy(pr->packnum,p);
			break;
			case 2://printf("2:%s\n",p);
			strcpy(pr->pcname,p);
			break;
			case 3://printf("3:%s\n",p);
			strcpy(pr->pc,p);
			break;
			case 4://printf("4:%s\n",p);
			strcpy(pr->cmd,p);
			break;
			default:break;
		}
		p = q+1;
	}
	//	printf("%s\n",pr->cmd);
	if(strncmp(pr->cmd,"2097440",7)!=0)
	{
		for(int i=0;i<14;i++)
		{
			q = strchr(p,'\0');
			switch(i)
			{
				case 0://printf("0:%s\n",p);
				strcpy(pr->name,p);
				break;
				case 1://printf("1:%s\n",p);
				strcpy(pr->depart,p);
				break;
				case 2://printf("2:%s\n",p);
				strcpy(pr->mac,p);
				break;
				case 4://printf("4:%s\n",p);
				strcpy(pr->tel,p);
				break;
				case 5://printf("5:%s\n",p);
				strcpy(pr->email,p);
				break;
				case 8://printf("8:%s\n",p);
				strcpy(pr->ip,p);
				break;
				case 12://printf("12:%s\n",p);
				strcpy(pr->sign,p);
				break;
				default:break;
			}
			p = q+1;
		}
	}
	else
	{
		p = p+1;
		q = strchr(p,':');
		*q = '\0';
		p = q +1;
		q = strchr(p,':');
		*q = '\0';
	//	printf("1:%s\n",p);
		strcpy(pr->name,p);
	}
	return pr;	
}

以下是各种包的打包:
2097440(文件名包)

int packsize = 0;
	num+=2;
	packsize = sprintf(buf,"%s:%u:%s:%s:2097440:%c%u:%s:%lx:0:1:%lu:%lu:%lu:%c","5.1.180210",num,"wanglu","wanglu-VirtualBox",0,num-1,buf3,st.st_size,st.st_ctime,st.st_mtime,st.st_atime,0);

487包(信息包)

char buf[1024];
	int packsize = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:487:%s","5.1.180210",num,"wanglu","wanglu-VirtualBox",p->mac);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:288:%s[rich]0A0000000000860008AE5F6F8FC596D19E12000000000000000000000000000000000000[/rich]"
		,"5.1.180210",num,"wanglu","wanglu-VirtualBox",buf3);

33确认包

User *p = head;
	while(p!=NULL)
	{
		if(!strcmp(p->pcname,pr->pcname))
			break;
		p=p->next;
	}
char buf[1024];
	int packsize = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:33:%s","5.1.180210",num,"wanglu","wanglu-VirtualBox,",pr->packnum);	

3确认包

char buf[1024];
	int packsize = 0;
	int len = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:3:","5.1.180210",num,"wanglu","wanglu-VirtualBox");
	len = sprintf(buf+packsize,"%s%c%s%c%s%c%c%s%c%s%c%c91%c","wanglu01",0,"WorkGroup",0,"08-00-27-1F-09-CD",0,0,"15252435862",0,"[email protected]",0,0,0);
	packsize += len;
	len = sprintf(buf+packsize,"%s%c%c16%c10000001%c%s%c%s","192.168.186.149",0,0,0,0,"yilushunfeng",0,"wanglu-VirtualBox");
	packsize += len;

发送与接收文件的内容(下载与上传文件)

int send_filenew(char *buf3)
{
	int ret;
	char buf[1024]={0};
	int sock = socket(AF_INET,SOCK_STREAM,0);
	struct sockaddr_in ad;
	ad.sin_family = AF_INET;
	ad.sin_port = htons(2425);
	inet_pton(AF_INET,"192.168.186.149",&ad.sin_addr.s_addr);
	int opt = 1;
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	if(bind(sock,(struct sockaddr *)&ad,sizeof(ad)))
	{
		perror("bind error\n");
		close(sock);
		return -1;
	}
	listen(sock,5);
	int csock;
	struct sockaddr_in caddr;
	unsigned int len = sizeof(caddr);
	csock = accept(sock,(struct sockaddr *)&caddr,&len);
	sleep(1);
//创建tcp服务器,以及是否连接到服务器;
	int fd = open(buf3,O_RDONLY);		//只读打开文件
	memset(buf,0,sizeof(buf));
	if(fd == 0)
	{
		printf("open error\n");
	}

	while((ret = read(fd,buf,1024))>0)	//每次读一行信息,并发送给相应的人
	{
		send(csock,buf,ret,0);
	//	printf("%s\n",buf);
		memset(buf,0,sizeof(buf));
	}
	close(fd);
	close(csock);
	close(sock);
	printf("read over\n");
return 0;
}

发送完96确认包后,接收信息

int packsize = 0;
	int ret;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:96:%s:%s:0:","5.1.180210",num,"wanglu","wanglu-VirtualBox",s1,s2);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&ad,sizeof(ad));
	memset(buf,0,sizeof(buf));
/创建tcp子客户端
	int fd = open(pr->name,O_WRONLY | O_CREAT ,0666);//根据文件名创建文件
	sleep(1);
	while((ret = read(sock,buf,sizeof(buf)))>0)		//接收文件信息直到接收不到信息
	{
		printf("%d\n",ret);
		write(fd,buf,ret);
		memset(buf,0,sizeof(buf));
	}
	close(fd);   //关闭文件描述符
	printf("write over\n");

总结
打包时要细心,可以通过wareshake来抓包,已确认是否接收/发送相应的包;
服务器创建,包的发送/发送可以是udp服务器,但文件的发送最好是tcp服务器。
详细信息可通过下列的连接查看
https://gitee.com/wlwcylsf/HKwork.git

猜你喜欢

转载自blog.csdn.net/weixin_44571701/article/details/88617795