1.引言
1.1 项目综述
聊天室项目是学习完linuxC网络编程后,是基于对暑假所学网络编程,线程同步,Linux文件系统编程的综合应用实例,功能更接近于商业聊天应用产品。
1.2 开发工具
Linux系统centos 7.0
gcc 编译器
1.3 项目参考资料
名称 | 作者 |
---|---|
LinuxC编程实战 | 董永清 |
C prime plus | Stephen Prata(US) |
Linux鸟各私房菜 | 高俊峰 |
1.4 术语表
序号 | 术语和缩略语 | 说明性定义 |
---|---|---|
1 | c/s |
client/server模型 |
2 | epoll |
I/O多路复用 |
2. 数据结构说明
名称 | 作用 |
---|---|
链表 | 存储上线用户,存储服务器发给客户端的消息,存储群成员等 |
数组 | 项目收发包主要是通过结构体来实现的,用字符数组存取客户端和服务器的消息和响应 |
3.模块设计
3.1 项目功能设计
-
用户可以进行注册,登录,进入主功能界面
-
主功能界面包含:加好友,查看好友列表,私聊,群聊管理(包含建群,查看群成员,查看用户已经建立的群聊,查看用户已经加入的群聊,解散群等),对于用户请求进行回复的消息管理中心,删除好友,查看聊天记录,发送文件操作。
总功能框架结构图如下:
消息中心主要是通过链表数据结构来将客户端发来的信息或请求进行收集,在指定时机显示给用户。我这群聊功能还不是很全,还有很多不合理的地方待改进。
3.2 算法设计及流程示意
-
客户端
-
服务器端
3.3 功能函数
- 客户端
- main函数
- log_in()
- re_account()
- menu()
- void*request()
- 线程中功能函数及辅助函数
- int file_size( char *filename );
- void s();
- void save_wenjian();
- void ask();
- void send_file();
- void group_chat();
- void del_friend();
- void person_chat();
- int denglu();
- void baocun( user *guy );
- void xiaoxi();
- main函数
- 服务器端
- main函数
- user_process()
- epoll_sock(int sock_fd)
- 线程中功能函数及辅助函数
- int u_exist(user * people);
- int g_exist(user* people);
- void show_group(int conn_fd);
- void get_alljgroup();
- void member_group( int conn_fd );
-int is_member(char* g_name); - void online_remind( char *number );
- void take_f_info();
- void offline_remind( char *number );
- void send_file();
- void ask( int conn_fd );
- void take_chatlog( int conn_fd );
- void save_talklog( user *people );
- void invite( user *people );
- void take_group();
- void group_chat();
- void save_log( char *number );
- void del_friend( char *number,char *nofri );
- void private_chat();
- void wenjian4( user *people );
- void wenjian3( user *people );
- void wenjian2( char *number );
- void wenjian1( char *number );
- void look_fri();
- void send_offline( int conn_fd );
- void take_offline( char *number );
- void off_line( user *people,char *number );
- int check_friend( char *number );
- int check_line( char *number );
- void take_friend( char *p );
- void save_friend( char *number,char *friend );
- void off_lines( int conn_fd );
- void reply( user *people );
- void take_out();
- int check_login( user *people,int conn_fd );
- int check_setin( user *people);
- void save();
- void add_friend( user *people,int conn_fd );
- void save_group(user* people);
- main函数
3.4 难点功能设计思路解析
- 加好友
有客户端1和客户端2,服务器,客户端1要加客户端2为好友,先向服务器发送请求,服务器根据客户端1发送的客户端2的用户名在在线用户链表中查找,是否存在该账号,如果找到客户端2的账号,就根据客户端2的套接字信息,向客户端2发送信息,客户端2这边收到消息,提醒他到消息中心(自定义的消息队列,用于存放各种请求和消息)查看添加好友信息。客户端2这边处理完后,再发送给服务器,服务器再根据客户端1的用户名查找其套接字信息,将结果返回给客户端1。这是在理想情况下,实现的加好友简单思路。
如果客户端在在线用户链表中没有找到用户信息,由于该项目中全用文件来持久化数据,所以,有个保存所有用户信息的文件,可以根据客户端2的用户名,在该文件中查找用户,如果存在的话,就将请求保存为客户端2对应的离线消息等其上线后,再进行通知。
如果在所有用户文件中并没有找到客户端2的信息,服务器就将结果直接返回给客户端1。
- 传文件
这一功能的思路和加好友流程大同小异,在此只提一下文件传输方法就行。项目中客户端与服务器之间的交互都是通过结构体传输信息的,所以在传输文件中,比如客户端1给客户端2传输文件数据,客户端1以读的方式打开文件,在一个while循环里面,每次发送长度为size的数据,客户端1每次以 写|创建文件|追加 的方式打开文件 ,每次写size长度的数据。这样就实现了文件传输的功能。其中输入的如果不是绝对路径,文件就存在当前目录下。否则就存在和客户端1发送的相同的绝对路径下。这样的文件传输有个问题,在传输过程中,不能干其他事,只能等到文件传完,在执行其他功能。还有就是传输过程中,要是传输方掉线,表示传输失败。只能有从头再传(即不能实现断点续传)。
- 私聊
私聊的前提必须是,要聊的对象必须存在,必须为自己的好友。客户端1将消息发送给服务器,服务器同样在在线用户链表中检查对象用户是否在线,不在线的话,村委对象用户的离线消息。在线的话,就根据对象用户的套接字将数据包发给对象用户,在在线用户这边用标志设置判断用户是否处于私聊状态,不处于私聊状态,就用消息队列将消息保存,并提醒该用户到消息盒子查看私聊消息。否则的话,就将私聊消息打印在屏幕上。下面流程和以上所讲差不多。
- 群聊
包括创建群,已建群列表显示,邀请群成员,群成员显示,群聊,解散群,已加入的群聊显示。
群聊和私聊大同小异,只是在服务器端,将所有群成员信息用链表收集起来,再遍历链表将消息逐个发给群成员。
邀请好友进群,要输入群账号,邀请人账号,服务器要查对应群聊是否存在,输入用户是否存在,被邀用户是否为当前用户的好友,如果是好友,就不需要好友同意直接能拉进群。如果要经过同意,流程和加好友差不多。被邀用户可通过查看已加入的群来看自己所近的群聊。
4.文件说明
文件名 | 功能描述 |
---|---|
all_user | 存放所有用户信息 |
all_group | 存放所有群信息 |
群聊名称+group | 存放群聊信息 |
chat-log | 存放用户聊天记录 |
###5.项目部分功能截图
- 加好友
-
私聊界面
-
群聊界面
-
聊天记录
-
文件传输(用结构体每次定长发送,不能实现是断点续传)
所传过的文件最大为5mb,ppt文件
6.容错处理
没有采用系统调用errno,如果出错,就用printf将错误的地方打印显示出来,提醒用户。
7.已知存在的问题
没有屏蔽群,群成员禁言等功能。要好友加群不经过对方同意就将对方邀请到群中,不是很又好,删除好友这一边删除了,好友的好友列表中还存在用户的用户名。文件传输还传不了目录文件,没有实现断点续传。