记得这还是当时在凌阳上网络课程时的做得一个小项目,过了这么久怕忘得一干二净,今天拿出来晒晒记忆,温故而知新。
这里我就不说飞鸽的具体协议了,而是重点列出主要我设计的程序框架。
工程文件组织架构:
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<<>>\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;
}
-----------------------------------------------------------