采用Client/Server架构,可以同时连接5个用户,每个用户最多可以拥有20个好友,最多可以加10个群聊,文件传输的限制字节为4096,缓存机制消息最大为50,在这些限制之内可以实现如下功能:
注册(用户名不重复):选择注册功能,输入账号密码,即可进行账号注册。登录(单个用户登录,密码输入不可见):用户登录时,输入账号和密码,与服务端储存的信息进行匹配,匹配成功即可登录,匹配失败显示错误信息。注销(无需再次运行程序便可登录):在功能菜单中可以退出登录。私聊(仅能对好友进行):用户选择私聊功能后,提示输入用户想要私聊的另一个用户名,然后提示要发送的消息,用户输入后,显示消息发送,处理成功后消息发送到目标用户。目标用户会接受的此消息。群聊(只能对所在群组进行):用户选择群聊功能后,提示输入用户想要发起群聊的群组名称,然后提示要发送的消息,用户输入后,显示消息发送,处理成功后消息发送到目标群聊用户。群聊的目标用户均会收到此消息。聊天记录查询(只能获取好友和所在群组的):聊天记录保存在特定的文件中,可以查看私聊、群聊聊天记录。用户选择查看聊天记录功能后,提示输入用户想要查看得聊天记录文件的名称,用户输入后,即可打开聊天信息文件,查看聊天记录。文件传输(简易版shell寻找文件,分群组和私聊文件传输):可以向好友发送指定文件。用户选择查看文件传输功能后,提示输入用户想要发送文件的另一个用户名,用户输入后,提示用户想要发送文件的文件名称,输入文件名后即可发送。接受方收到文件后,会将此文件保存在特定的文件夹中。服务端消息和文件传输缓存机制:缓存好友和群组发送的离线文件和消息,待该用户登陆后由服务器返回历史消息。【1】client端输入用户名和密码 -> 存于消息结构体mess中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户名密码的文件(server/data/user.txt) -> 验证文件中是否已存在该信息 -> 若无,将用户信息存入文件 ->返回注册消息(已存在该用户,重新注册||注册成功)。 2.2登录 【1】client端输入用户名和密码 -> 存于结构体中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户名密码的文件(server/data/user.txt) -> 读取文件验证用户信息。 【3】server端匹配正确发送“登陆成功!”消息,匹配失败根据输入的内容判定提示(“密码错误!”、“用户名不存在,请注册新用户”、“用户已登录,请勿重复登录”)消息 -> client端接收,“登陆成功!”则进入功能菜单,其余则继续循环注册登录的菜单。 【4】若验证成功,server端产生一个新的套接字newfd,将它与用户名封装于同一个结构体中,存储在线用户的信息。将用户信息存入链表中,表示为在线用户。 消息、存储在线用户信息结构体:
Client Server消息结构体 (all.h)
【1】client端后台发送好友列表请求信息 -> 存于结构体中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户好友信息的文件(server/data/friends/用户名.txt) -> 读取文件返回好友信息。 【3】client端接收server发送的结构体 -> 分离线程处理打印传输回来的好友信息。 【4】client端将发送好友对象和消息内容-> 存入发送的结构体中 -> 将结构体发送给server端。 【5】server端接收client发送的结构体 -> 根据接收者名字在online的链表中查找套接字描述符(若不在线将消息和日志信息存入服务端,待接受者登陆后将消息转发) -> 将消息发送给该接收者client端。 【6】client端接收server发送的结构体 -> 分离线程处理打印传输回来的好友消息。
【1】client端后台发送群组列表请求信息 -> 存于结构体中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户群组信息的文件遍历查找该用户所在的群组(server/data/groups/group*.txt)-> 返回群组信息。 【3】client端接收server发送的结构体 -> 分离线程处理打印传输回来的群组信息。 【4】client端将发送群组对象和消息内容-> 存入发送的结构体中 -> 将结构体发送给server端。 【5】server端接收client发送的结构体 -> 根据群组所有接收者名字在online的链表中查找套接字描述符(若不在线将消息和日志信息存入服务端,待接受者登陆后将消息转发) -> 将消息存入消息结构体发送给该接收者client端。 【6】client端接收server发送的结构体 -> 分离线程处理打印传输回来的群组消息。
【1】client端选择文件传输对象的类型(friend||group),后台发送所选类型列表请求信息 -> 存于结构体中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户群组(好友)信息的文件遍历查找该用户所在的群组(好友)(server/data/groups/group*.txt||server/friends/用户名.txt)-> 返回群组||好友信息。 【3】client端接收server发送的结构体 -> 分离线程处理打印传输回来的群组||好友信息。 【4】client端将查询对象(群组||好友)-> 存入发送的结构体中 -> 将结构体发送给server端。 【5】server端接收client发送的结构体 -> 根据查询对象读取server端的消息记录文件(server/records/groupchat/group*.txt|| server/records/ privatechat /用户1_用户2(根据字符串大小排序).txt) -> 将文件内容存入消息结构体发送给该接收者client端。 【6】client端接收server发送的结构体 -> 分离线程处理打印(保存)传输回来的群组消息(文件)。
【1】client端选择文件传输对象的类型(friend||group),后台发送所选类型列表请求信息 -> 存于结构体中 -> 将结构体发送给server端。 【2】server端接收client发送的结构体 -> 打开存储用户群组(好友)信息的文件遍历查找该用户所在的群组(好友)(server/data/groups/group*.txt||server/data/friends/用户名.txt)-> 返回群组||好友信息。 【3】client端接收server发送的结构体 -> 分离线程处理打印传输回来的群组||好友信息。 【4】client端将发送对象(群组||好友),简易shell读取发送文件的路径和内容 -> 存入发送的结构体中 -> 将结构体发送给server端。 【5】server端接收client发送的结构体 -> 根据群组所有接收者名字(好友的名字)在online的链表中查找套接字描述符(若不在线将消息和日志信息存入服务端,待接受者登陆后将消息转发) -> 将消息发送给该接收者client端。 【6】client端接收server发送的结构体 -> 分离线程处理打印(保存)传输回来的群组消息(文件:保存在特定的文件夹中)。
代码较多,感兴趣的同学可以点击链接下载(https://download.csdn.net/download/lzj_feifei/12575318)。
聊天室的底层参考的第一位博主的代码,文件传输的简易shell参考的第二位博主的代码(后续补上,有点找不到了,如果是博主看到的话请联系我给您加上):
准备过程之中有些许的失误,过于重视逻辑功能的完备性,忽视了界面的制作的重要性,不占视觉的优势。基础的功能调试花费了过长时间,后面部分功能(会用到前面功能的部分:服务端离线消息处理调用私聊的函数)应该单拉出来写函数,调用之前函数比较混乱,导致功能和bug修改困难,但是其余部分功能都完成的比较顺利。 再就是对软件的应用存在一定的意识缺乏,仅将Clion作为写代码的工具,没有充分利用DeBug功能;起初有过将界面和浏览器网页融合和云服务器运行服务端以及功能设计特色等想法,但也只是停留在了最后的功能设计上,总之只要有想法,并付出实践,想法就可以实现,这就是编程的魅力所在。