├── .gitattributes
├── .gitignore
├── README.md
├── chat_client_code
├── addfriend.cpp
├── addfriend.h
├── addfriend.ui
├── addgroup.cpp
├── addgroup.h
├── addgroup.ui
├── chat_server.sln
├── chat_soft.pro
├── chatlist.cpp
├── chatlist.h
├── chatlist.ui
├── creategroup.cpp
├── creategroup.h
├── creategroup.ui
├── groupchat.cpp
├── groupchat.h
├── groupchat.ui
├── main.cpp
├── privatechat.cpp
├── privatechat.h
├── privatechat.ui
├── recvthread.cpp
├── recvthread.h
├── sendthread.cpp
├── sendthread.h
├── widget.cpp
├── widget.h
└── widget.ui
├── chat_database.cpp
├── chat_database.h
├── chat_server_project.sln
├── chat_server_project.vcxproj
├── chatlist.cpp
├── chatlist.h
├── main.cpp
├── myassets
├── image-20220912180434913.png
└── image-20220912180641606.png
├── server.cpp
├── server.h
├── 在阿里云服务器上搭建开发环境.txt
├── 服务器与客户端接口文档.txt
└── 测试客户端.c
/.gitattributes:
--------------------------------------------------------------------------------
1 | # liuzhensen 2022/8/3
2 | ###############################################################################
3 | # Set default behavior to automatically normalize line endings.
4 | ###############################################################################
5 | * text=auto
6 |
7 | ###############################################################################
8 | # Set default behavior for command prompt diff.
9 | #
10 | # This is need for earlier builds of msysgit that does not have it on by
11 | # default for csharp files.
12 | # Note: This is only used by command line
13 | ###############################################################################
14 | #*.cs diff=csharp
15 |
16 | ###############################################################################
17 | # Set the merge driver for project and solution files
18 | #
19 | # Merging from the command prompt will add diff markers to the files if there
20 | # are conflicts (Merging from VS is not affected by the settings below, in VS
21 | # the diff markers are never inserted). Diff markers may cause the following
22 | # file extensions to fail to load in VS. An alternative would be to treat
23 | # these files as binary and thus will always conflict and require user
24 | # intervention with every merge. To do so, just uncomment the entries below
25 | ###############################################################################
26 | #*.sln merge=binary
27 | #*.csproj merge=binary
28 | #*.vbproj merge=binary
29 | #*.vcxproj merge=binary
30 | #*.vcproj merge=binary
31 | #*.dbproj merge=binary
32 | #*.fsproj merge=binary
33 | #*.lsproj merge=binary
34 | #*.wixproj merge=binary
35 | #*.modelproj merge=binary
36 | #*.sqlproj merge=binary
37 | #*.wwaproj merge=binary
38 |
39 | ###############################################################################
40 | # behavior for image files
41 | #
42 | # image files are treated as binary by default.
43 | ###############################################################################
44 | #*.jpg binary
45 | #*.png binary
46 | #*.gif binary
47 |
48 | ###############################################################################
49 | # diff behavior for common document formats
50 | #
51 | # Convert binary document formats to text before diffing them. This feature
52 | # is only available from the command line. Turn it on by uncommenting the
53 | # entries below.
54 | ###############################################################################
55 | #*.doc diff=astextplain
56 | #*.DOC diff=astextplain
57 | #*.docx diff=astextplain
58 | #*.DOCX diff=astextplain
59 | #*.dot diff=astextplain
60 | #*.DOT diff=astextplain
61 | #*.pdf diff=astextplain
62 | #*.PDF diff=astextplain
63 | #*.rtf diff=astextplain
64 | #*.RTF diff=astextplain
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 | ## liuzhensen 2022/8/3
6 |
7 | # User-specific files
8 | *.rsuser
9 | *.suo
10 | *.user
11 | *.userosscache
12 | *.sln.docstates
13 |
14 | # User-specific files (MonoDevelop/Xamarin Studio)
15 | *.userprefs
16 |
17 | # Build results
18 | [Dd]ebug/
19 | [Dd]ebugPublic/
20 | [Rr]elease/
21 | [Rr]eleases/
22 | x64/
23 | x86/
24 | [Aa][Rr][Mm]/
25 | [Aa][Rr][Mm]64/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015/2017 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # Visual Studio 2017 auto generated files
37 | Generated\ Files/
38 |
39 | # MSTest test Results
40 | [Tt]est[Rr]esult*/
41 | [Bb]uild[Ll]og.*
42 |
43 | # NUNIT
44 | *.VisualState.xml
45 | TestResult.xml
46 |
47 | # Build Results of an ATL Project
48 | [Dd]ebugPS/
49 | [Rr]eleasePS/
50 | dlldata.c
51 |
52 | # Benchmark Results
53 | BenchmarkDotNet.Artifacts/
54 |
55 | # .NET Core
56 | project.lock.json
57 | project.fragment.lock.json
58 | artifacts/
59 |
60 | # StyleCop
61 | StyleCopReport.xml
62 |
63 | # Files built by Visual Studio
64 | *_i.c
65 | *_p.c
66 | *_h.h
67 | *.ilk
68 | *.meta
69 | *.obj
70 | *.iobj
71 | *.pch
72 | *.pdb
73 | *.ipdb
74 | *.pgc
75 | *.pgd
76 | *.rsp
77 | *.sbr
78 | *.tlb
79 | *.tli
80 | *.tlh
81 | *.tmp
82 | *.tmp_proj
83 | *_wpftmp.csproj
84 | *.log
85 | *.vspscc
86 | *.vssscc
87 | .builds
88 | *.pidb
89 | *.svclog
90 | *.scc
91 |
92 | # Chutzpah Test files
93 | _Chutzpah*
94 |
95 | # Visual C++ cache files
96 | ipch/
97 | *.aps
98 | *.ncb
99 | *.opendb
100 | *.opensdf
101 | *.sdf
102 | *.cachefile
103 | *.VC.db
104 | *.VC.VC.opendb
105 |
106 | # Visual Studio profiler
107 | *.psess
108 | *.vsp
109 | *.vspx
110 | *.sap
111 |
112 | # Visual Studio Trace Files
113 | *.e2e
114 |
115 | # TFS 2012 Local Workspace
116 | $tf/
117 |
118 | # Guidance Automation Toolkit
119 | *.gpState
120 |
121 | # ReSharper is a .NET coding add-in
122 | _ReSharper*/
123 | *.[Rr]e[Ss]harper
124 | *.DotSettings.user
125 |
126 | # JustCode is a .NET coding add-in
127 | .JustCode
128 |
129 | # TeamCity is a build add-in
130 | _TeamCity*
131 |
132 | # DotCover is a Code Coverage Tool
133 | *.dotCover
134 |
135 | # AxoCover is a Code Coverage Tool
136 | .axoCover/*
137 | !.axoCover/settings.json
138 |
139 | # Visual Studio code coverage results
140 | *.coverage
141 | *.coveragexml
142 |
143 | # NCrunch
144 | _NCrunch_*
145 | .*crunch*.local.xml
146 | nCrunchTemp_*
147 |
148 | # MightyMoose
149 | *.mm.*
150 | AutoTest.Net/
151 |
152 | # Web workbench (sass)
153 | .sass-cache/
154 |
155 | # Installshield output folder
156 | [Ee]xpress/
157 |
158 | # DocProject is a documentation generator add-in
159 | DocProject/buildhelp/
160 | DocProject/Help/*.HxT
161 | DocProject/Help/*.HxC
162 | DocProject/Help/*.hhc
163 | DocProject/Help/*.hhk
164 | DocProject/Help/*.hhp
165 | DocProject/Help/Html2
166 | DocProject/Help/html
167 |
168 | # Click-Once directory
169 | publish/
170 |
171 | # Publish Web Output
172 | *.[Pp]ublish.xml
173 | *.azurePubxml
174 | # Note: Comment the next line if you want to checkin your web deploy settings,
175 | # but database connection strings (with potential passwords) will be unencrypted
176 | *.pubxml
177 | *.publishproj
178 |
179 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
180 | # checkin your Azure Web App publish settings, but sensitive information contained
181 | # in these scripts will be unencrypted
182 | PublishScripts/
183 |
184 | # NuGet Packages
185 | *.nupkg
186 | # The packages folder can be ignored because of Package Restore
187 | **/[Pp]ackages/*
188 | # except build/, which is used as an MSBuild target.
189 | !**/[Pp]ackages/build/
190 | # Uncomment if necessary however generally it will be regenerated when needed
191 | #!**/[Pp]ackages/repositories.config
192 | # NuGet v3's project.json files produces more ignorable files
193 | *.nuget.props
194 | *.nuget.targets
195 |
196 | # Microsoft Azure Build Output
197 | csx/
198 | *.build.csdef
199 |
200 | # Microsoft Azure Emulator
201 | ecf/
202 | rcf/
203 |
204 | # Windows Store app package directories and files
205 | AppPackages/
206 | BundleArtifacts/
207 | Package.StoreAssociation.xml
208 | _pkginfo.txt
209 | *.appx
210 |
211 | # Visual Studio cache files
212 | # files ending in .cache can be ignored
213 | *.[Cc]ache
214 | # but keep track of directories ending in .cache
215 | !?*.[Cc]ache/
216 |
217 | # Others
218 | ClientBin/
219 | ~$*
220 | *~
221 | *.dbmdl
222 | *.dbproj.schemaview
223 | *.jfm
224 | *.pfx
225 | *.publishsettings
226 | orleans.codegen.cs
227 |
228 | # Including strong name files can present a security risk
229 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
230 | #*.snk
231 |
232 | # Since there are multiple workflows, uncomment next line to ignore bower_components
233 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
234 | #bower_components/
235 |
236 | # RIA/Silverlight projects
237 | Generated_Code/
238 |
239 | # Backup & report files from converting an old project file
240 | # to a newer Visual Studio version. Backup files are not needed,
241 | # because we have git ;-)
242 | _UpgradeReport_Files/
243 | Backup*/
244 | UpgradeLog*.XML
245 | UpgradeLog*.htm
246 | ServiceFabricBackup/
247 | *.rptproj.bak
248 |
249 | # SQL Server files
250 | *.mdf
251 | *.ldf
252 | *.ndf
253 |
254 | # Business Intelligence projects
255 | *.rdl.data
256 | *.bim.layout
257 | *.bim_*.settings
258 | *.rptproj.rsuser
259 | *- Backup*.rdl
260 |
261 | # Microsoft Fakes
262 | FakesAssemblies/
263 |
264 | # GhostDoc plugin setting file
265 | *.GhostDoc.xml
266 |
267 | # Node.js Tools for Visual Studio
268 | .ntvs_analysis.dat
269 | node_modules/
270 |
271 | # Visual Studio 6 build log
272 | *.plg
273 |
274 | # Visual Studio 6 workspace options file
275 | *.opt
276 |
277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
278 | *.vbw
279 |
280 | # Visual Studio LightSwitch build output
281 | **/*.HTMLClient/GeneratedArtifacts
282 | **/*.DesktopClient/GeneratedArtifacts
283 | **/*.DesktopClient/ModelManifest.xml
284 | **/*.Server/GeneratedArtifacts
285 | **/*.Server/ModelManifest.xml
286 | _Pvt_Extensions
287 |
288 | # Paket dependency manager
289 | .paket/paket.exe
290 | paket-files/
291 |
292 | # FAKE - F# Make
293 | .fake/
294 |
295 | # JetBrains Rider
296 | .idea/
297 | *.sln.iml
298 |
299 | # CodeRush personal settings
300 | .cr/personal
301 |
302 | # Python Tools for Visual Studio (PTVS)
303 | __pycache__/
304 | *.pyc
305 |
306 | # Cake - Uncomment if you are using it
307 | # tools/**
308 | # !tools/packages.config
309 |
310 | # Tabs Studio
311 | *.tss
312 |
313 | # Telerik's JustMock configuration file
314 | *.jmconfig
315 |
316 | # BizTalk build output
317 | *.btp.cs
318 | *.btm.cs
319 | *.odx.cs
320 | *.xsd.cs
321 |
322 | # OpenCover UI analysis results
323 | OpenCover/
324 |
325 | # Azure Stream Analytics local run output
326 | ASALocalRun/
327 |
328 | # MSBuild Binary and Structured Log
329 | *.binlog
330 |
331 | # NVidia Nsight GPU debugger configuration file
332 | *.nvuser
333 |
334 | # MFractors (Xamarin productivity tool) working folder
335 | .mfractor/
336 |
337 | # Local History for Visual Studio
338 | .localhistory/
339 |
340 | # BeatPulse healthcheck temp database
341 | healthchecksdb
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## chat-software
2 | > 项目框架
3 |
4 |
5 |
6 | > 项目难点及解决办法
7 |
8 | - 使用**加盐`salt`+哈希加密**解决**用户注册、登录时的密码泄露**的问题;
9 | - 使用**多线程**解决**文件传输造成高并发下聊天事件堵塞及传输数据丢失**的问题
10 |
11 | > 项目介绍
12 |
13 | - 基于阿里云服务器+libevent+qt+mysql+Json等实现仿qq聊天软件,主要功能包括注册、登录、添加好友、聊天(私聊和群聊)、文件传输、建群、加群、好友上下线提醒。
14 |
15 | - 主要分为两大部分:
16 | - 第一,在linux上实现服务器端chat_server开发
17 | - 第二,在qt上实现客户端chat_client开发
18 |
19 | ## 1. chat_server
20 |
21 | ### 1.1 配置服务器端开发环境
22 |
23 | 购买阿里云服务器,配置环境,详见文件——在阿里云服务器上搭建开发环境.txt
24 |
25 | ### 1.2 创建服务器与客户端接口文档
26 |
27 | 首先创建一个满足Json数据格式的服务器与客户端传输信息或者交互接口文档,方便查看重要信息且有助于接下来实现各种功能。详见文件——服务器与客户端接口文档.txt
28 |
29 | ### 1.3 封装数据库类和链表类,用于存储用户和群聊信息
30 |
31 | 在mysql中,创建user和chatgroup两个数据库,
32 | 其中user存储用户信息,为一个用户创建一个表名为用户名的表,表中包含用户的密码password、friend好友、groupchat所在群聊
33 | chatgroup存储群聊信息,为每个群聊创建一张表名为群聊名的表,表中包含群聊的群主owner、群聊成员member
34 |
35 | 
36 |
37 | 创建online_user和group_info两个链表————————链表访问速度比数据库快,且方便后续功能的实现
38 | 其中,online_user存储在线用户的信息,节点为,包括在线用户名和在线用户的缓冲区对象bev;
39 | group_info存储群聊信息,节点为,包括群聊名称和群成员链表,其中群成员链表的节点为,只包含群成员姓名
40 |
41 | 
42 |
43 | ### 1.4 封装一个服务器类class Server
44 |
45 | 首先初始化服务器,使其可以监听待连接的客户端:在Server的构造函数中,基于libevent创建事件集合,创建并绑定监听对象,设置监听队列的长度,即最多同时与多少客户端建立TCP连接,开始循环监听,一旦有客户端发起连接,则调用回调函数,在回调函数中创建工作线程来处理该客户端。在某一工作线程中,创建该连接客户端的事件集合,基于该事件集合创建bufferevent缓存区对象,给bufferevent设置回调函数,循环监听集合(监听客户端是否有数据发送过来),一旦从客户端读取到数据,调用回调函数,处理客户端发送的满足Json格式的数据,接下来根据解析到的不同”cmd“,实现服务器端不同的功能,比如注册功能对应server_register(bev, val)函数,当客户端退出或连接断开,释放该连接客户端的事件集合,该工作线程随之退出分离,释放资源。在Server的成员变量中,分别创建一个链表对象static ChatInfo* chatlist和一个数据库对象static ChatDataBase* chatdb,用于访问用户和群聊的相关信息。
46 |
47 | > Sever类
48 |
49 | 
50 |
51 | ### 1.5 实现注册功能
52 |
53 | server_register(bev, val); // 参数1为服务器与该客户端之间的缓存区对象,参数2为客户端发送的信息
54 |
55 | - 首先连接上user数据库,chatdb->my_database_connect("user");
56 |
57 | - 判断注册用户是否已经存在,chatdb->my_database_user_exist(val["user"].asString()))
58 |
59 | - 若已经存在,回复客户端注册失败;
60 |
61 | - 若不存在,执行以下函数,将注册用户的用户名和密码,加入到user数据库中;然后回复客户端注册成功。
62 |
63 | ```c++
64 | chatdb->my_database_user_password(val["user"].asString(), val["password"].asString());
65 | ```
66 |
67 | - 关闭user数据库,chatdb->my_database_disconnect();
68 |
69 | ### 1.6 实现用户登录功能
70 |
71 | - 首先连接上user数据库,最后再断开连接,同上,接下来涉及到访问user数据库,均需要这两步,不再赘述;
72 |
73 | - 判断登录用户是否已经存在于user数据库中:
74 |
75 | - 若不存在,回复客户端该登录用户不存在;
76 |
77 | - 若存在,判断用户登录密码是否正确:
78 |
79 | ```c++
80 | chatdb->my_database_password_correct(val["user"].asString(),
81 | val["password"].asString()
82 | ```
83 |
84 | - 若不正确,回复客户端,输入登录失败,密码不正确,将登录函数结束掉return
85 |
86 | - 若正确:
87 |
88 | - 向在线用户链表中加入该登录用户,chatlist->online_user->push_back(u);
89 |
90 | - 获取该登录用户好友friend_list和群聊列表group_list并且返回给客户端,便于qt客户端开发时,显示登录用户的好友和群聊列表,以实现接下来的好友上线提醒、聊天等功能;
91 |
92 | ```
93 | chatdb->my_database_get_friend_group(val["user"].asString(), friend_list, group_list)
94 | ```
95 |
96 | - 登录成功后,向该登录用户的所有在线好友,发送自己上线的提醒:遍历friend_list,与 chatlist->online_user的一一匹配,若某好友在线,则向其bev/客户端发送自己上线的提醒
97 |
98 | ### 1.7 实现添加好友功能
99 |
100 | - 首先判断用户user——小明将要添加的好友friend小华——是否存在于用户数据库中
101 |
102 | - 若不存在,回复用户小明,你要添加的好友小华不存在,添加好友操作结束return
103 |
104 | - 若存在,再判断两人是否已经是好友关系
105 |
106 | ```c++
107 | chatdb->my_database_is_friend(val["user"].asString(), val["friend"].asString())
108 | ```
109 |
110 | - 若已经是好友关系,回复用户小明,你与添加的好友小华已经是好友关系,添加好友操作结束return
111 |
112 | - 若还不是好友关系:
113 |
114 | - 修改双方的用户表的friend好友字符串,互相添加为好友(注意,此处未考虑好友验证通过的功能,后期优化再实现);
115 |
116 | ```c++
117 | chatdb->my_database_add_new_friend(val["user"].asString(), val["friend"].asString());
118 | chatdb->my_database_add_new_friend(val["friend"].asString(), val["user"].asString());
119 | ```
120 |
121 | - 回复执行添加好友的用户小明,添加好友成功
122 | - 遍历在线用户链表,判断添加的好友小华是否在线,若在线,回复小华,小明已将你添加为好友。
123 |
124 | ### 1.8 实现创建群聊功能
125 |
126 | * 首先连接上`chatgroup`数据库,使用结束再断开连接,接下来涉及到访问`chatgroup`数据库,均需要这两步,不再赘述;
127 |
128 | * 判断群是否已存在`chatdb->my_database_group_exist(val["group"].asString())`
129 |
130 | * 若已经存在,回复客户端用户,该群已存在
131 |
132 | * 若不存在,
133 |
134 | * 在`chatgroup`中创建该群聊,初始化群聊名,群主,群成员信息
135 |
136 | ```c++
137 | chatdb->my_database_add_new_group(val["group"].asString(), val["user"].asString())
138 | ```
139 |
140 | * 在`user`中,将新建群聊加入到创建该群聊用户的群聊字符串中
141 |
142 | ```c++
143 | chatdb->my_database_user_add_group(val["user"].asString(), val["group"].asString());
144 | ```
145 |
146 | * 将新建群聊加入到群信息链表中
147 |
148 | ```C++
149 | chatlist->info_add_new_group(val["group"].asString(), val["user"].asString());
150 | ```
151 |
152 | * 回复客户端用户,群聊创建成功
153 |
154 | ### 1.9 添加群聊 `server_add_group`
155 |
156 | * 首先判断该群聊是否存在于`chatgroup`数据库中
157 |
158 | * 如果不存在,回复客户端用户,你要添加的群聊不存在,`return`;
159 |
160 | * 如果存在,判断该用户是否已经在该群聊中,此时使用群聊信息链表,访问速度相比于数据库更快
161 |
162 | ```C++
163 | chatlist->info_user_in_group(val["group"].asString(), val["user"].asString())
164 | ```
165 |
166 | * 如果该用户已经存在于该群聊中,回复客户端用户,你已经存在于该群聊中,`return`;
167 |
168 | * 若不在该群聊中
169 |
170 | * 在`user`中,将该群聊加入到该用户的群聊字符串中;
171 |
172 | 在`chatgroup`中,将该用户加入到该群聊的群成员字符串中;
173 |
174 | * 修改群聊信息链表,将该用户加入到该群聊节点的群成员链表中;
175 |
176 | ```c++
177 | chatlist->info_group_add_user(val["group"].asString(), val["user"].asString());
178 | ```
179 |
180 | * 回复客户端用户,添加群聊成功
181 |
182 | ### 1.10 私聊 `server_private_chat`
183 |
184 | * 首先判断好友是否在线————遍历在线用户链表,获得其缓存区对象`to_bev`
185 |
186 | ```c++
187 | struct bufferevent* to_bev = chatlist->info_get_friend_bev(val["user_to"].asString());
188 | ```
189 |
190 | * 如果`NULL == to_bev`,说明好友不在线,回复发送方,return
191 | * 如果好友在线,将发送方用户缓存区对象bev中的内容val转换为字符串s,再转发给好友的缓存区对象to_bev,再回复发送方,私聊发送成功。
192 |
193 | ### 1.11 群聊 `server_group_chat`
194 |
195 | * 首先遍历群聊信息链表找到该群聊
196 | * 遍历该群聊的群成员链表
197 | * 遍历在线用户链表,找到每个群成员(包括发送方自己)的缓存区对象`to_bev`,若不为空,转发发送方的bev,最后回复发送方,群聊发送成功
198 |
199 | ### 1.12 获取群聊成员 `server_get_group_member`
200 |
201 | * 遍历群聊信息链表,获取某群聊的群聊成员字符串member,将其返回给调用该函数的客户端
202 |
203 | ```c++
204 | string member = chatlist->info_get_group_member(val["group"].asString());
205 | ```
206 |
207 | ### 1.13 用户下线 `server_user_offline`
208 |
209 | * 首先从用户在线链表`online_user`中删除该用户
210 | * 获取该用户好友friend_list
211 | * 向在线好友,发送该用户的下线提醒
212 |
213 | ### 1.14 发送文件 server_send_file
214 |
215 | * 首先判断对方是否在线
216 |
217 | * 若不在线,回复发送方,接收方不在线,return;
218 |
219 | * 若在线:
220 |
221 | * 启动新线程,创建文件服务器,处理该文件传输任务(不影响聊天等功能),引用方式获得发送方客户端和接收方客户端相对于文件服务器的fd
222 |
223 | ```c++
224 | thread send_file_thread(send_file_handler, val["length"].asInt(), port, &from_fd, &to_fd);
225 | ```
226 |
227 | * 将文件服务器端口号返回给发送客户端,发送客户端根据端口号向文件服务器发起连接;
228 |
229 | * 判断发送客户端连接文件服务器是否成功,文件服务器中的`accept()`一旦被执行,对应的`fd`就会被修改(传入时为0),设置最长连接时间为`10s`,即等待10秒之后,`from_fd<=0`,说明仍未连接成功,判定为连接超时,取消文件服务器所在的线程,返回发送客户端连接文件服务器超时;相同方法连接接收客户端与文件服务器。
230 |
231 | * 文件服务器一边从`*f_fd`接收,一边向`*t_fd`发送,文件发送结束后,关闭发送与接收客户端与文件服务器之间的描述字,关闭该文件服务器,线程分离,释放资源
232 |
233 | ``` c++
234 | send_file_thread.detach();
235 | ```
236 |
237 | ## 2. chat_client
238 | 未完待续......
239 |
240 |
241 |
242 |
243 |
244 |
--------------------------------------------------------------------------------
/chat_client_code/addfriend.cpp:
--------------------------------------------------------------------------------
1 | #include "addfriend.h"
2 | #include "ui_addfriend.h"
3 |
4 | Addfriend::Addfriend(QTcpSocket *s, QString u, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::Addfriend)
7 | {
8 | ui->setupUi(this);
9 | this->socket = s;
10 | userName = u;
11 | }
12 |
13 | Addfriend::~Addfriend()
14 | {
15 | delete ui;
16 | }
17 |
18 | void Addfriend::on_cancelButton_clicked()
19 | {
20 | this->close();
21 | }
22 |
23 | void Addfriend::on_addButton_clicked()
24 | {
25 | QString friendName = ui->lineEdit->text();
26 | QJsonObject obj;
27 | obj.insert("cmd", "add");
28 | obj.insert("user", userName);
29 | obj.insert("friend", friendName);
30 |
31 | QByteArray ba = QJsonDocument(obj).toJson();
32 | socket->write(ba);
33 |
34 | this->close();
35 | }
36 |
--------------------------------------------------------------------------------
/chat_client_code/addfriend.h:
--------------------------------------------------------------------------------
1 | #ifndef ADDFRIEND_H
2 | #define ADDFRIEND_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Ui {
10 | class Addfriend;
11 | }
12 |
13 | class Addfriend : public QWidget
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit Addfriend(QTcpSocket *s, QString u, QWidget *parent = 0);
19 | ~Addfriend();
20 |
21 | private slots:
22 | void on_cancelButton_clicked();
23 |
24 | void on_addButton_clicked();
25 |
26 | private:
27 | Ui::Addfriend *ui;
28 | QTcpSocket *socket;
29 | QString userName;
30 | };
31 |
32 | #endif // ADDFRIEND_H
33 |
--------------------------------------------------------------------------------
/chat_client_code/addfriend.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Addfriend
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 210
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 90
20 | 50
21 | 71
22 | 31
23 |
24 |
25 |
26 | <html><head/><body><p align="center"><span style=" font-size:12pt;">好友账号</span></p></body></html>
27 |
28 |
29 |
30 |
31 |
32 | 170
33 | 50
34 | 151
35 | 31
36 |
37 |
38 |
39 |
40 |
41 |
42 | 90
43 | 120
44 | 75
45 | 23
46 |
47 |
48 |
49 | 取消
50 |
51 |
52 |
53 |
54 |
55 | 220
56 | 120
57 | 75
58 | 23
59 |
60 |
61 |
62 | 添加
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/chat_client_code/addgroup.cpp:
--------------------------------------------------------------------------------
1 | #include "addgroup.h"
2 | #include "ui_addgroup.h"
3 |
4 | AddGroup::AddGroup(QTcpSocket *s, QString u, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::AddGroup)
7 | {
8 | ui->setupUi(this);
9 | socket = s;
10 | userName = u;
11 | }
12 |
13 | AddGroup::~AddGroup()
14 | {
15 | delete ui;
16 | }
17 |
18 | void AddGroup::on_cancelButton_clicked()
19 | {
20 | this->close();
21 | }
22 |
23 | void AddGroup::on_addButton_clicked()
24 | {
25 | QString groupName = ui->lineEdit->text();
26 | QJsonObject obj;
27 | obj.insert("cmd", "add_group");
28 | obj.insert("user", userName);
29 | obj.insert("group", groupName);
30 | QByteArray ba = QJsonDocument(obj).toJson();
31 | socket->write(ba);
32 | this->close();
33 | }
34 |
--------------------------------------------------------------------------------
/chat_client_code/addgroup.h:
--------------------------------------------------------------------------------
1 | #ifndef ADDGROUP_H
2 | #define ADDGROUP_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Ui {
10 | class AddGroup;
11 | }
12 |
13 | class AddGroup : public QWidget
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit AddGroup(QTcpSocket *s, QString u, QWidget *parent = 0);
19 | ~AddGroup();
20 |
21 | private slots:
22 | void on_cancelButton_clicked();
23 |
24 | void on_addButton_clicked();
25 |
26 | private:
27 | Ui::AddGroup *ui;
28 | QTcpSocket *socket;
29 | QString userName;
30 | };
31 |
32 | #endif // ADDGROUP_H
33 |
--------------------------------------------------------------------------------
/chat_client_code/addgroup.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | AddGroup
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 212
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 90
20 | 70
21 | 81
22 | 31
23 |
24 |
25 |
26 | <html><head/><body><p align="center"><span style=" font-size:12pt;">群名</span></p></body></html>
27 |
28 |
29 |
30 |
31 |
32 | 160
33 | 70
34 | 161
35 | 31
36 |
37 |
38 |
39 |
40 |
41 |
42 | 120
43 | 140
44 | 75
45 | 23
46 |
47 |
48 |
49 | 取消
50 |
51 |
52 |
53 |
54 |
55 | 230
56 | 140
57 | 75
58 | 23
59 |
60 |
61 |
62 | 添加
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/chat_client_code/chat_server.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30907.101
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chat_server", "chat_server.vcxproj", "{376D12C2-B058-4FDA-93B9-2C2F81C440AB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|ARM = Release|ARM
15 | Release|ARM64 = Release|ARM64
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.ActiveCfg = Debug|ARM
21 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.Build.0 = Debug|ARM
22 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.Deploy.0 = Debug|ARM
23 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.ActiveCfg = Debug|x64
27 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.Build.0 = Debug|x64
28 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.Deploy.0 = Debug|x64
29 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.ActiveCfg = Debug|x86
30 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.Build.0 = Debug|x86
31 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.Deploy.0 = Debug|x86
32 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.ActiveCfg = Release|ARM
33 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.Build.0 = Release|ARM
34 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.Deploy.0 = Release|ARM
35 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.ActiveCfg = Release|ARM64
36 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.Build.0 = Release|ARM64
37 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.Deploy.0 = Release|ARM64
38 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.ActiveCfg = Release|x64
39 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.Build.0 = Release|x64
40 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.Deploy.0 = Release|x64
41 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.ActiveCfg = Release|x86
42 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.Build.0 = Release|x86
43 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.Deploy.0 = Release|x86
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {EA6647A8-C091-45F0-8AFF-D0632C712335}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/chat_client_code/chat_soft.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2021-03-01T17:08:37
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui network
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = chat_soft
12 | TEMPLATE = app
13 |
14 | # The following define makes your compiler emit warnings if you use
15 | # any feature of Qt which as been marked as deprecated (the exact warnings
16 | # depend on your compiler). Please consult the documentation of the
17 | # deprecated API in order to know how to port your code away from it.
18 | DEFINES += QT_DEPRECATED_WARNINGS
19 |
20 | # You can also make your code fail to compile if you use deprecated APIs.
21 | # In order to do so, uncomment the following line.
22 | # You can also select to disable deprecated APIs only up to a certain version of Qt.
23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
24 |
25 |
26 | SOURCES += main.cpp\
27 | widget.cpp \
28 | chatlist.cpp \
29 | addfriend.cpp \
30 | creategroup.cpp \
31 | addgroup.cpp \
32 | privatechat.cpp \
33 | groupchat.cpp \
34 | sendthread.cpp \
35 | recvthread.cpp
36 |
37 | HEADERS += widget.h \
38 | chatlist.h \
39 | addfriend.h \
40 | creategroup.h \
41 | addgroup.h \
42 | privatechat.h \
43 | groupchat.h \
44 | sendthread.h \
45 | recvthread.h
46 |
47 | FORMS += widget.ui \
48 | chatlist.ui \
49 | addfriend.ui \
50 | creategroup.ui \
51 | addgroup.ui \
52 | privatechat.ui \
53 | groupchat.ui
54 |
--------------------------------------------------------------------------------
/chat_client_code/chatlist.cpp:
--------------------------------------------------------------------------------
1 | #include "chatlist.h"
2 | #include "ui_chatlist.h"
3 |
4 | Chatlist::Chatlist(QTcpSocket *s, QString fri, QString group, QString u, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::Chatlist)
7 | {
8 | ui->setupUi(this);
9 | userName = u;
10 | socket = s;
11 | connect(socket, &QTcpSocket::readyRead, this, &Chatlist::server_reply);
12 |
13 | QStringList friList = fri.split('|');
14 | for (int i = 0; i < friList.size(); i++)
15 | {
16 | if (friList.at(i) != "")
17 | {
18 | ui->friendList->addItem(friList.at(i));
19 | }
20 | }
21 |
22 | QStringList groList = group.split('|');
23 | for (int i = 0; i < groList.size(); i++)
24 | {
25 | if (groList.at(i) != "")
26 | {
27 | ui->groupList->addItem(groList.at(i));
28 | }
29 | }
30 |
31 | connect(ui->friendList, &QListWidget::itemDoubleClicked, this, &Chatlist::on_friendList_double_clicked);
32 | connect(ui->groupList, &QListWidget::itemDoubleClicked, this, &Chatlist::on_groupList_double_clicked);
33 | }
34 |
35 | Chatlist::~Chatlist()
36 | {
37 | delete ui;
38 | }
39 |
40 | void Chatlist::server_reply()
41 | {
42 | QByteArray ba = socket->readAll();
43 | QJsonObject obj = QJsonDocument::fromJson(ba).object();
44 | QString cmd = obj.value("cmd").toString();
45 | if (cmd == "friend_login")
46 | {
47 | client_login_reply(obj.value("friend").toString());
48 | }
49 | else if (cmd == "add_reply")
50 | {
51 | client_add_friend_reply(obj);
52 | }
53 | else if (cmd == "add_friend_reply")
54 | {
55 | QString str = QString("%1把你添加为好友").arg(obj.value("result").toString());
56 | QMessageBox::information(this, "添加好友提醒", str);
57 | ui->friendList->addItem(obj.value("result").toString());
58 | }
59 | else if (cmd == "create_group_reply")
60 | {
61 | client_create_group_reply(obj);
62 | }
63 | else if (cmd == "add_group_reply")
64 | {
65 | client_add_group_reply(obj);
66 | }
67 | else if (cmd == "private_chat_reply")
68 | {
69 | client_private_chat_reply(obj.value("result").toString());
70 | }
71 | else if (cmd == "private_chat")
72 | {
73 | client_chat_reply(obj);
74 | }
75 | else if (cmd == "get_group_member_reply")
76 | {
77 | client_get_group_member_reply(obj);
78 | }
79 | else if (cmd == "group_chat")
80 | {
81 | client_group_chat_reply(obj);
82 | }
83 | else if (cmd == "send_file_reply")
84 | {
85 | client_send_file_reply(obj.value("result").toString());
86 | }
87 | else if (cmd == "send_file_port_reply")
88 | {
89 | client_send_file_port_reply(obj);
90 | }
91 | else if (cmd == "recv_file_port_reply")
92 | {
93 | client_recv_file_port_reply(obj);
94 | }
95 | else if (cmd == "friend_offline")
96 | {
97 | client_friend_offline(obj.value("friend").toString());
98 | }
99 | }
100 |
101 | void Chatlist::client_login_reply(QString fri)
102 | {
103 | QString str = QString("%1好友上线").arg(fri);
104 | QMessageBox::information(this, "好友上线提醒", str);
105 | }
106 |
107 | void Chatlist::client_add_friend_reply(QJsonObject &obj)
108 | {
109 | if (obj.value("result").toString() == "user_not_exist")
110 | {
111 | QMessageBox::warning(this, "添加好友提醒", "好友不存在");
112 | }
113 | else if (obj.value("result").toString() == "already_friend")
114 | {
115 | QMessageBox::warning(this, "添加好友提醒", "已经是好友关系");
116 | }
117 | else if (obj.value("result").toString() == "success")
118 | {
119 | QMessageBox::information(this, "添加好友提醒", "好友添加成功");
120 | ui->friendList->addItem(obj.value("friend").toString());
121 | }
122 | }
123 |
124 | void Chatlist::client_create_group_reply(QJsonObject &obj)
125 | {
126 | if (obj.value("result").toString() == "group_exist")
127 | {
128 | QMessageBox::warning(this, "创建群提示", "群已经存在");
129 | }
130 | else if (obj.value("result").toString() == "success")
131 | {
132 | ui->groupList->addItem(obj.value("group").toString());
133 | }
134 | }
135 |
136 | void Chatlist::client_add_group_reply(QJsonObject &obj)
137 | {
138 | if (obj.value("result").toString() == "group_not_exist")
139 | {
140 | QMessageBox::warning(this, "添加群提示", "群不存在");
141 | }
142 | else if (obj.value("result").toString() == "user_in_group")
143 | {
144 | QMessageBox::warning(this, "添加群提示", "已经在群里面");
145 | }
146 | else if (obj.value("result").toString() == "success")
147 | {
148 | ui->groupList->addItem(obj.value("group").toString());
149 | }
150 | }
151 |
152 | void Chatlist::client_private_chat_reply(QString res)
153 | {
154 | if (res == "offline")
155 | {
156 | QMessageBox::warning(this, "发送提醒", "对方不在线");
157 | }
158 | }
159 |
160 | void Chatlist::client_chat_reply(QJsonObject &obj)
161 | {
162 | int flag = 0;
163 | for (int i = 0; i < chatWidgetList.size(); i++)
164 | {
165 | if (chatWidgetList.at(i).name == obj.value("user_from").toString())
166 | {
167 | flag = 1;
168 | break;
169 | }
170 | }
171 |
172 | if (flag == 0) //聊天窗口没有打开过
173 | {
174 | QString friendName = obj.value("user_from").toString();
175 | PrivateChat *privateChatWidget = new PrivateChat(socket, userName, friendName, this, &chatWidgetList);
176 | privateChatWidget->setWindowTitle(friendName);
177 | privateChatWidget->show();
178 |
179 | ChatWidgetInfo c = {privateChatWidget, friendName};
180 | chatWidgetList.push_back(c);
181 | }
182 |
183 | emit signal_to_sub_widget(obj);
184 | }
185 |
186 | void Chatlist::client_get_group_member_reply(QJsonObject obj)
187 | {
188 | emit signal_to_sub_widget_member(obj);
189 | }
190 |
191 | void Chatlist::client_group_chat_reply(QJsonObject obj)
192 | {
193 | int flag = 0;
194 | for (int i = 0; i < groupWidgetList.size(); i++)
195 | {
196 | if (groupWidgetList.at(i).name == obj.value("group").toString())
197 | {
198 | flag = 1;
199 | break;
200 | }
201 | }
202 |
203 | if(flag == 0)
204 | {
205 | QString groupName = obj.value("group").toString();
206 | GroupChat *groupChatWidget = new GroupChat(socket, groupName, userName, this, &groupWidgetList);
207 | groupChatWidget->setWindowTitle(groupName);
208 | groupChatWidget->show();
209 |
210 | groupWidgetInfo g = {groupChatWidget, groupName};
211 | groupWidgetList.push_back(g);
212 | }
213 |
214 | emit signal_to_sub_widget_group(obj);
215 | }
216 |
217 | void Chatlist::client_send_file_reply(QString res)
218 | {
219 | if (res == "offline")
220 | {
221 | QMessageBox::warning(this, "发送文件提醒", "对方不在线");
222 | }
223 | else if (res == "timeout")
224 | {
225 | QMessageBox::warning(this, "发送文件提醒", "连接超时");
226 | }
227 | }
228 |
229 | void Chatlist::client_send_file_port_reply(QJsonObject obj)
230 | {
231 | SendThread *mySendthread = new SendThread(obj);
232 | mySendthread->start();
233 | }
234 |
235 | void Chatlist::client_recv_file_port_reply(QJsonObject obj)
236 | {
237 | RecvThread *myRecvThread = new RecvThread(obj);
238 | myRecvThread->start();
239 | }
240 |
241 | void Chatlist::client_friend_offline(QString fri)
242 | {
243 | QString str = QString("%1下线").arg(fri);
244 | QMessageBox::information(this, "下线提醒", str);
245 | }
246 |
247 | void Chatlist::on_addButton_clicked()
248 | {
249 | Addfriend *addFriendWidget = new Addfriend(socket, userName);
250 | addFriendWidget->show();
251 | }
252 |
253 | void Chatlist::on_createGroupButton_clicked()
254 | {
255 | CreateGroup *createGroupWidget = new CreateGroup(socket, userName);
256 | createGroupWidget->show();
257 | }
258 |
259 | void Chatlist::on_addGroupButton_clicked()
260 | {
261 | AddGroup *addGroupWidget = new AddGroup(socket, userName);
262 | addGroupWidget->show();
263 | }
264 |
265 | void Chatlist::on_friendList_double_clicked()
266 | {
267 | QString friendName = ui->friendList->currentItem()->text();
268 | PrivateChat *privateChatWidget = new PrivateChat(socket, userName, friendName, this, &chatWidgetList);
269 | privateChatWidget->setWindowTitle(friendName);
270 | privateChatWidget->show();
271 |
272 | ChatWidgetInfo c = {privateChatWidget, friendName};
273 | chatWidgetList.push_back(c);
274 | }
275 |
276 | void Chatlist::on_groupList_double_clicked()
277 | {
278 | QString groupName = ui->groupList->currentItem()->text();
279 | GroupChat *groupChatWidget = new GroupChat(socket, groupName, userName, this, &groupWidgetList);
280 | groupChatWidget->setWindowTitle(groupName);
281 | groupChatWidget->show();
282 |
283 | groupWidgetInfo g = {groupChatWidget, groupName};
284 | groupWidgetList.push_back(g);
285 | }
286 |
287 | void Chatlist::closeEvent(QCloseEvent *event)
288 | {
289 | QJsonObject obj;
290 | obj.insert("cmd", "offline");
291 | obj.insert("user", userName);
292 | QByteArray ba = QJsonDocument(obj).toJson();
293 | socket->write(ba);
294 | socket->flush();
295 |
296 | event->accept();
297 | }
298 |
--------------------------------------------------------------------------------
/chat_client_code/chatlist.h:
--------------------------------------------------------------------------------
1 | #ifndef CHATLIST_H
2 | #define CHATLIST_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "addfriend.h"
11 | #include "creategroup.h"
12 | #include "addgroup.h"
13 | #include "sendthread.h"
14 | #include "recvthread.h"
15 |
16 | class GroupChat;
17 | #include "groupchat.h"
18 |
19 | class PrivateChat;
20 | #include "privatechat.h"
21 |
22 | namespace Ui {
23 | class Chatlist;
24 | }
25 |
26 | struct ChatWidgetInfo
27 | {
28 | PrivateChat *w;
29 | QString name;
30 | };
31 |
32 | struct groupWidgetInfo
33 | {
34 | GroupChat *w;
35 | QString name;
36 | };
37 |
38 | class Chatlist : public QWidget
39 | {
40 | Q_OBJECT
41 |
42 | public:
43 | explicit Chatlist(QTcpSocket *, QString, QString, QString, QWidget *parent = 0);
44 | void closeEvent(QCloseEvent *event);
45 | ~Chatlist();
46 |
47 | private slots:
48 | void server_reply();
49 |
50 | void on_addButton_clicked();
51 |
52 | void on_createGroupButton_clicked();
53 |
54 | void on_addGroupButton_clicked();
55 |
56 | void on_friendList_double_clicked();
57 |
58 | void on_groupList_double_clicked();
59 |
60 | signals:
61 | void signal_to_sub_widget(QJsonObject);
62 | void signal_to_sub_widget_member(QJsonObject);
63 | void signal_to_sub_widget_group(QJsonObject);
64 |
65 | private:
66 | void client_login_reply(QString);
67 | void client_add_friend_reply(QJsonObject &obj);
68 | void client_create_group_reply(QJsonObject &obj);
69 | void client_add_group_reply(QJsonObject &obj);
70 | void client_private_chat_reply(QString);
71 | void client_chat_reply(QJsonObject &);
72 | void client_get_group_member_reply(QJsonObject);
73 | void client_group_chat_reply(QJsonObject);
74 | void client_send_file_reply(QString);
75 | void client_send_file_port_reply(QJsonObject);
76 | void client_recv_file_port_reply(QJsonObject);
77 | void client_friend_offline(QString fri);
78 |
79 | Ui::Chatlist *ui;
80 | QTcpSocket *socket;
81 | QString userName;
82 | QList chatWidgetList;
83 | QList groupWidgetList;
84 | };
85 |
86 | #endif // CHATLIST_H
87 |
--------------------------------------------------------------------------------
/chat_client_code/chatlist.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Chatlist
4 |
5 |
6 |
7 | 0
8 | 0
9 | 277
10 | 476
11 |
12 |
13 |
14 |
15 | 277
16 | 476
17 |
18 |
19 |
20 |
21 | 277
22 | 476
23 |
24 |
25 |
26 | Form
27 |
28 |
29 | -
30 |
31 |
32 | QTabBar::tab{width:120}
33 |
34 |
35 | 0
36 |
37 |
38 |
39 | 好友
40 |
41 |
42 |
-
43 |
44 |
45 |
46 |
47 |
48 |
49 | 群
50 |
51 |
52 | -
53 |
54 |
55 |
56 |
57 |
58 |
59 | -
60 |
61 |
62 | 添加好友
63 |
64 |
65 |
66 | -
67 |
68 |
69 | 创建群聊
70 |
71 |
72 |
73 | -
74 |
75 |
76 | 添加群
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/chat_client_code/creategroup.cpp:
--------------------------------------------------------------------------------
1 | #include "creategroup.h"
2 | #include "ui_creategroup.h"
3 |
4 | CreateGroup::CreateGroup(QTcpSocket *s, QString u, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::CreateGroup)
7 | {
8 | ui->setupUi(this);
9 | socket = s;
10 | userName = u;
11 | }
12 |
13 | CreateGroup::~CreateGroup()
14 | {
15 | delete ui;
16 | }
17 |
18 | void CreateGroup::on_cancelButton_clicked()
19 | {
20 | this->close();
21 | }
22 |
23 | void CreateGroup::on_pushButton_2_clicked()
24 | {
25 | QString groupName = ui->lineEdit->text();
26 | QJsonObject obj;
27 | obj.insert("cmd", "create_group");
28 | obj.insert("user", userName);
29 | obj.insert("group", groupName);
30 | QByteArray ba = QJsonDocument(obj).toJson();
31 | socket->write(ba);
32 | this->close();
33 | }
34 |
--------------------------------------------------------------------------------
/chat_client_code/creategroup.h:
--------------------------------------------------------------------------------
1 | #ifndef CREATEGROUP_H
2 | #define CREATEGROUP_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Ui {
10 | class CreateGroup;
11 | }
12 |
13 | class CreateGroup : public QWidget
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit CreateGroup(QTcpSocket *s, QString u, QWidget *parent = 0);
19 | ~CreateGroup();
20 |
21 | private slots:
22 | void on_cancelButton_clicked();
23 |
24 | void on_pushButton_2_clicked();
25 |
26 | private:
27 | Ui::CreateGroup *ui;
28 | QString userName;
29 | QTcpSocket *socket;
30 | };
31 |
32 | #endif // CREATEGROUP_H
33 |
--------------------------------------------------------------------------------
/chat_client_code/creategroup.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | CreateGroup
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 217
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 70
20 | 70
21 | 81
22 | 31
23 |
24 |
25 |
26 | <html><head/><body><p align="center"><span style=" font-size:12pt;">创建群名称</span></p></body></html>
27 |
28 |
29 |
30 |
31 |
32 | 160
33 | 70
34 | 161
35 | 31
36 |
37 |
38 |
39 |
40 |
41 |
42 | 80
43 | 140
44 | 75
45 | 23
46 |
47 |
48 |
49 | 取消
50 |
51 |
52 |
53 |
54 |
55 | 220
56 | 140
57 | 75
58 | 23
59 |
60 |
61 |
62 | 创建
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/chat_client_code/groupchat.cpp:
--------------------------------------------------------------------------------
1 | #include "groupchat.h"
2 | #include "ui_groupchat.h"
3 |
4 | GroupChat::GroupChat(QTcpSocket *s, QString g, QString u, Chatlist *c, QList *l, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::GroupChat)
7 | {
8 | ui->setupUi(this);
9 | socket = s;
10 | groupName = g;
11 | userName = u;
12 | mainWidget = c;
13 | groupWidgetList = l;
14 |
15 | QJsonObject obj;
16 | obj.insert("cmd", "get_group_member");
17 | obj.insert("group", groupName);
18 | QByteArray ba = QJsonDocument(obj).toJson();
19 | socket->write(ba);
20 |
21 | connect(mainWidget, &Chatlist::signal_to_sub_widget_member, this, &GroupChat::show_group_member);
22 | connect(mainWidget, &Chatlist::signal_to_sub_widget_group, this, &GroupChat::show_group_text);
23 | }
24 |
25 | GroupChat::~GroupChat()
26 | {
27 | delete ui;
28 | }
29 |
30 | void GroupChat::show_group_member(QJsonObject obj)
31 | {
32 | if (obj.value("cmd").toString() == "get_group_member_reply")
33 | {
34 | if (obj.value("group").toString() == groupName)
35 | {
36 | QStringList strList = obj.value("member").toString().split("|");
37 | for (int i = 0; i < strList.size(); i++)
38 | {
39 | ui->listWidget->addItem(strList.at(i));
40 | }
41 | }
42 | }
43 | }
44 |
45 | void GroupChat::on_sendButton_clicked()
46 | {
47 | QString text = ui->lineEdit->text();
48 | QJsonObject obj;
49 | obj.insert("cmd", "group_chat");
50 | obj.insert("user", userName);
51 | obj.insert("group", groupName);
52 | obj.insert("text", text);
53 | QByteArray ba = QJsonDocument(obj).toJson();
54 | socket->write(ba);
55 |
56 | ui->lineEdit->clear();
57 | ui->textEdit->append(text);
58 | ui->textEdit->append("\n");
59 | }
60 |
61 | void GroupChat::show_group_text(QJsonObject obj)
62 | {
63 | if (obj.value("cmd").toString() == "group_chat")
64 | {
65 | if (obj.value("group").toString() == groupName)
66 | {
67 | if (this->isMinimized())
68 | {
69 | this->showNormal();
70 | }
71 | this->activateWindow();
72 | ui->textEdit->append(obj.value("text").toString());
73 | ui->textEdit->append("\n");
74 | }
75 | }
76 | }
77 |
78 | void GroupChat::closeEvent(QCloseEvent * event)
79 | {
80 | for (int i = 0; i < groupWidgetList->size(); i++)
81 | {
82 | if (groupWidgetList->at(i).name == groupName)
83 | {
84 | groupWidgetList->removeAt(i);
85 | }
86 | }
87 | event->accept();
88 | }
89 |
--------------------------------------------------------------------------------
/chat_client_code/groupchat.h:
--------------------------------------------------------------------------------
1 | #ifndef GROUPCHAT_H
2 | #define GROUPCHAT_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | class Chatlist;
11 | struct groupWidgetInfo;
12 | #include "chatlist.h"
13 |
14 | namespace Ui {
15 | class GroupChat;
16 | }
17 |
18 | class GroupChat : public QWidget
19 | {
20 | Q_OBJECT
21 |
22 | public:
23 | explicit GroupChat(QTcpSocket *s, QString g, QString u, Chatlist *c, QList *l, QWidget *parent = 0);
24 | ~GroupChat();
25 | void closeEvent(QCloseEvent *);
26 |
27 | private slots:
28 | void show_group_member(QJsonObject);
29 |
30 | void on_sendButton_clicked();
31 |
32 | void show_group_text(QJsonObject);
33 |
34 | private:
35 | Ui::GroupChat *ui;
36 | QTcpSocket *socket;
37 | QString userName;
38 | QString groupName;
39 | Chatlist *mainWidget;
40 | QList *groupWidgetList;
41 | };
42 |
43 | #endif // GROUPCHAT_H
44 |
--------------------------------------------------------------------------------
/chat_client_code/groupchat.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | GroupChat
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 0
20 | 0
21 | 291
22 | 181
23 |
24 |
25 |
26 |
27 |
28 |
29 | 0
30 | 200
31 | 291
32 | 41
33 |
34 |
35 |
36 |
37 |
38 |
39 | 220
40 | 270
41 | 75
42 | 23
43 |
44 |
45 |
46 | 发送
47 |
48 |
49 |
50 |
51 |
52 | 310
53 | 0
54 | 81
55 | 241
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/chat_client_code/main.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | Widget w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/chat_client_code/privatechat.cpp:
--------------------------------------------------------------------------------
1 | #include "privatechat.h"
2 | #include "ui_privatechat.h"
3 |
4 | PrivateChat::PrivateChat(QTcpSocket *s, QString u, QString f, Chatlist *c, QList *l, QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::PrivateChat)
7 | {
8 | ui->setupUi(this);
9 | socket = s;
10 | userName = u;
11 | friendName = f;
12 | mainWidget = c;
13 | chatWidgetList = l;
14 |
15 | connect(mainWidget, &Chatlist::signal_to_sub_widget, this, &PrivateChat::show_text_slot);
16 | }
17 |
18 | PrivateChat::~PrivateChat()
19 | {
20 | delete ui;
21 | }
22 |
23 | void PrivateChat::on_sendButton_clicked()
24 | {
25 | QString text = ui->lineEdit->text();
26 | QJsonObject obj;
27 | obj.insert("cmd", "private_chat");
28 | obj.insert("user_from", userName);
29 | obj.insert("user_to", friendName);
30 | obj.insert("text", text);
31 | QByteArray ba = QJsonDocument(obj).toJson();
32 | socket->write(ba);
33 |
34 | ui->lineEdit->clear();
35 | ui->textEdit->append(text);
36 | ui->textEdit->append("\n");
37 | }
38 |
39 | void PrivateChat::show_text_slot(QJsonObject obj)
40 | {
41 | if (obj.value("cmd").toString() == "private_chat")
42 | {
43 | if (obj.value("user_from").toString() == friendName)
44 | {
45 | if (this->isMinimized())
46 | {
47 | this->showNormal();
48 | }
49 | this->activateWindow();
50 | ui->textEdit->append(obj.value("text").toString());
51 | ui->textEdit->append("\n");
52 | }
53 | }
54 | }
55 |
56 | void PrivateChat::closeEvent(QCloseEvent *event)
57 | {
58 | for (int i = 0; i < chatWidgetList->size(); i++)
59 | {
60 | if (chatWidgetList->at(i).name == friendName)
61 | {
62 | chatWidgetList->removeAt(i);
63 | break;
64 | }
65 | }
66 | event->accept();
67 | }
68 |
69 | void PrivateChat::on_fileButton_clicked()
70 | {
71 | QString fileName = QFileDialog::getOpenFileName(this, "发送文件", QCoreApplication::applicationFilePath());
72 | if (fileName.isEmpty())
73 | {
74 | QMessageBox::warning(this, "发送文件提示", "请选择一个文件");
75 | }
76 | else
77 | {
78 | QFile file(fileName);
79 | file.open(QIODevice::ReadOnly);
80 | QJsonObject obj;
81 | obj.insert("cmd", "send_file");
82 | obj.insert("from_user", userName);
83 | obj.insert("to_user", friendName);
84 | obj.insert("length", file.size());
85 | obj.insert("filename", fileName);
86 | QByteArray ba = QJsonDocument(obj).toJson();
87 | socket->write(ba);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/chat_client_code/privatechat.h:
--------------------------------------------------------------------------------
1 | #ifndef PRIVATECHAT_H
2 | #define PRIVATECHAT_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | class Chatlist;
14 | struct ChatWidgetInfo;
15 | #include "chatlist.h"
16 |
17 | namespace Ui {
18 | class PrivateChat;
19 | }
20 |
21 | class PrivateChat : public QWidget
22 | {
23 | Q_OBJECT
24 |
25 | public:
26 | explicit PrivateChat(QTcpSocket *s, QString u, QString f, Chatlist *c, QList *l, QWidget *parent = 0);
27 | ~PrivateChat();
28 | void closeEvent(QCloseEvent *event);
29 |
30 | private slots:
31 | void on_sendButton_clicked();
32 | void show_text_slot(QJsonObject);
33 |
34 | void on_fileButton_clicked();
35 |
36 | private:
37 | Ui::PrivateChat *ui;
38 | QTcpSocket *socket;
39 | QString userName;
40 | QString friendName;
41 | Chatlist *mainWidget;
42 | QList *chatWidgetList;
43 | };
44 |
45 | #endif // PRIVATECHAT_H
46 |
--------------------------------------------------------------------------------
/chat_client_code/privatechat.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | PrivateChat
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 0
20 | 0
21 | 401
22 | 171
23 |
24 |
25 |
26 |
27 |
28 |
29 | 0
30 | 200
31 | 401
32 | 41
33 |
34 |
35 |
36 |
37 |
38 |
39 | 290
40 | 260
41 | 75
42 | 23
43 |
44 |
45 |
46 | 发送
47 |
48 |
49 |
50 |
51 |
52 | 30
53 | 260
54 | 75
55 | 23
56 |
57 |
58 |
59 | 传输文件
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/chat_client_code/recvthread.cpp:
--------------------------------------------------------------------------------
1 | #include "recvthread.h"
2 |
3 | RecvThread::RecvThread(QJsonObject obj)
4 | {
5 | total = 0;
6 | port = obj.value("port").toInt();
7 | fileLength = obj.value("length").toInt();
8 |
9 | QString pathName = obj.value("filename").toString();
10 | QStringList strList = pathName.split('/');
11 | fileName = strList.at(strList.size() - 1);
12 | }
13 |
14 | void RecvThread::run()
15 | {
16 | file = new QFile(fileName);
17 | file->open(QIODevice::WriteOnly);
18 |
19 | recvSocket = new QTcpSocket;
20 |
21 | connect(recvSocket, &QTcpSocket::readyRead, this, &RecvThread::recv_file, Qt::DirectConnection);
22 |
23 | recvSocket->connectToHost(QHostAddress("47.101.128.140"), port);
24 | if (!recvSocket->waitForConnected(10000))
25 | {
26 | this->quit();
27 | }
28 | else
29 | {
30 |
31 | }
32 |
33 | exec();
34 | }
35 |
36 | void RecvThread::recv_file()
37 | {
38 | QByteArray ba = recvSocket->readAll();
39 | total += ba.size();
40 | file->write(ba);
41 |
42 | if (total >= fileLength)
43 | {
44 | file->close();
45 | recvSocket->close();
46 | delete file;
47 | delete recvSocket;
48 | this->quit();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/chat_client_code/recvthread.h:
--------------------------------------------------------------------------------
1 | #ifndef RECVTHREAD_H
2 | #define RECVTHREAD_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | class RecvThread : public QThread
12 | {
13 | Q_OBJECT
14 | public:
15 | RecvThread(QJsonObject obj);
16 | void run();
17 |
18 | private slots:
19 | void recv_file();
20 |
21 | private:
22 | QString fileName;
23 | int fileLength;
24 | int total;
25 | int port;
26 | QTcpSocket *recvSocket;
27 | QFile *file;
28 | };
29 |
30 | #endif // RECVTHREAD_H
31 |
--------------------------------------------------------------------------------
/chat_client_code/sendthread.cpp:
--------------------------------------------------------------------------------
1 | #include "sendthread.h"
2 |
3 | SendThread::SendThread(QJsonObject obj)
4 | {
5 | port = obj.value("port").toInt();
6 | fileName = obj.value("filename").toString();
7 | fileLength = obj.value("length").toInt();
8 | }
9 |
10 | void SendThread::run()
11 | {
12 | QTcpSocket sendSocket;
13 | sendSocket.connectToHost(QHostAddress("47.101.128.140"), port);
14 | if (!sendSocket.waitForConnected(10000))
15 | {
16 | this->quit();
17 | }
18 | else
19 | {
20 | QFile file(fileName);
21 | file.open(QIODevice::ReadOnly);
22 |
23 | while (1)
24 | {
25 | QByteArray ba = file.read(1024 * 1024);
26 | if (ba.size() == 0)
27 | {
28 | break;
29 | }
30 | sendSocket.write(ba);
31 | sendSocket.flush();
32 | usleep(2000000);
33 | }
34 | file.close();
35 | sendSocket.close();
36 | this->quit();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/chat_client_code/sendthread.h:
--------------------------------------------------------------------------------
1 | #ifndef SENDTHREAD_H
2 | #define SENDTHREAD_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | class SendThread : public QThread
12 | {
13 | public:
14 | SendThread(QJsonObject obj);
15 | void run();
16 |
17 | private:
18 | QString fileName;
19 | int fileLength;
20 | int port;
21 | };
22 |
23 | #endif // SENDTHREAD_H
24 |
--------------------------------------------------------------------------------
/chat_client_code/widget.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include "ui_widget.h"
3 |
4 | Widget::Widget(QWidget *parent) :
5 | QWidget(parent),
6 | ui(new Ui::Widget)
7 | {
8 | ui->setupUi(this);
9 | socket = new QTcpSocket;
10 | socket->connectToHost(QHostAddress("47.101.128.140"), 8000);
11 |
12 | connect(socket, &QTcpSocket::connected, this, &Widget::connect_success);
13 | connect(socket, &QTcpSocket::readyRead, this, &Widget::server_reply);
14 | }
15 |
16 | Widget::~Widget()
17 | {
18 | delete ui;
19 | }
20 |
21 | void Widget::connect_success()
22 | {
23 | QMessageBox::information(this, "连接提示", "连接服务器成功");
24 | }
25 |
26 | void Widget::on_registerButton_clicked()
27 | {
28 | QString username = ui->userLineEdit->text();
29 | QString password = ui->passwdLineEdit->text();
30 |
31 | QJsonObject obj;
32 | obj.insert("cmd", "register");
33 | obj.insert("user", username);
34 | obj.insert("password", password);
35 |
36 | QByteArray ba = QJsonDocument(obj).toJson();
37 | socket->write(ba);
38 | }
39 |
40 | void Widget::server_reply()
41 | {
42 | QByteArray ba = socket->readAll();
43 | QJsonObject obj = QJsonDocument::fromJson(ba).object();
44 | QString cmd = obj.value("cmd").toString();
45 | if (cmd == "register_reply")
46 | {
47 | client_register_handler(obj.value("result").toString());
48 | }
49 | else if (cmd == "login_reply")
50 | {
51 | client_login_handler(obj.value("result").toString(),
52 | obj.value("friend").toString(), obj.value("group").toString());
53 | }
54 | }
55 |
56 | void Widget::client_register_handler(QString res)
57 | {
58 | if (res == "success")
59 | {
60 | QMessageBox::information(this, "注册提示", "注册成功");
61 | }
62 | else if (res == "failure")
63 | {
64 | QMessageBox::warning(this, "注册提示", "注册失败");
65 | }
66 | }
67 |
68 | void Widget::on_loginButton_clicked()
69 | {
70 | QString username = ui->userLineEdit->text();
71 | QString password = ui->passwdLineEdit->text();
72 |
73 | QJsonObject obj;
74 | obj.insert("cmd", "login");
75 | obj.insert("user", username);
76 | obj.insert("password", password);
77 |
78 | userName = username;
79 |
80 | QByteArray ba = QJsonDocument(obj).toJson();
81 | socket->write(ba);
82 | }
83 |
84 | void Widget::client_login_handler(QString res, QString fri, QString group)
85 | {
86 | if (res == "user_not_exist")
87 | {
88 | QMessageBox::warning(this, "登录提示", "用户不存在");
89 | }
90 | else if (res == "password_error")
91 | {
92 | QMessageBox::warning(this, "登录提示", "密码错误");
93 | }
94 | else if (res == "success")
95 | {
96 | this->hide();
97 | socket->disconnect(SIGNAL(readyRead()));
98 | Chatlist *c = new Chatlist(socket, fri, group, userName);
99 | c->setWindowTitle(userName);
100 | c->show();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/chat_client_code/widget.h:
--------------------------------------------------------------------------------
1 | #ifndef WIDGET_H
2 | #define WIDGET_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "chatlist.h"
11 |
12 | namespace Ui {
13 | class Widget;
14 | }
15 |
16 | class Widget : public QWidget
17 | {
18 | Q_OBJECT
19 |
20 | public:
21 | explicit Widget(QWidget *parent = 0);
22 | ~Widget();
23 |
24 | private slots:
25 | void connect_success();
26 | void server_reply();
27 |
28 | void on_registerButton_clicked();
29 |
30 | void on_loginButton_clicked();
31 |
32 | private:
33 | void client_register_handler(QString);
34 | void client_login_handler(QString, QString, QString);
35 |
36 | Ui::Widget *ui;
37 | QTcpSocket *socket;
38 | QString userName;
39 | };
40 |
41 | #endif // WIDGET_H
42 |
--------------------------------------------------------------------------------
/chat_client_code/widget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Widget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Widget
15 |
16 |
17 |
18 |
19 | 80
20 | 100
21 | 51
22 | 21
23 |
24 |
25 |
26 | <html><head/><body><p align="center"><span style=" font-size:12pt;">用户</span></p></body></html>
27 |
28 |
29 |
30 |
31 |
32 | 80
33 | 140
34 | 51
35 | 21
36 |
37 |
38 |
39 | <html><head/><body><p align="center"><span style=" font-size:12pt;">密码</span></p></body></html>
40 |
41 |
42 |
43 |
44 |
45 | 140
46 | 90
47 | 141
48 | 31
49 |
50 |
51 |
52 |
53 |
54 |
55 | 140
56 | 140
57 | 141
58 | 31
59 |
60 |
61 |
62 |
63 |
64 |
65 | 90
66 | 200
67 | 75
68 | 23
69 |
70 |
71 |
72 | 注册
73 |
74 |
75 |
76 |
77 |
78 | 230
79 | 200
80 | 75
81 | 23
82 |
83 |
84 |
85 | 登录
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/chat_database.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/chat_database.cpp
--------------------------------------------------------------------------------
/chat_database.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/chat_database.h
--------------------------------------------------------------------------------
/chat_server_project.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30907.101
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chat_server", "chat_server.vcxproj", "{376D12C2-B058-4FDA-93B9-2C2F81C440AB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|ARM = Release|ARM
15 | Release|ARM64 = Release|ARM64
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.ActiveCfg = Debug|ARM
21 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.Build.0 = Debug|ARM
22 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM.Deploy.0 = Debug|ARM
23 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.ActiveCfg = Debug|x64
27 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.Build.0 = Debug|x64
28 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x64.Deploy.0 = Debug|x64
29 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.ActiveCfg = Debug|x86
30 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.Build.0 = Debug|x86
31 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Debug|x86.Deploy.0 = Debug|x86
32 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.ActiveCfg = Release|ARM
33 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.Build.0 = Release|ARM
34 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM.Deploy.0 = Release|ARM
35 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.ActiveCfg = Release|ARM64
36 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.Build.0 = Release|ARM64
37 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|ARM64.Deploy.0 = Release|ARM64
38 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.ActiveCfg = Release|x64
39 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.Build.0 = Release|x64
40 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x64.Deploy.0 = Release|x64
41 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.ActiveCfg = Release|x86
42 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.Build.0 = Release|x86
43 | {376D12C2-B058-4FDA-93B9-2C2F81C440AB}.Release|x86.Deploy.0 = Release|x86
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {EA6647A8-C091-45F0-8AFF-D0632C712335}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/chat_server_project.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM
7 |
8 |
9 | Release
10 | ARM
11 |
12 |
13 | Debug
14 | ARM64
15 |
16 |
17 | Release
18 | ARM64
19 |
20 |
21 | Debug
22 | x86
23 |
24 |
25 | Release
26 | x86
27 |
28 |
29 | Debug
30 | x64
31 |
32 |
33 | Release
34 | x64
35 |
36 |
37 |
38 | {376d12c2-b058-4fda-93b9-2c2f81c440ab}
39 | Linux
40 | chat_server
41 | 15.0
42 | Linux
43 | 1.0
44 | Generic
45 | {2238F9CD-F817-4ECC-BD14-2524D2669B35}
46 |
47 |
48 |
49 | true
50 |
51 |
52 | false
53 |
54 |
55 | true
56 |
57 |
58 | false
59 |
60 |
61 | true
62 |
63 |
64 | false
65 |
66 |
67 | false
68 |
69 |
70 | true
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/chatlist.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/chatlist.cpp
--------------------------------------------------------------------------------
/chatlist.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/chatlist.h
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/main.cpp
--------------------------------------------------------------------------------
/myassets/image-20220912180434913.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/myassets/image-20220912180434913.png
--------------------------------------------------------------------------------
/myassets/image-20220912180641606.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/myassets/image-20220912180641606.png
--------------------------------------------------------------------------------
/server.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/server.cpp
--------------------------------------------------------------------------------
/server.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/server.h
--------------------------------------------------------------------------------
/在阿里云服务器上搭建开发环境.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/在阿里云服务器上搭建开发环境.txt
--------------------------------------------------------------------------------
/服务器与客户端接口文档.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/服务器与客户端接口文档.txt
--------------------------------------------------------------------------------
/测试客户端.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kuzsen/chat-software/fe0194dc3523f7914d36fe4f7d4b022ac5c774c6/测试客户端.c
--------------------------------------------------------------------------------