linux终端下飞鸽传书(飞秋)协议的容易实现

linux终端下飞鸽传书(飞秋)协议的简单实现

       记得这还是当时在凌阳上网络课程时的做得一个小项目,过了这么久怕忘得一干二净,今天拿出来晒晒记忆,温故而知新。

       这里我就不说飞鸽的具体协议了,而是重点列出主要我设计的程序框架。

       工程文件组织架构:

	Makefile	 :工程编译管理文件	
	main.c		 :工程主main入口c文件	
	myinclude.h	 :公共头文件集合	
	ipmsg.h		 :IPMSG协议头文件
	communication.c	 :用于实现消息及文件收发的c文件
	communication.h		
	file_manager.c	 :用链表实现的管理文件列表的c文件
	file_manager.h	
	user_interface.c :接收并解析处理用户命令的c文件
	user_interface.h 		
	user_manager.c   :用链表实现的管理用户列表的c文件
	user_manager.h
	downfile	 :接收文件的存储文件夹
	file		 :发送文件的存储文件夹
-----------------------------------------------------------
    主main程序架构:
-----------------------------------------------------------
#include "myinclude.h"		//公共头文件
#include "communication.h"	
#include "user_manager.h"
#include "user_interface.h"

int main(int argc, char *argv[])
{
	pthread_t tid_get;	
	pthread_t tid_recv;	
	pthread_t tid_sendf;
	
	help_fun();		   //打印帮助信息
	online("liuhb", "TwoWing");//上线
	
	/* 用户界面线程,处理用户输入的命令 */
	pthread_create(&tid_get, NULL, user_interface, NULL);
	/* 接收消息线程,接收其他客户端发送的UDP数据 */
	pthread_create(&tid_recv, NULL, recv_msg_thread, NULL);
	/* 发送文件线程,等待客户端接收并向其传送文件 */
	pthread_create(&tid_sendf, NULL, sendfile_thread, NULL);
	
	/* 主线程不能退出 */
	pthread_join(tid_get, NULL);
	pthread_join(tid_recv, NULL);
	pthread_join(tid_sendf, NULL);

	return 0;	
}
-----------------------------------------------------------
    用户界面线程:
-----------------------------------------------------------
//命令数组:用来保存 命令名 和 处理函数名
CMD cmdlist[]={	
	{"send", send_fun},		
	{"sendfile", send_file_fun},		
	{"getfile", getfile_fun},
	{"ls", list_fun},	
	{"list", list_fun},	
	{"show", lists},	
	{"help", help_fun},
	{"exit", exit_fun},
	{"quit", exit_fun},
	{"clear", clear_fun},			
	{"cls", clear_fun},	
	{"rm", rm_fun}				
};

//解析并处理命令
int exec_cmd(char *cmd)
{
	char *argv[10] = {NULL};
	int 	argc = 0;
	int 	i = 0;

	/* 去除命令前面的空格 */
	while (*cmd == ' ')
	  cmd ++;

	/* 空命令不做任何处理 */
	if (strlen(cmd) == 0)
	  return 0;

	/*以字符' ' 和'\t' 对命令进行切割 */
	while ((argv[argc] = strtok((argc==0 ? cmd : NULL), " \t")) != NULL) 
	{
	    //printf("argv[%d] = %s\n", argc, argv[argc]);
	    argc++;
	}

	/* 查找命令 */
	for (i=0; i < sizeof(cmdlist)/sizeof(cmdlist[0]); i++)
	{
	    if (strcmp(cmdlist[i].name, argv[0]) == 0)
	    {
		/* 执行命令*/
		cmdlist[i].fun(argc, argv);
		return 0;
	    }
	}
	return -1;
}			

/*
 *用户界面线程,处理用户输入的命令
 */
void *user_interface(void *arg)
{
	int l = write(1, "\033[32m", 5);
	if (l < 0)
	{
	    perror("sys_write");	
	}
	while(1)
	{
	   char buf[100]="";
	   int l = write(1, "\rIPMSG>> ", 9);
	   if (l < 0)
	      perror("sys_write");	
	   fgets(buf, sizeof(buf), stdin);
	   buf[strlen(buf) - 1] = 0;
	   if (exec_cmd(buf) < 0)
	   {
		IPMSG_OUT_MSG_COLOR(
		printf("command not find!\n");
		)
	   }
	}
	return NULL;
}
-----------------------------------------------------------
    接收消息线程:
-----------------------------------------------------------
void *recv_msg_thread(void *arg)
{
    while(1)
    {
	char buf[500]="";		
	char edition[100]="";
	struct sockaddr_in addr = {AF_INET};
	unsigned int addrlen = sizeof(addr);
	int len = 0;
	long pkgnum = 0;
	long cmd = 0;
	char msg[100]="";
	int t = 0;
	char *p = NULL;
	IPMSG_USER temp;			
	len = recvfrom(udp_fd(), buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addrlen);
	sscanf(buf, "%[^:]:%ld:%[^:]:%[^:]:%ld",edition, &pkgnum, temp.name, temp.host, &cmd);
		
	p = strrchr(buf, ':'); //查找附加信息
	memcpy(msg, p+1, len-(p-buf)); //将附加信息放入msg
	temp.s_addr = addr.sin_addr.s_addr;
	switch(GET_MODE(cmd))
	{
	  case IPMSG_BR_ENTRY:
		t = time((time_t*)NULL);
		len = sprintf(buf,"1:%d:%s:%s:%ld:%s",t,user(),host(),IPMSG_ANSENTRY,user());
		sendto(udp_fd(),buf,len,0,(struct sockaddr*)&addr,sizeof(addr));
	  case IPMSG_ANSENTRY:
		add_user(temp);
		break;
	  case IPMSG_SENDMSG:
		if (msg[0] != 0)
		{
		   IPMSG_OUT_MSG_COLOR(
		   printf("\r[recv msg from: %s ]#\n%s\n", temp.name, msg);
		   )
		   write(1,"\rIPMSG:",7);
		}
		if ((cmd&IPMSG_SENDCHECKOPT) == IPMSG_SENDCHECKOPT)
		{
		   char buf[50]="";
		   t = time((time_t *)NULL);
		   int len = sprintf(buf,"1:%d:%s:%s:%ld:%ld",t,user(),host(),IPMSG_RECVMSG, pkgnum);
		   sendto(udp_fd(),buf,len,0,(struct sockaddr*)&addr,sizeof(addr));
		}
		if ((cmd&IPMSG_FILEATTACHOPT) == IPMSG_FILEATTACHOPT)
		{
		   char *p = msg+strlen(msg)+1;
		   //printf("filemsg=%s\n",p);
		   char *fileopt= strtok(p, "\a");//fileopt指向第一个文件属性
		   do{	//循环提取文件信息
			IPMSG_FILE ftemp;
			sscanf(fileopt, "%d:%[^:]:%lx:%lx", &ftemp.num, ftemp.name, &ftemp.size, &ftemp.ltime);	
			strcpy(ftemp.user, temp.name);
			ftemp.pkgnum = pkgnum;
			add_file(ftemp, RECVFILE);
			fileopt = strtok(NULL, "\a");//指向下一个文件属性
		   }while(fileopt != NULL);
		   IPMSG_OUT_MSG_COLOR(
		   printf("\r<<<Recv file from %s!>>>\n", temp.name);
		   )
		   write(1,"\rIPMSG:",7);
		}
		break;
	  case IPMSG_RECVMSG:
		{
		   IPMSG_OUT_MSG_COLOR(
		   printf("\r%s have receved your msg!\n", temp.name);
		   )
		   write(1,"\rIPMSG:",7);
		}
		break;			
	  case IPMSG_BR_EXIT:
		del_user(temp);
		break;
	  default :
		break;			
	}
    }
    return NULL;
}
-----------------------------------------------------------
    发送文件线程:
-----------------------------------------------------------
void *sendfile_thread(void *arg)
{
    int fd = tcp_fd(); //获取TCP_Server套接口描述符
    while(1)
    {
	struct sockaddr_in addr = {AF_INET};
	unsigned int addrlen = sizeof(addr);
	int clifd = accept(fd, (struct sockaddr*)&addr, &addrlen);
	if( clifd<0 )
	{
	    perror("accept");
	    exit(1);
	}
	while (1) // 发送多个文件
	{
	  IPMSG_FILE *p = NULL;
	  FILE *fp = NULL;
	  IPMSG_USER temp;
	  long pkgnum = 0 ;
	  char edition[100]=""; 
	  char file_path[50] = "./file/"; //发送文件目录
	  long oldpkgnum = 0 ;
	  long cmd = 0;
	  int filenum = 0;
	  char buf[1400]="";
	  int sendsize = 0;			
	  //接收IPMSG_GETFILEDATA
	  if (recv(clifd, buf, sizeof(buf), 0)==0)
	      break;
	  sscanf(buf, "%[^:]:%ld:%[^:]:%[^:]:%ld:%lx:%x",edition, &pkgnum, temp.name, temp.host, &cmd, &oldpkgnum, &filenum);
	  //是否是IPMSG_GETFILEDATA
	  if ((GET_MODE(cmd)&IPMSG_GETFILEDATA) != IPMSG_GETFILEDATA)
		break;
	  //获取之前发送的文件信息
	  if ((p = getfileinfo(oldpkgnum, filenum))==NULL)
	      	return NULL;
	  sprintf(file_path, "%s%s", file_path, p->name);
	  if ((fp=fopen(file_path, "r"))==NULL)
	  {
		IPMSG_OUT_MSG_COLOR(
		printf("senderror: no such file: %s\n", p->name);
		)
		return NULL;
	  }			
	  do	//发送文件
	  {
		int size = fread(buf, 1, sizeof(buf), fp);
		send(clifd, buf, size, 0);
		sendsize += size;
	  }while(sendsize < p->size);
	  fclose(fp);	//关闭文件
	  del_file(p, SENDFILE); //从发送文件链表中删除文件
	} //循环发送多个文件
	close(clifd); //关闭套接口等待下个用户连接
    }
    return NULL;
}
-----------------------------------------------------------