飞鸽传书
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