目录
注意
一 .项目功能
二.项目简介
三.项目演示
四.项目功能基本介绍
四.代码部分
server.c
server.h
mian.c
客户端
client.c
client.h
main.c
注意
相比较第一个版本 第二个版本将服务器的多线程并发服务器改成了epoll+线程池处理
客户端依旧运用的是上个版本的客户端
一 .项目功能
目前该项目实现基本功能有:
基本功能:
1.注册 2.登录 3.群聊 4快捷短语 5.保存聊天记录 6.查看聊天记录
7.文件传输 8.敏感词汇判断 9.私聊 10.离线消息发送
11.查看在线用户 12.管理员申请 13.管理员专属头像 14.禁言用户
15.解除禁言 16.管理员踢人 17.修改密码 18.注销用户 19.撤销管理员身份
二.项目简介
epoll
1.相比较: select内部使用数组实现,poll是链表。他们需要做内核区到用户区的转换,还需要做数据拷贝,因此效率低
2.epoll不需要做内核区到用户区的转换,因为数据存在共享内存中。epoll维护的树在共享内存中,内核区和用户区去操作共享内存,因此不需要区域转换,也不需要拷贝操作。
线程池
(1)降低销毁资源:重复利用线程池中已经存在的线程,减少了线程的创建和消亡造成的性能开销。
(2)提高了相应速率:当任务到达时,任务可以不需要等到线程创建就能够执行。
(3)防止服务器过载:形成内存溢出,或者cpu耗尽。
(4)提高线程的可管理性:线程时稀缺资源,若无限的创建线程,不仅会消耗资源,还会降低系统的稳定性,使用线程池可以统一的分配,调优和监控
三.项目演示
即使通讯系统项目
四.项目功能基本介绍
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149## 三 .项目具体介绍 ### 1.注册 ``` 注册有重复注册判断 在数据库 普通用户表中遍历 如果存在该用户则 停止注册 将注册的信息保存在通信协议中 服务器收到注册的功能标志 调用注册函数 将注册的信息插入数据库的普通用户表中; ``` #### 2.登录 ``` 用户登录 用一个链表保存在线用户 链表里包含用户的文件描述符 负责与用户之间通信 登录成功将会给所有在线用户发送自己已上线; 登录第一步在数据库中遍历该用户是否注册 只有注册了才能进行登录操作 第一步是遍历链表是否已经登录如果已经在别处登录 将不能进行登录操作. ``` ### 3.群聊 ``` 因为登录过程中所有的用户的文件描述符 都会保存在在线链表中 群聊直接遍历在线用户链表 对每个文件描述符对应的用户发送消息 群聊的第一步 首先判断除了自己以外是否还有别的用户在线 第二步才是遍历链表 对除了自己的每个在线用户发送消息 ``` ### 4.快捷短语 ``` 在发送消息之前 判断 所要发送的消息 是否有对应的快捷短语 如果有快捷短语 则将快捷短语strcpy 至通信协议 聊天内容的字符串数组 进行发送 如果没有找对对应的快捷消息 则正常发送 ``` ### 5.聊天记录的保存以及查看 ``` 在服务器有一个recv函数循环的阻塞接受 客户端发来的结构体 也就是通信协议 每一次的信息传递都要经过这个函数 只用在recv函数下面 运用数据库相关的操作将 发送信息的用户 发送时间 以及消息内容存储至数据库中 查看聊天记录遍历数据库内容 将遍历的内容以固定格式保存在buf 发送给客户端; ``` ### 6.文件传输 ``` 使用read函数 从打开的文件中循环读取内容 将内容与读取到的字节数 保存在通信协议中内容保存专用于文件传输的字符串数组中,将读取到的字节数一并传输 为了写入时 按读取的字节数进行写入 发送给服务器,再由服务器进行转发到对应的客户端 为了防止粘包现象采用传输结构体 ``` ### 7.敏感词判断 ``` 敏感词判断 数据中有一张表保存了各种敏感词汇 当客户端进行发送消息时 服务器遍历数据库判断消息是否为敏感词汇 一旦是敏感词汇 返回客户端 发送失败信号 并停止将敏感词汇转发给其他客户端 ``` ## 8.私聊 ``` 私聊第一步就是 服务器遍历在线用户链表 判断私聊对象是否在线 不在线返回给客户端 不在线消息 私聊和群聊相似 当客户端发送私聊信号时 服务器遍历链表 遍历出私聊对象 再将消息内容转发给对应的客户端 ``` ### 9.离线消息的发送 ``` 当私聊不在线是私聊信息会保存在数据库的 离线消息表中 当对方上线时 立即将消息发送给对方 ``` ### 10.查看在线用户 ``` 查看在线用户 和群聊相似 都是一个遍历链表的过程 当客户端发送查看在线用户的信号给 服务器 服务器在进行遍历在线链表将每遍历一个用户 将其用户名按固定格式 发送给 需要查看在线用户的用户 ``` ## 管理员用户的相关操作 ### 11.申请称为管理员设置管理员头像 ``` 只有先成为普通用户以后 在能申请管理员 管理员有专属的管理员头像 申请成管理员后必需重新以管理员身份进行登录 在群聊过程中 管理员自带头像 客户端发送申请管理员信号以后 服务器 会将管理员用户信息 姓名密码头像等 保存在数据库的root表中 管理员用户 不可以重复申请 ``` ### 12.管理员禁言用户 ### 13.解除禁言 ``` 管理员禁言 客户端给服务器发送一个 禁言信号 以及禁言对象 服务器首先判断发送禁言指令的是不是管理员 在对方是否在线 其次判断对方是不是管理员 管理员不能对管理员进行踢人 或者 禁言操作 如果对方是普通用则给对方发送禁言信号 这里采用的是全局变量flag 客户端收到禁言信号时flag至0 失去通信权限 收到解禁信号 flag至1 恢复通信权限 ``` ### 14.管理员踢人 ``` 管理员踢人 和禁言一样判断是否在线 在判断是否为管理员 如果为普通用户 则向对应的客户端发送退出聊天室指令 客户端收到退出指令以后自主结束整个进程 同时服务器将在线用户链表中的该用户踢出链表 并给所有在线用户发送消息 ``` #### 15.修改密码 ``` 没有设置密保 直接根据名字进行修改密码 修改密码以后需要从新登录 客户端发送 修改密码信号 以及新密码 至服务器 服务器调用封装好的数据库函数 执行update更新数据库的语句 根据名字对密码进行更新 update user set password = '%s' where name = '%s' ``` ### 16.注销用户 ``` 注销用户和修改密码类似 首先进行账户密码判断 账户密码正确才能进行注销用户 数据库找到关于注销名字的记录 然后删除这条记录 同时服务器将在线用户链表中的该用户踢出链表; delete from user where name = '%s' ``` #### 17.撤销管理员身份 ``` 注销用户和注销用户类似 首先进行账户密码判断 账户密码正确才能进行撤销root 数据库找到关于撤销名字的记录 然后删除这条记录 同时服务器将在线用户链表中的该用户踢出链表; delete from user where name = '%s' ``` 退出聊天室 结束整个进程
四.代码部分
server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794#include "server.h" int flag2 = 1; //发送文件信号 extern struct pthreadpool *pool ; extern online_userlist *head; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int socket_init() { unsigned char ip_str[] = "192.168.91.151"; unsigned char port_str[] = "8787"; int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket error"); return -1; } //设置套接字端口属性为端口释放后可以重复使用 int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); //将套接字进行IP与端口的绑定 struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); //清空内存 addr.sin_family = AF_INET; addr.sin_port = htons(atoi(port_str)); //端口和ip要改成大端模式 addr.sin_addr.s_addr = inet_addr(ip_str); int ret = bind(sockfd, (struct sockaddr *)&(addr), sizeof(addr)); if (ret == -1) { perror("bind error"); printf("绑定套接字失败.n"); return -1; } //监听 ret = listen(sockfd, 20); if (ret == -1) { perror("listen error"); printf("监听套接字失败.n"); return -1; } printf("客户机已经开启,等待用户连接中.....n"); return sockfd; } // epoll操作 int mypoll(int sockfd) { int N = sizeof(clientlist);//MSg为通信协议 计算通信协议的大小 struct sockaddr_in clientaddr;//创建被填充的网络信息结构体 socklen_t addrlen = sizeof(clientaddr); //计算被网络信息结构体的大小 //第一步:创建epoll对象 int epfd = epoll_create(2000); //创建内核事件表 最大保存文件描述符个数为2000 //如果用epoll_create1一般参数为0 每添加一个自动增加结点保存文件描述符 if (-1 == epfd)//成功返回非负数的文件描述符 失败返回-1 { ERRLOG("epoll"); } //epoll树上挂的就是下面这个结构体 struct epoll_event ev, events[2000] = {0};//事件初始化 读 写 异常等 ev.events = EPOLLIN; //监听sockfd可读 ev.data.fd = sockfd; //操作epoll内核时间表 // 参数一create生成的专用文件描述符 二操作类型 增 删 改 三 关联的文件描述符 四epoll_event结构体也就是上面的结构体 int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); if (-1 == ret) {//成功返回0 失败返回-1 printf("%sn", strerror(errno)); return -1; } //accept接受客户端连接 int i; int acceptfd = 0; while (1) { clientlist agreement; //Msg msg;//通信协议 //参数分析 参数一 create返回值 参数二结点结构体(传出参数) 参数三事件表的最大存储个数 参数四 阻塞方式永久阻塞0是立即返回 int num = epoll_wait(epfd, events, 2000, -1);//等待IO事件发生 if (-1 == num) { printf("epoll_wait() failedn"); return -1; }//成功:返回准备好的文件描述符的个数,如果没有准备号的,则返回0 错误:返回 -1 for (i = 0; i < num; i++) { if (events[i].data.fd == sockfd) //表示有客户端发起链接 { if ((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) == -1) { ERRLOG("accept error"); continue; } //为新的文件描述符注册事件 printf("accept fd %dn", acceptfd); ev.events = EPOLLIN; //监听sockfd可读 ev.data.fd = acceptfd; int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, acceptfd, &ev); if (-1 == ret) { ERRLOG("epoll_ctl"); } printf("客户端%s:%d 连接了n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); } else //有客户端发消息 { //Myarg arg; Myarg* arg = (Myarg *)malloc(sizeof(Myarg)); memset(arg, 0, sizeof(Myarg)); if (events[i].events & EPOLLIN) //如果事件是可读的 { memset(&agreement, 0, sizeof(agreement)); ret = recv(events[i].data.fd, &agreement, N, 0); if(agreement.flag == 3 || agreement.flag == 5) { insert_uprecord(&agreement); } if (ret == -1) { ERRLOG("recv"); } else if (0 == ret) { ev.events = EPOLLIN; //监听sockfd可读 ev.data.fd = events[i].data.fd; int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev); //客户端退出,注销事件 if (-1 == ret) { ERRLOG("epoll_ctl"); } printf("退出的客户端fd=%dn",events[i].data.fd); Offlineprocessing(events[i].data.fd);//掉线处理函数 close(events[i].data.fd); } else { // //信息拷贝 arg->msg.flag=agreement.flag; arg->msg.root=agreement.root; arg->msg.num=agreement.num; strcpy(arg->msg.name, agreement.name); strcpy(arg->msg.to_name, agreement.to_name); strcpy(arg->msg.msg, agreement.msg); printf("agreement.msg = %sn",agreement.msg); strcpy(arg->msg.emojio, agreement.emojio); strcpy(arg->msg.password, agreement.password); strcpy(arg->msg.buf, agreement.buf); arg->fd = events[i].data.fd; ThreadAddJob(pool, work, (void *)arg);//任務添加到任務隊列 } } } } } } //线程函数从任务队列去任务 void *ThreadRun(void *arg) { struct pthreadpool *pool = (struct pthreadpool *)arg; struct job *pjob = NULL;//任务队列指针 while (1) { pthread_mutex_lock(&pool->mutex); if (pool->m_QueueCurNum == 0) { printf("当前任务队列为空,线程%ld阻塞等待任务到来!n", pthread_self()); pthread_cond_wait(&pool->m_QueueNotEmpty, &pool->mutex); } pjob = pool->head;//指针指向任务队列的头部 pool->m_QueueCurNum--;//当前任务数量-- if (pool->m_QueueCurNum != pool->m_QueueMaxNum)//如果当前任务队列没有满 { pthread_cond_signal(&pool->m_QueueNotFull); //每次线程取出一个任务之后,都要唤醒线程去添加任务 } if (pool->m_QueueCurNum == 0)//如果当前任务对列没有任务 { pool->head = pool->rear = NULL; pthread_cond_broadcast(&pool->m_QueueEmpty); //当通知任务队列添加任务无果后,发送条件变量,通知其销毁线程 } else { pool->head = pool->head->next; } pthread_mutex_unlock(&pool->mutex); pjob->func(pjob->arg);//运行任务函数 free(pjob); pjob = NULL; } } //参数分析 参数1线程池线程数量 参数二 任务队列最大任务数 struct pthreadpool *InitPthreadPool(int ThreadNum, int QueueMaxNum) //初始化線程池 創建線程池 { struct pthreadpool *pool = (struct pthreadpool *)malloc(sizeof(struct pthreadpool)); //创建一个线程池初始化的结构体 pool->m_QueueCurNum = 0;//当前任务队列的任务数 pool->m_QueueMaxNum = QueueMaxNum;//任务队列的最大最大任务数 pool->head = NULL; pool->rear = NULL; pool->m_threadNum = ThreadNum;//已经开启的线程数量也就是创建的线程数量 pool->m_pthreadIDs = (pthread_t *)malloc(sizeof(pthread_t) * ThreadNum);//保存已开启的线程IO //动态数组名 保证后续指针的移动合法 pthread_mutex_init(&pool->mutex, NULL);//初始化一把锁 pthread_cond_init(&pool->m_QueueEmpty, NULL);//任务队列为空条件 pthread_cond_init(&pool->m_QueueNotEmpty, NULL);//任务队列不为空的条件 pthread_cond_init(&pool->m_QueueNotFull, NULL);//任务队列不满的条件 for (int i = 0; i < ThreadNum; i++) { pthread_create(&pool->m_pthreadIDs[i], NULL, ThreadRun, pool); } return pool; } //將任務函數添加到任務隊列 void ThreadAddJob(struct pthreadpool *pool, void *(*func)(void *arg), void *arg)// { pthread_mutex_lock(&pool->mutex); if (pool->m_QueueCurNum == pool->m_QueueMaxNum) { printf("任务队列已满,挂起等待线程执行完毕。。。n"); pthread_cond_wait(&pool->m_QueueNotFull, &pool->mutex); } struct job *pjob = (struct job *)malloc(sizeof(struct job)); //创建任务队列 pjob->func = func;//任务函数通过任务传参传入任务函数 pjob->arg = arg;//任务函数的参数 // pjob->func(pjob->arg); pjob->next = NULL; if (pool->head == NULL)//如果任务队列 里面没有任务 { pool->head = pool->rear = pjob;//那么将任务函数放置头结点处 pthread_cond_broadcast(&pool->m_QueueNotEmpty); //添加任务后,唤醒任意一个线程开始执行任务 } else { pool->rear->next = pjob;//如果任务队列有任务 就将新的任务函数放在任务队的末尾 pool->rear = pjob;//尾指针指向最后一盒任务函数 } pool->m_QueueCurNum++;//当前任务数量++ pthread_mutex_unlock(&pool->mutex); } //銷毀線程池 void ThreadDestroy(struct pthreadpool *pool) { pthread_mutex_lock(&pool->mutex); while (pool->m_QueueCurNum != 0) { printf("阻塞等待销毁线程。。。n"); pthread_cond_wait(&pool->m_QueueEmpty, &pool->mutex); } printf("任务结束,线程%ld被销毁n", pthread_self()); pthread_mutex_unlock(&pool->mutex); pthread_cond_broadcast(&pool->m_QueueNotEmpty); pthread_cond_broadcast(&pool->m_QueueNotFull); int i; for (i = 0; i < pool->m_threadNum; i++) { pthread_join(pool->m_pthreadIDs[i], NULL); } pthread_mutex_destroy(&pool->mutex); pthread_cond_destroy(&pool->m_QueueEmpty); pthread_cond_destroy(&pool->m_QueueNotEmpty); pthread_cond_destroy(&pool->m_QueueNotFull); free(pool->m_pthreadIDs); struct job *tmp; while (pool->head != NULL) { tmp = pool->head; pool->head = pool->head->next; free(tmp); } free(pool); } //任务工作函数 void *work(void *arg) { Myarg *workarg = (Myarg *)arg; printf("work: %dn", workarg->fd); printf("msg: %sn",workarg->msg.msg); printf("msg: %dn",workarg->msg.flag); switch(workarg->msg.flag) { case REGISTER: Register(workarg,&workarg->msg);//注册用户 printf(" 注册用户n"); break; case LOGIN: login(workarg,&workarg->msg);//登录 printf("用户登录功能n"); break; case PRIVATE: privatechat(workarg,&workarg->msg); //私聊 printf("私聊功能n"); break; case CHPASSWORD: changepassword(workarg,&workarg->msg); //修改密码 printf("修改密码n"); break; case GROUPCHAT: groupchat(workarg,&workarg->msg);//进行群聊 break; case VIEWUSER: //查看所有在线用户 viewonline_user(workarg,&workarg->msg); break; case LOGUSER://注销用户 loguser(workarg,&workarg->msg); break; case CHECKRECORD: Checkrecord(workarg);//查看聊天记录 break; case FILETRAN: filetransfer(workarg,&workarg->msg); //文件传输 break; case APPLYROOT: applyroot(workarg,&workarg->msg); //申请管理员用户 break; case ROOTLOGIN: rootlogin(workarg,&workarg->msg); //管理员登录 break; case ROOTKICK: rootkick(workarg,&workarg->msg); //管理员踢人 break; case SILENT: silent(workarg,&workarg->msg); //管理员禁言 break; case REMSILENT: remsilent(workarg,&workarg->msg); //管理员解除用户禁言 break; case CANCELROOT: cancelroot(workarg,&workarg->msg); //取消管理员身份 break; default: break; } free(arg); } //在线用户链表 online_userlist* online_userlistcreate() { online_userlist *head = (online_userlist *)malloc(sizeof(online_userlist)); head->next = NULL; return head; } //注册部分 void Register(Myarg *node,clientlist *c) { printf("判断:%s 是否在数据库n",c->name); int ret = searchtable(c->name); //在数据库中查找是否已经注册过 printf("%d",ret); if(1 == ret) { char arr[128] = {"账号已经存在,请重新注册"}; if(send(node->fd,arr,sizeof(arr),0) == -1) { ERRLOG("send error"); } return; } else { insert_updata(node,c); //向数据库中插入数据 } } //向数据库中插入注册数据 void insert_updata(Myarg *node,clientlist *c) { printf("注册的名字%sn",c->name); char *errmsg; sqlite3 *db =NULL; char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql sprintf(sql,"insert into user(name,password) values('%s','%s')",c->name,c->password); printf("数据库sql语句测试n"); execstate(sql); printf("33[0;34m插入成功33n"); char buf[100] = {"[系统日志]:注册成功...n"}; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } //在数据库查询用户 c存在返回1 不存在返回0 int searchtable(char *tablename) { int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char sql[200] = ""; sprintf(sql,"select *from user;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i < nrow+1;i++) { int ret = strcmp(result[i*ncolumn + 0],tablename); if(ret == 0) { flag = 1; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("数据库是否存在该用户%d存在n",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else { flag = 0; printf("%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //执行sql语句函数 void execstate(char *sql)//执行SQL语句 { sqlite3 *db =NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { ERRLOG("sqlite3_open"); } char *errmsg; ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg); if(SQLITE_OK != ret) { ERRLOG("sqlite3_exec"); } ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite_close:"); exit(1); } } //登录部分 void login(Myarg *node,clientlist *c) { //判断是否注册 if(0 == (searchtable(c->name))) { char buf[32] = "该用户不存在,请注册..."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else if( 0 == (veridandpassword(c)))//密码错误 { char buf[20] = "密码输入错误.."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else if(1 == (veridandpassword(c)))//返回值为1账号密码正确 { if(1 ==Repeatlogin(node,c))//判断重复登录 { online_insertion(node,c); char buf[32] = "登录成功.."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } online_userlist *p = head; p=p->next; while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { if(p->c_fd != 0) { char buf[50] = ""; sprintf(buf,"[%s]:上线了",c->name); if(send(p->c_fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } memset(buf,0,sizeof(buf)); } p=p->next; } sleep(2); sendOfflinemessage(node,c); } else { return; } } } //重复登录判断 int Repeatlogin(Myarg *node,clientlist *c) { printf("正在判断是否重复登录n"); char s1[32]={0}; strcpy(s1,c->name);//判断自己是否登录 printf("正在判断%s是否在线n",c->to_name); online_userlist *p = head; while(p!=NULL) { if(strcmp(s1,p->name) == 0 ) { printf("%s在线,重复登录n",p->name); char buf[32] = "您已在线,请勿重复登录"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } return 0; } p=p->next; } printf("未遍历到该用户,可以进行登录n"); return 1; } //登录插入链表 void online_insertion(Myarg *node,clientlist *c) { online_userlist *tmp=(online_userlist *)malloc(sizeof(online_userlist)); tmp->next=NULL; online_userlist *p =head;//定义一个指针为表头 strcpy(tmp->name,c->name); tmp->c_fd = node->fd; printf("判断:%s,%d是否进行插入链表n",tmp->name,tmp->c_fd); if(1==onlineempty()) {printf("1"); tmp->next=p->next;//令新插入的结点指针指向下一个结点 p->next=tmp; } else {printf("2"); while(p->next!=NULL&&strncmp(p->next->name , tmp->name,1)<0)//当目的name小于源name { p=p->next; } //当p->next指向的数据大于或者等于需要插入的数据是跳出循环 //此事p->next 向的是第一个大于value的值 tmp->next=p->next; p->next=tmp; //然后将其插入大于value的值之前 putchar(10); } printf("链表插入完成n"); } //验证账户与密码 正确返回1 错误返回0; int veridandpassword(clientlist *p) { printf("已进入密码效验工作n"); int flag; sqlite3 *db = NULL; //数据库的名字记得更换 int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } printf("已打开数据库n"); char sql[200] = ""; sprintf(sql,"select *from user;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; int ret1,ret2; printf("已进行遍历数据库n"); for(i = 0 ; i < nrow+1;i++) { ret1 = (strcmp(result[i*ncolumn + 0],p->name)); ret2 = (strcmp(result[i*ncolumn + 1],p->password)); printf("正在进行账户密码效验n"); printf("账户:%sn",result[i*ncolumn + 0]); printf("密码:%sn",result[i*ncolumn + 1]); printf("密码:%sn",p->password); if(0 == ret1 && 0 == ret2) { flag = 1; break; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("核对返回值为%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else{ flag = 0; sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //判断链表是否为空 int onlineempty() { if (head->next==NULL) { return 1 ; } else {printf("kong3n"); return 0; } } //判断除自己是否还有别人在线 int onlineempty1() { if (head->next->next==NULL) { return 1 ; } else { return 0; } } //私聊部分 void privatechat(Myarg *node,clientlist *c) { int flag = 0; printf("正在运行私聊函数n"); int to_cfd = Find_person(c); //在线返回对方的文件描述符 printf("私聊对象的文件描述符为%dn",to_cfd); if(1 == sensitiveword(c->msg)) { printf("该消息存在敏感词n"); char buf2[128] = ""; sprintf(buf2,"[系统日志]:你的消息中存在敏感词汇,无法发送"); if(send(node->fd,buf2,sizeof(buf2),0) == -1) { ERRLOG("send error"); } return; } if(0 == to_cfd) { saveOfflinemessage(c); char buf[32] = "对方不在线..."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else { if(0 == flag) { char buf1[128] = ""; sprintf(buf1,"[系统日志]:正在与%s进行私聊",c->to_name); if(send(node->fd,buf1,sizeof(buf1),0) == -1) { ERRLOG("send error"); } flag++; } printf("正在进行消息:%s转发n",c->msg); char buf[128] = ""; sprintf(buf,"[%s悄悄对你说了一句]:%s",c->name,c->msg); if(send(to_cfd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } } //判断是否在线 在线返回对方文件描述符 不在线返回0 int Find_person(clientlist *c) { char s1[32]={0}; strcpy(s1,c->to_name);//想跟s1进行私聊 printf("正在判断%s是否在线n",c->to_name); online_userlist *p = head; while(p!=NULL) { if(strcmp(s1,p->name) == 0 ) { printf("%s在线n",p->name); return p->c_fd;//私聊对象的文件描述符 } p=p->next; } return 0; } //判断是否为敏感词 存在返回1 不存在返回0 int sensitiveword(char *sensitive) { printf("正在进行敏感词判断n"); int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char sql[200] = ""; sprintf(sql,"select *from sensitive;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i <nrow+1;i++) { printf("数据库遍历结果%sn",result[i*ncolumn + 0]); int ret = strcmp(result[i*ncolumn + 0],sensitive); if(ret == 0) { flag = 1; break; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("数据库是否存在该用户%d存在n",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else { flag = 0; printf("数据库遍历返回值%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //离线消息保存至表中 void saveOfflinemessage(clientlist *c) { time_t timep; struct tm *p; time (&timep); p=gmtime(&timep); char newtime[32] = {0}; memset(newtime,0,32); sprintf(newtime,"%d-%d-%d:%d:%dn",1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec); printf("获取时间%sn",newtime); char *errmsg; sqlite3 *db =NULL; char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql sprintf(sql,"insert into message(name,toname,message,time) values('%s','%s','%s','%s')",c->name,c->to_name,c->msg,newtime); printf("数据库sql语句测试n"); execstate(sql); printf("33[0;34m插入成功33n"); } //修改密码部分 void changepassword(Myarg *node,clientlist *c) { printf("用户%s将吧密码修改为%s",c->name,c->msg); Insert_updated_data(c->name,c->msg); char buf1[600] = ""; sprintf(buf1,"[系统日志]:密码修改成功"); if(send(node->fd,buf1,sizeof(buf1),0) == -1) { ERRLOG("send error"); } printf("用户%s已成功修改密码",c->name); exituser(c); } //根据名字修改密码 void Insert_updated_data(char *name,char *password) { char sql[500] = ""; sprintf(sql,"update user set password = '%s' where name = '%s';",password,name); execstate(sql); } //退出群聊 删除链表内的用户结点 void exituser(clientlist *c) { online_userlist *p = head; online_userlist *q; while(p->next!=NULL) { if(strcmp(c->name,p->next->name)==0) { q=p->next; p->next=p->next->next; free(q); q=NULL; printf("将%s踢出链表成功n",c->name); return; } p=p->next; } } //群聊部分 void groupchat(Myarg *node,clientlist *c) { printf("正在运行管理员群聊函数n"); online_userlist *p = head; int ret; ret = onlineempty1(p); if(1 == ret) { char buf1[128] = ""; strcpy(buf1,"[系统日志]:当前没有别的用户在线"); if(send(node->fd,buf1,sizeof(buf1),0) == -1) { ERRLOG("send error"); } return; } printf("正在遍历链表给每个用户发送消息n"); printf("打印管理员标志%dn",c->root); if(1 == sensitiveword(c->msg)) { printf("该消息存在敏感词%sn",c->msg); char buf2[128] = ""; sprintf(buf2,"[系统日志]:你的消息中存在敏感词汇,无法发送"); if(send(node->fd,buf2,sizeof(buf2),0) == -1) { ERRLOG("send error"); } return; } if(c->root == 1) { getheadflag(c);//获取管理员头像 printf("打印管理员头像%sn",c->emojio); p=p->next; while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { if(strcmp(p->name,c->name) != 0) { printf("打印文件描述符%d n",p->c_fd); char buf[128] = ""; sprintf(buf,"%s[%s]:%s",c->emojio,c->name,c->msg); if(send(p->c_fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } memset(buf,0,sizeof(buf)); } p=p->next; } } else { p=p->next; while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { if(strcmp(p->name,c->name) != 0) { printf("打印文件描述符%d n",p->c_fd); char buf[100] = ""; sprintf(buf,"[%s]:%s",c->name,c->msg); if(send(p->c_fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } memset(buf,0,sizeof(buf)); } p=p->next; } } } //获取管理员头像 void getheadflag(clientlist *c) { int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char sql[200] = ""; sprintf(sql,"select *from root;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i < nrow+1;i++) { int ret = strcmp(result[i*ncolumn + 1],c->name); if(ret == 0) { strcpy(c->emojio,result[i*ncolumn + 0]); flag = 1; printf("当前管理员头像%sn",result[i*ncolumn + 0]); printf("c->emojio=%sn",c->emojio); }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("管理员头像获取成功%s存在n",c->emojio); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return; } else { printf("管理员头像获取失败%d不存在n",flag); flag = 0; printf("%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return; } } //查看所有在线用户 void viewonline_user(Myarg *node,clientlist *c) { online_userlist *p = head->next; int ret; ret = onlineempty(p); if(1 == ret) { char buf1[128] = ""; strcpy(buf1,"[系统日志]:当前没有别的用户在线"); if(send(node->fd,buf1,sizeof(buf1),0) == -1) { ERRLOG("send error"); } return; } while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { if(p->c_fd != 0) { char buf[70] = {0}; memset(buf,0,sizeof(buf)); printf("%s当前在线3n",p->name); sprintf(buf,"[%s]:当前在线",p->name); if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } sleep(1); } p=p->next; } } //注销用户 void loguser(Myarg *node,clientlist *c) { deleteuser(c); if(c->root == 1) { deleteroot(c); } printf("注销用户删除数据库成功n"); char buf[32] = "注销成功.."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } exituser(c); printf("注销用户删除链表结点成功n"); } //指定删除数据库里面的用户 void deleteuser(clientlist *c) { char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql sprintf(sql,"delete from user where name = '%s';",c->name); execstate(sql); printf("删除数据库内容成功n"); return; } //指定删除数据库里面的root用户 void deleteroot(clientlist *c) { char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql sprintf(sql,"delete from root where name = '%s';",c->name); execstate(sql); printf("删除root内容成功n"); return; } //查看聊天记录部分 //将聊天记录插入记录表(保存聊天记录) void insert_uprecord(clientlist *c) { printf("正在进行聊天记录存储n"); printf("聊天方式标志位:%d",c->flag); printf("聊天内容:%s",c->msg); if(1 == sensitiveword(c->msg)) { return; } time_t timep; struct tm *p; time (&timep); p=gmtime(&timep); char newtime[32] = {0}; sprintf(newtime,"%d-%d-%d:%d:%dn",1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec); printf("获取时间%sn",newtime); char *errmsg; sqlite3 *db =NULL; char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql pthread_mutex_lock(&mutex); sprintf(sql,"insert into record(time,name,record) values('%s','%s','%s')",newtime,c->name,c->msg); printf("数据库sql语句测试n"); execstate(sql); pthread_mutex_unlock(&mutex); printf("33[0;34m聊天记录保存成功33n"); } //查看聊天记录 void Checkrecord(Myarg *node) { printf("已进入聊天记录返回客户端工作n"); int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } printf("已打开数据库n"); char sql[200] = ""; sprintf(sql,"select *from record;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; int ret1,ret2; printf("已进行遍历数据库n"); char buf[256] = {0}; for(i = 1 ; i < nrow+1;i++) { printf("正在将聊天记录发送给客户端n"); sprintf(buf,"%sn[%s]:%s",result[i*ncolumn + 0],result[i*ncolumn + 1],result[i*ncolumn + 2]); printf("时间:%sn",result[i*ncolumn + 0]); printf("用户:%sn",result[i*ncolumn + 1]); printf("消息内容:%sn",result[i*ncolumn + 2]); printf("%s",buf); if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } } //管理员申请部分 //管理员用户的申请 void applyroot(Myarg *node,clientlist *c) { printf("正在判断:%s 是否已经是管理员n",c->name); int ret = searchtableroot(c->name); printf("%d",ret); if(1 == ret) { char arr[128] = {"您已是管理员.."}; if(send(node->fd,arr,sizeof(arr),0) == -1) { ERRLOG("send error"); } return; } else { insert_updataroot(node,c); } } //在数据库中管理员表中查看是否存在该管理员 int searchtableroot(char *tablename) { int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char sql[200] = ""; sprintf(sql,"select *from root;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i < nrow+1;i++) { int ret = strcmp(result[i*ncolumn + 1],tablename); if(ret == 0) { flag = 1; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("root表中该用户%d存在n",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else { printf("root表中该用户%d不存在n",flag); flag = 0; printf("%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //向root表中插入数据 void insert_updataroot(Myarg *node,clientlist *c) { printf("申请管理员的用户%sn",c->name); char *errmsg; sqlite3 *db =NULL; char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql pthread_mutex_lock(&mutex); sprintf(sql,"insert into root(head,name,password) values('%s','%s','%s');",c->emojio,c->name,c->password); printf("将 头像:%s,名字;%s,密码:%s 插入表中n",c->emojio,c->name,c->password); execstate(sql); pthread_mutex_unlock(&mutex); printf("33[0;34m插入成功33n"); char buf[100] = {"管理员申请成功"}; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } exituser(c);//注册完将其踢出链表让其进入初始界面从新登录 return; } //管理员登录部分 //管理员登录 void rootlogin(Myarg *node,clientlist *c) { if(0 == (searchtableroot(c->name))) { char buf[32] = "该用户非管理员"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else if( 0 == (rootveridandpassword(c)))//密码错误 { char buf[20] = "密码输入错误"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else if(1 == (rootveridandpassword(c)))//返回值为1账号密码正确 { if(rootRepeatlogin(node,c)) { online_insertion(node,c); char buf[32] = "管理员登录成功.."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } online_userlist *p = head; p=p->next; while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { if(p->c_fd != 0) { char buf[70] = ""; sprintf(buf,"%s[%s]:上线了",c->emojio,c->name); if(send(p->c_fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } memset(buf,0,sizeof(buf)); } p=p->next; } } else { return; } } } //判断管理员用户与密码 int rootveridandpassword(clientlist *c) { printf("已进入管理员的密码效验工作n"); int flag; sqlite3 *db = NULL; //数据库的名字记得更换 int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } printf("已打开数据库n"); char sql[200] = ""; sprintf(sql,"select *from root;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; int ret1,ret2; printf("已进行遍历数据库n"); for(i = 0 ; i < nrow+1;i++) { ret1 = (strcmp(result[i*ncolumn + 1],c->name)); ret2 = (strcmp(result[i*ncolumn + 2],c->password)); printf("正在进行账户密码效验n"); printf("账户:%sn",result[i*ncolumn + 1]); printf("密码:%sn",result[i*ncolumn + 2]); printf("密码:%sn",c->password); if(0 == ret1 && 0 == ret2) { strcpy(c->emojio,result[i*ncolumn + 0]); printf("打印管理员存在数据库中的头像%s",result[i*ncolumn + 0]); printf("打印被赋值后的当前结构体头像%s",c->emojio); flag = 1; break; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("核对返回值为%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else{ flag = 0; sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //管理员重复登录判断 int rootRepeatlogin(Myarg *node,clientlist *c) { printf("正在判断是否重复登录n"); char s1[32]={0}; strcpy(s1,c->name);//判断自己是否登录 printf("正在判断%s是否在线n",c->to_name); online_userlist *p = head; while(p!=NULL) { if(strcmp(s1,p->name) == 0 ) { printf("%s在线,重复登录n",p->name); char buf[32] = "您已在线,请勿重复登录"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } return 0; } p=p->next; } printf("未遍历到该用户,可以进行登录n"); return 1; } //文件传输部分 //文件传输 void filetransfer(Myarg *node,clientlist *c) { MSG msg; printf("正在运行文件传输函数n"); int to_cfd = Find_person(c); //在线返回对方的文件描述符 printf("私聊对象的文件描述符为%dn",to_cfd); char buf[256] = ""; printf("***********11111n"); printf("%s",c->buf); printf("***********22222n"); strcpy(msg.text,c->buf); msg.num = c->num; if(0 == to_cfd) { char buf1[32] = "对方不在线..."; if(send(node->fd,buf1,sizeof(buf),0) == -1) { ERRLOG("send error"); } sleep(2); } else { while(flag2) { printf("正在向对方发送文件传输信号n"); if(send(to_cfd,"文件存在进行文件传输",M,0) == -1) { ERRLOG("send error"); } flag2 = 0; } if(c->num == 0) { printf("文件内容全部发送完成n"); flag2 = 1; } sleep(1); printf("本次向对方送的内容%sn",msg.text); if(send(to_cfd,&msg,sizeof(msg),0) == -1) { ERRLOG("send error"); } printf("单次发送内容完成n"); memset(&msg,0,sizeof(msg)); } return; } //管理员功能部分 //管理员踢人 void rootkick(Myarg *node,clientlist *c) { int to_cfd = Find_person(c); //在线返回对方的文件描述符 printf("踢出对象的文件描述符为%dn",to_cfd); if(0 == to_cfd) { char buf[32] = "对方不在线..."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else { if(searchtableroot(c->to_name) == 1) { char buf[128] = "对方是管理员,无法进行操作"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } return; } else { char buf[128] = "管理员已将你踢出聊天室"; if(send(to_cfd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } } } //管理员禁言 void silent(Myarg *node,clientlist *c) { int to_cfd = Find_person(c); //在线返回对方的文件描述符 printf("禁言对象的文件描述符为%dn",to_cfd); if(0 == to_cfd) { char buf[32] = "对方不在线..."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else { if(searchtableroot(c->to_name) == 1) { char buf[128] = "对方是管理员,无法进行操作"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } return; } else { char buf[128] = "管理员已将你禁言"; if(send(to_cfd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } } } //管理员解除禁言 void remsilent(Myarg *node,clientlist *c) { int to_cfd = Find_person(c); //在线返回对方的文件描述符 printf("解除禁言对象的文件描述符为%dn",to_cfd); if(0 == to_cfd) { char buf[32] = "对方不在线..."; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } else { char buf[128] = "管理员已将你解除禁言"; if(send(to_cfd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } } } //撤销管理员身份 void cancelroot(Myarg *node,clientlist *c)// 功能标志15 撤销管理员身份 { char buf[128] = "撤销成功"; if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } deleteroot(c); exituser(c); return; } //离线消息的保存与发送 //离线消息发送 void sendOfflinemessage(Myarg *node,clientlist *c) { if(searchtuser(c->name) == 1) { sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char buf[128] = {0}; char sql[200] = ""; memset(buf,0,128); memset(sql,0,200); sprintf(sql,"select *from message;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i < nrow+1;i++) { int ret = strcmp(result[i*ncolumn + 1],c->name); if(ret == 0) { printf("正在将离线消息发送给客户端n"); sprintf(buf,"%sn[%s对你说了一句]:%s",result[i*ncolumn + 3],result[i*ncolumn + 0],result[i*ncolumn + 2]); printf("时间:%sn",result[i*ncolumn + 0]); printf("用户:%sn",result[i*ncolumn + 1]); printf("消息内容:%sn",result[i*ncolumn + 2]); printf("%s",buf); if(send(node->fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } }//0行就是第一行 第i行第j列 } deleteumessage(c); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } } else { return; } } //在数据库中查找是否有该用户的离线消息 存在返回1 不存在返回0 int searchtuser(char *username) { int flag; sqlite3 *db = NULL; int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char sql[200] = ""; sprintf(sql,"select *from message;"); char *errmsg;//定义指着指向错误信息 char **result;//相当于二维数组 保存查询到的信息 int nrow,ncolumn;//分别代表行和列 ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg); int j,i; int Index = ncolumn; for(i = 1 ; i < nrow+1;i++) { int ret = strcmp(result[i*ncolumn + 1],username); if(ret == 0) { flag = 1; }//0行就是第一行 第i行第j列 } if(flag == 1) { printf("数据库是否存在该用户%d存在n",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } else { flag = 0; printf("%dn",flag); sqlite3_free_table(result);//释放数据库 ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return flag; } } //指定删除数据库里面的离线消息 void deleteumessage(clientlist *c) { char sql[200] = ""; memset(sql,0,sizeof(sql));//清空sql sprintf(sql,"delete from message where toname = '%s';",c->name); execstate(sql); printf("删除数据库消息成功n"); } //创建表 注意更换数据库 void createtable() { sqlite3 *db = NULL; //目标数据库 int ret = sqlite3_open("user.db",&db); if(SQLITE_OK != ret) { perror("sqlite3_open"); exit(1); } char *errmsg; char sql[500] = ""; strcpy(sql,"create table user (name text,password text);"); ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg); if(SQLITE_OK != ret) { perror("sqlite3_exec:"); printf("errmsg:%sn",errmsg); exit(1); } ret = sqlite3_close(db); if(SQLITE_OK != ret) { perror("sqlite3_close:"); exit(1); } return; } //异常掉线处理 void Offlineprocessing(int fd) { char buf2[20] = ""; online_userlist *p = head; online_userlist *q; online_userlist *p1 = head; while(p->next!=NULL) { if(p->next->c_fd==fd) { strcpy(buf2,p->next->name); q=p->next; p->next=p->next->next; free(q); q=NULL; printf("将%s踢出链表成功n",buf2); break; } p=p->next; } char buf[50] = ""; memset(buf,0,sizeof(buf)); sprintf(buf,"[%s]:退出了",buf2); printf("退出信息拷贝确认"); p1=p1->next; while(p1!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环 { printf("客户退出遍历链表测试n"); if(send(p1->c_fd,buf,sizeof(buf),0) == -1) { ERRLOG("send error"); } p1=p1->next; } }
server.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225#ifndef SERVER_H_ #define SERVER_H_ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <sys/socket.h> #include <pthread.h> #include <arpa/inet.h> #include <sys/errno.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h> #include <sys/epoll.h> #include <sqlite3.h> #define M 256 #define REGISTER 1//注册 #define LOGIN 2 //登录 #define PRIVATE 3 //私聊 #define CHPASSWORD 4 //修改密码 #define GROUPCHAT 5 //群聊 #define VIEWUSER 6 //查看在线用户 #define LOGUSER 7 //注销用户 #define CHECKRECORD 8 //查看聊天记录 #define FILETRAN 9 //文件传输 #define APPLYROOT 10 //管理员注册 #define ROOTLOGIN 11 //管理员登录 #define ROOTKICK 12 //管理员踢人 #define SILENT 13 //管理员禁言 #define REMSILENT 14 //解除禁言 #define CANCELROOT 15 //撤销管理员身份 #define ERRLOG(errmsg) do{ perror(errmsg); printf("%s - %s - %dn", __FILE__, __func__, __LINE__); exit(1); }while(0) //1通信协议 typedef struct client { char emojio[20]; //头像保存 char name[32]; //姓名 char msg[50]; //聊天内容 char password[32]; //密码 char to_name[50]; //聊天对象 char buf[256]; //文件内容 int num; //文件读取大小 int root; //管理员标志 int flag; //功能标志 注册标志1 登录2 私聊3 修改密码4 群聊界面5 查看在线用户6 注销用户7 查看聊天记录8 下载文件9 }clientlist; //文件传输使用的结构体 typedef struct file { char text[M]; int num; }MSG; //在线用户链表 typedef struct online_user { char name[32];//姓名 int c_fd; struct online_user*next; //指针域 }online_userlist; //线程池 typedef struct Myarg { clientlist msg; int fd; }Myarg; //任务队列 struct job{ void*(*func)(void *arg); void *arg; //给回调函数传参使用 struct job *next; }; struct pthreadpool//线程池的初始化 { int m_threadNum; //已开启的线程的数量 pthread_t *m_pthreadIDs; //保存线程池中线程的ID struct job *head; //任务队列的头 struct job *rear; //任务队列的尾 int m_QueueMaxNum; //任务队列的最大数 int m_QueueCurNum; //目前任务队列的任务数 pthread_mutex_t mutex; pthread_cond_t m_QueueEmpty; //任务队列为空的条件 pthread_cond_t m_QueueNotEmpty; //任务队列不为空的条件 pthread_cond_t m_QueueNotFull; //任务队列为空的条件 }; //线程函数 void *work(void *arg); //函数声明 void *ThreadRun(void *arg); //初始化线程池 struct pthreadpool *InitPthreadPool(int ThreadNum, int QueueMaxNum); //添加任务队列 void ThreadAddJob(struct pthreadpool *pool, void *(*func)(void *arg), void *arg); //销毁线程池 void ThreadDestroy(struct pthreadpool *pool); //初始化 int socket_init(); //epoll函数 int mypoll(int sockfd); //在线用户链表 online_userlist* online_userlistcreate(); //注册 void Register(Myarg *node,clientlist *c); //向数据库中插入注册数据 void insert_updata(Myarg *node,clientlist *c); //在数据库中查询用户 int searchtable(char *tablename); //执行sql语句函数 void execstate(char *sql); //登录部分 void login(Myarg *node,clientlist *c); //登录插入链表 void online_insertion(Myarg *node,clientlist *c); //核验密码和账户是否正确 int veridandpassword(clientlist *p); //重复登录判断 int Repeatlogin(Myarg *node,clientlist *c); //判断除自己以外是否还有别人在线 int onlineempty1(); //判断链表是否为空 int onlineempty(); //私聊部分 void privatechat(Myarg *node,clientlist *c); //判断是否在线 在线返回对方文件描述符 不在线返回0 int Find_person(clientlist *c); //判断是否为敏感词 存在返回1 不存在返回0 int sensitiveword(char *sensitive); //离线消息保存至表中 void saveOfflinemessage(clientlist *c); //修改密码部分 void changepassword(Myarg *node,clientlist *c); //根据名字修改密码 void Insert_updated_data(char *name,char *password); //退出聊天室 删除链表内的用户结点 void exituser(clientlist *c); //群聊部分 void groupchat(Myarg *node,clientlist *c); //获取管理员头像 void getheadflag(clientlist *c); //查看所有在线用户 void viewonline_user(Myarg *node,clientlist *c); //注销用户 void loguser(Myarg *node,clientlist *c); //掉线处理 void Offlineprocessing(int fd); //将聊天记录保存 void insert_uprecord(clientlist *c); //指定删除数据库的数据 void deleteuser(clientlist *c); //指定删除数据库里面的root用户 void deleteroot(clientlist *c); //查看聊天记录 void Checkrecord(Myarg *node); //管理员用户的申请 void applyroot(Myarg *node,clientlist *c); //在数据库中管理员表中查看是否存在该管理员 int searchtableroot(char *tablename); //向root表中插入数据 void insert_updataroot(Myarg *node,clientlist *c); //管理员登录 void rootlogin(Myarg *node,clientlist *c); //判断管理员用户与密码 int rootveridandpassword(clientlist *c); //管理员重复登录判断 int rootRepeatlogin(Myarg *node,clientlist *c); //文件传输 void filetransfer(Myarg *node,clientlist *c); //管理员踢人 void rootkick(Myarg *node,clientlist *c); //管理员禁言 void silent(Myarg *node,clientlist *c); //管理员解除禁言 void remsilent(Myarg *node,clientlist *c); //撤销管理员身份 void cancelroot(Myarg *node,clientlist *c); //离线消息发送 void sendOfflinemessage(Myarg *node,clientlist *c); //在数据库中查找是否有该用户的离线消息 存在返回1 不存在返回0 int searchtuser(char *tablename); //指定删除数据库里面的离线消息 void deleteumessage(clientlist *c); //异常掉线处理 void Offlineprocessing(int fd); //char *exit1user(int fd); #endif
mian.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "server.h" online_userlist* head = NULL; //在线用户列表 struct pthreadpool *pool; extern struct pthreadpool *InitPthreadPool(int ThreadNum, int QueueMaxNum);//初始化线程池 int main() { head = online_userlistcreate(); //创建在线用户链表 int sockfd = socket_init(); pool = InitPthreadPool(1, 10);//1个线程对10个任务 mypoll(sockfd); return 0; }
客户端
client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068#include "clientaddr.h" unsigned char ip_str[] = "192.168.91.151"; unsigned char port_str[] = "8787"; int flag1 = 0; int flag2 = 1; int flag3 = 1;//文件传输对方是否在线标志 void n_init()//客户端初始化框架 { clientfd2 = socket(AF_INET,SOCK_STREAM,0); if(clientfd2 == -1) { perror("socket"); return; } struct sockaddr_in clientaddr; clientaddr.sin_family = AF_INET;//协议族 IPV4 clientaddr.sin_addr.s_addr = inet_addr(ip_str); /*in_addr_t inet_addr(const char *cp);将点分十进制字符串ip地址转化为网络序的无符号4字节 整数ip地址*/ int addrlen = sizeof(clientaddr); clientaddr.sin_port = htons(atoi(port_str)); if(connect(clientfd2,(struct sockaddr *)&clientaddr,addrlen)==-1) { perror("33[0;31m无法连接到服务器33[0mn"); ERRLOG("connect"); } return; } void selectfun()//进入页面选着功能 { usleep(500*1000); system("clear"); printf("33[0;46m*===================================================================*33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m|*********************33[0;33m欢迎来到防脱发研究中心33[0;46m************************|33[0mn"); printf("33[0;46m| ???? 33[1;43;33m作者:ZJN 33[0;46m |33[0mn"); printf("33[0;46m| 版本:epoll+线程池 |33[0mn"); printf("33[0;46m|-------------------------------------------------------------------|33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m| 33[0;35m1.用户登录????33[0;46m |33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m| 33[0;32m2.帐号注册????33[0;46m |33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m| 33[0;33m3.管理员登录????33[0;46m |33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m| 33[0;31m 0:退出聊天室????33[0;46m |33[0mn"); printf("33[0;46m| |33[0mn"); printf("33[0;46m*===================================================================*33[0mn"); printf("n"); int num; scanf("%d",&num); getchar(); switch (num) { case 0: exit_room();//退出聊天室 break; case 1: system("clear"); printf("33[0;31m正在进行用户登录..33[0mn"); system("./zjn"); user_login();//登录 break; case 2: system("clear"); printf("33[0;31m正在进行账号注册33[0mn"); user_register();//返回注册页面 selectfun(); break; case 3: system("clear"); printf("33[0;31m正在进行管理员登录33[0mn"); rootlogin(); putchar(10); break; case 4: system("clear"); printf("33[0;31m正在退出聊天室33[0mn"); exit_room(); putchar(10); break; default: system("clear"); printf("33[0;31m对不起输入错误请从新输入..33[0mn"); selectfun(); return; } } void funcinto()//第二阶段选择进入 { system("clear"); printf("33[34m 33[0;36m<1:私聊功能>????33[0;34m 33[0mn"); putchar(10); printf("33[34m 33[0;36m????<2:进入群聊>33[0;34m 33[0mn"); putchar(10); printf("33[34m 33[0;36m<3:修改密码>????33[0;34m 33[0mn"); putchar(10); printf("33[0;31m 33[0;36m????<4:查看当前在看用户>33[0;34m 33[0mn"); putchar(10); printf("33[34m 33[0;31m<5:注销用户>????33[0;34m 33[0mn"); putchar(10); printf("33[33m 33[0;33m????<6:申请称为管理员>33[0;34m 33[0mn"); putchar(10); printf("33[34m 33[0;33m????<0:退出聊天室>33[0;34m 33[0mn"); int num; scanf("%d",&num); getchar(); switch (num) { case 0: printf("33[0;31m正在退出聊天室..33[0mn"); exit_room(); putchar(10); break; case 1: system("clear"); printf("33[0;31m正在进入私聊功能..33[0mn"); privatechat(); funcinto(); break; case 2: system("clear"); printf("33[0;31m正在入群聊功能33[0mn"); groupchat(); funcinto(); break; case 3: system("clear"); printf("33[0;31m正在进行修改密码33[0mn"); changpassword(); selectfun(); putchar(10); break; case 4: system("clear"); printf("33[0;31m正在查看在线用户33[0mn"); viewonline_user(); sleep(3); funcinto(); break; case 5: system("clear"); printf("33[0;31m正在进行注销用户33[0mn"); deleteuser(); sleep(1); selectfun(); putchar(10); break; case 6: system("clear"); printf("33[0;31m正在申请成为管理员33[0mn"); applyroot(); putchar(10); break; default: system("clear"); printf("33[0;31m对不起输入错误请从新输入..33[0mn"); funcinto(); return; } } void user_register()//功能标志1 用户注册 { ssize_t ret; char password[50]; system("clear"); printf("33[0;31m请输入你的名字..33[0mn"); scanf("%s",ts.name); system("clear"); printf("33[0;31m请输入你的密码33[0mn"); system("stty -echo"); scanf("%s",password); system("stty echo"); system("clear"); printf("33[0;31m请再次确认你的密码33[0mn"); system("stty -echo"); scanf("%s",ts.password); system("stty echo"); if(strcmp(password,ts.password) == 0) { system("./zjn"); ts.flag = 1; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } return; } else { printf("33[0;31m输入密码不一致请从新输入...33[0mn"); sleep(1); user_register(ts); } } void user_login()//功能标志 2用户登录 { ssize_t ret; system("clear"); printf("33[0;31m请输入你的名字..33[0mn"); scanf("%s",ts.name); system("clear"); printf("33[0;31m请输入你的密码33[0mn"); system("stty -echo"); scanf("%s",ts.password); sleep(1); system("stty echo"); ts.flag = 2; //用户登录标志位 ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } sleep(1); if(1==flag1) { flag1 = 0; selectfun(); } if(0 == flag1) { funcinto(); } return; } void privatechat()// 功能标志3 用户私聊 { ssize_t ret; char to_name[50]; system("clear"); printf("33[0;31m请输入你想私聊的对象..33[0mn"); scanf("%s",ts.to_name); sleep(1); system("clear"); ts.flag = 3; //私聊标志为3 char buf[200] = ""; char *buf2; system("clear"); printf("33[0;31m请输入聊天内容..33[0mn"); //循环聊天记得加循环 printf("33[0;31m <输入Q!退出私聊>33[0mn"); printf("33[0;31m <输入W!查看快捷短语>33[0mn"); printf("33[0;31m [当前用户]:%s33[0mn",ts.name); while(1) { scanf("%s",buf); if(strcmp(buf,"Q!") == 0) { system("clear"); return; } if(strcmp(buf,"W!") == 0) { phrase(); continue; } if(flag2) { if((buf2 = selectphrase(buf)) == NULL) { strcpy(ts.msg,buf); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } else { strcpy(ts.msg,buf2); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } } } return; } void changpassword()//功能标志4 修改密码 { ssize_t ret; char newpassword[50]; char password[50]; system("clear"); printf("33[0;31m请输入你的新密码33[0mn"); system("stty -echo"); scanf("%s",newpassword); system("stty echo"); system("clear"); printf("33[0;31m请再次确认你的密码33[0mn"); system("stty -echo"); scanf("%s",password); system("stty echo"); if(strcmp(password,newpassword) == 0) { strcpy(ts.msg,newpassword); system("./zjn"); ts.flag = 4; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } return; } else { printf("33[0;31m输入密码不一致请从新输入...33[0mn"); sleep(1); changpassword(); } } void groupchat() //功能标志5 群聊 显示群聊界面 { int num = 0; ssize_t ret; system("./zjn"); ts.flag = 5; //私聊标志为5 char buf[200] = ""; char *buf2; system("clear"); printf("33[0;31m请输入聊天内容..33[0mn"); //循环聊天记得加循环 printf("33[0;31m <输入Q!退出群聊>33[0mn"); printf("33[0;36m <输入W!查看快捷短语>33[0mn"); printf("33[0;36m <输入C!查看聊天记录>33[0mn"); printf("33[0;36m <输入T!进行文件传输>33[0mn"); printf("33[0;31m [当前用户]:%s33[0mn",ts.name); while(1) { scanf("%s",buf); if(strcmp(buf,"Q!") == 0) { system("clear"); return; } if(strcmp(buf,"W!") == 0) { phrase(); printf("33[0;32m请输入1继续群聊..33[0mn"); scanf("%d",&num); if(1 == num) { break; } else { printf("33[0;32m输入错误33[0mn"); } } if(strcmp(buf,"C!") == 0) { checkrecord(); printf("33[0;32m请输入1继续群聊..33[0mn"); scanf("%d",&num); if(1 == num) { break; } else { printf("33[0;32m输入错误33[0mn"); } } if(strcmp(buf,"T!") == 0) { filetransfer(); sleep(1); break; } if(flag2) { if((buf2 = selectphrase(buf)) == NULL) { strcpy(ts.msg,buf); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } else { strcpy(ts.msg,buf2); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } } } groupchat(); } void viewonline_user()//功能标志6 查看所有在线用户 { ts.flag = 6; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } return; } void deleteuser() //功能标志 7 注销用户 { char password[30] = {0}; char name[30] = {0}; printf("33[0;31m 请认真确认你的用户信息33[0mn"); printf("33[0;31m<输入姓名>33[0mn"); scanf("%s",name); system("clear"); printf("33[0;31m<输入密码>33[0mn"); scanf("%s",password); int ret1,ret2; ret1 = strcmp(name,ts.name); ret2 = strcmp(password,ts.password); if(0 == ret1 && 0 == ret2) { ts.flag = 7; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } } void phrase()//快捷短语打印 { printf("33[34m 33[0;36m????<快捷短语大全>33[0;34m 33[0mn"); putchar(10); printf("33[34m 33[0;36m1.<听说jsetc给分配对象?????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m2.<????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m3.<????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m4.<????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m5.<????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m6.<真男人从不食????,只食????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m7.<????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m8.< 嘟嘟嘟!! ???? The car is coming>33[0;34m 33[0mn"); printf("33[34m 33[0;36m9.<就这么点?????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m10.< 来????????????????多吃点,别让人看扁 >33[0;34m 33[0mn"); printf("33[34m 33[0;36m11.<顺便给你分配个????????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m12.< Other people's money is my belongings???? >33[0;34m 33[0mn"); printf("33[34m 33[0;36m13.<Are you a dog?????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m14.<你是个什么????????>33[0;34m 33[0mn"); printf("33[34m 33[0;36m15.<一个巴掌拍不响但是加上一个????可以>33[0;34m 33[0mn"); } char *selectphrase(char *num)//快捷短语选择 { char *buf; buf = (char *)malloc(32); if(strcmp(num,"1.")==0) { strcpy(buf,"听说jsetc给分配对象?????"); return buf; } if(strcmp(num,"2.")==0) { strcpy(buf,"????"); return buf; } if(strcmp(num,"3.")==0) { strcpy(buf,"????"); return buf; } if(strcmp(num,"4.")==0) { strcpy(buf,"????"); return buf; } if(strcmp(num,"5.")==0) { strcpy(buf,"????"); return buf; } if(strcmp(num,"6.")==0) { strcpy(buf,"真男人从不食????,只食????"); return buf; } if(strcmp(num,"7.")==0) { strcpy(buf,"嘟嘟嘟!! ???? The car is coming"); return buf; } if(strcmp(num,"8.")==0) { strcpy(buf,"就这么点?????"); return buf; } if(strcmp(num,"9.")==0) { strcpy(buf,"来????????????????多吃点,别让人看扁"); return buf; } if(strcmp(num,"10.")==0) { strcpy(buf,"顺便给你分配个????????"); return buf; } if(strcmp(num,"11.")==0) { strcpy(buf,"Other people's money is my belongings????"); return buf; } if(strcmp(num,"12.")==0) { strcpy(buf,"Are you a dog?????"); return buf; } if(strcmp(num,"13.")==0) { strcpy(buf,"你是个什么????????"); return buf; } if(strcmp(num,"14.")==0) { strcpy(buf,"一个巴掌拍不响但是加上一个????可以"); return buf; } if(strcmp(num,"15.")==0) { strcpy(buf,"????"); return buf; } return NULL; } void checkrecord()//功能标志8 查看聊天记录 { ts.flag = 8; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } void filetransfer()//功能标志9 文件传输 { clientlist ts1; strcpy(ts1.name,ts.name); ts1.flag = 9; char filename[128]; printf("33[0;31m <请输入要传输的文件名>33[0mn"); scanf("%s",filename); printf("33[0;31m <请输入要传输的对象>33[0mn"); scanf("%s",ts1.to_name); int bytes; int fd; if((fd = open(filename,O_RDONLY)) == -1) { perror("open error!n"); printf("未找到此文件"); return; } printf("打开文件成功n"); while(flag3) { memset(ts1.buf,0,sizeof(ts1.buf)); bytes = read(fd,ts1.buf,256); if(bytes == -1) { perror("read"); return; } ts1.num = bytes; sleep(1); send(clientfd2,&ts1,sizeof(ts1),0); if(bytes == 0) { strcpy(ts1.buf,"0"); send(clientfd2,&ts1,sizeof(ts1),0); break; } } flag3 = 1; close(fd); return; } void applyroot()//功能标志 10 管理员申请 包含头像的选择 { int num; putchar(10); printf("33[5;;35m尊敬的管理员请选择您的专属头像33[0mn"); putchar(10); printf("33[33m33[0;33m 1.???? 2.???? 3.???? 4.???? 5.???? 6.???? 7.???? 8.???? 33[0;34m 33[0mn"); putchar(10); printf("33[33m33[0;33m 9.???? 10.???? 11.???? 12.???? 13.???? 14.???? 15.????33[0;34m 33[0mn"); scanf("%d",&num); if(1 == num) { strcpy(ts.emojio,"????"); } if(2 == num) { strcpy(ts.emojio,"????"); } if(3 == num) { strcpy(ts.emojio,"????"); } if(4 == num) { strcpy(ts.emojio,"????"); } if(5 == num) { strcpy(ts.emojio,"????"); } if(6 == num) { strcpy(ts.emojio,"????"); } if(7 == num) { strcpy(ts.emojio,"????"); } if(8 == num) { strcpy(ts.emojio,"????"); } if(9 == num) { strcpy(ts.emojio,"????"); } if(10 == num) { strcpy(ts.emojio,"????"); } if(11 == num) { strcpy(ts.emojio,"????"); } if(12 == num) { strcpy(ts.emojio,"????"); } if(13 == num) { strcpy(ts.emojio,"????"); } if(14 == num) { strcpy(ts.emojio,"????"); } if(15 == num) { strcpy(ts.emojio,"????"); } ts.flag = 10; ts.root = 1; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } sleep(1); system("clear"); if(flag1 == 2) { flag1 = 0; selectfun(); } else { printf("33[33m 33[0;33m申请管理员失败33[0;34m 33[0mn"); sleep(1); //system("clear"); funcinto(); } } void rootlogin()//功能标志11 管理员登录 登录成功直接进入管理员聊天界面 { ssize_t ret; system("clear"); printf("33[0;31m请输入你的名字..33[0mn"); scanf("%s",ts.name); system("clear"); printf("33[0;31m请输入你的密码33[0mn"); system("stty -echo"); scanf("%s",ts.password); sleep(1); system("stty echo"); ts.flag = 11; //用户登录标志位 ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } sleep(1); if(3 == flag1) { flag1 = 0; selectfun(); } if(0 == flag1) { rootgroupchat(); } return; } void rootgroupchat() //管理员群聊界面 显示群聊界面 { usleep(500*1000); int num = 0; ts.root = 1; ssize_t ret; ts.flag = 5; char buf[200] = ""; char *buf2; system("clear"); printf("33[0;31m请输入聊天内容..33[0mn"); //循环聊天记得加循环 printf("33[0;31m <输入Q!退出聊天室>33[0mn"); printf("33[0;36m <输入W!查看快捷短语>33[0mn"); printf("33[0;36m <输入C!查看聊天记录>33[0mn"); printf("33[0;36m <输入T!进行文件传输>33[0mn"); printf("33[0;36m <输入L!查看当前在线人数>33[0mn"); printf("33[0;36m <输入K!踢人>33[0mn"); printf("33[0;36m <输入F!禁言>33[0mn"); printf("33[0;36m <输入U!解除禁言>33[0mn"); printf("33[0;36m <输入E!撤销管理员身份>33[0mn"); printf("33[0;33m [管理员]????:%s33[0mn",ts.name); while(1) { scanf("%s",buf); if(strcmp(buf,"Q!") == 0)//退出群聊 { system("clear"); exit_room(); return; } if(strcmp(buf,"E!") == 0)//取消管理员身份 { system("clear"); cancelroot(); return; } if(strcmp(buf,"W!") == 0)//查看快捷短语 { phrase(); continue; } if(strcmp(buf,"C!") == 0)//查看聊天记录 { checkrecord(); printf("33[0;32m请输入1继续群聊..33[0mn"); scanf("%d",&num); if(1 == num) { break; } else { printf("33[0;32m输入错误33[0mn"); } } if(strcmp(buf,"T!") == 0)//文件传输 { filetransfer(); break; } if(strcmp(buf,"L!") == 0)//查看在线用户 { rootviewonline_user(); printf("33[0;32m请输入1继续群聊..33[0mn"); scanf("%d",&num); if(1 == num) { break; } else { printf("33[0;32m输入错误33[0mn"); } } if(strcmp(buf,"K!") == 0)//踢人 { rootkick(); break; } if(strcmp(buf,"F!") == 0)//禁言 { silent(); break; } if(strcmp(buf,"U!") == 0)//解除禁言 { remsilent(); break; } if((buf2 = selectphrase(buf)) == NULL) { strcpy(ts.msg,buf); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } continue; } else { strcpy(ts.msg,buf2); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } } rootgroupchat(); } void rootviewonline_user()//管理员标志6 查看所有在线用户 { ts.flag = 6; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } ts.flag = 5; return; } void rootkick()//功能标志12 踢出群聊 { ts.root = 1; ssize_t ret; system("clear"); ts.flag = 12; printf("33[0;31m请输入你想踢出群聊的对象..33[0mn"); scanf("%s",ts.to_name); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } sleep(1); rootgroupchat(); return; } void silent()//功能标志13 禁言 { ts.root = 1; ssize_t ret; system("clear"); ts.flag = 13; printf("33[0;31m请输入你想禁言的对象..33[0mn"); scanf("%s",ts.to_name); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } sleep(1); rootgroupchat(); return; } void remsilent()//功能标志14 解除禁言 { ts.root = 1; ssize_t ret; system("clear"); ts.flag = 14; printf("33[0;31m请输入你想解除禁言的对象..33[0mn"); scanf("%s",ts.to_name); ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } rootgroupchat(); return; } void cancelroot()//功能标志15 取消管理员身份 { char password[30] = {0}; char name[30] = {0}; printf("33[0;31m 请认真确认你的用户信息33[0mn"); printf("33[0;31m<输入姓名>33[0mn"); scanf("%s",name); system("clear"); printf("33[0;31m<输入密码>33[0mn"); scanf("%s",password); int ret1,ret2; ret1 = strcmp(name,ts.name); ret2 = strcmp(password,ts.password); if(0 == ret1 && 0 == ret2) { ts.flag = 15; int ret; ret =send(clientfd2,&ts,sizeof(clientlist),0); if(ret == -1) { ERRLOG("send"); } } sleep(1); selectfun(); return; } void *recv_thread(void *arg)//接受线程函数 { // int ret = 1; int fd; MSG msg; //int num; char buf[256] = {0}; int length; clientfd2 = *((int *)arg); while(1) { memset(buf,0,sizeof(buf)); length = recv(clientfd2,buf,sizeof(buf),0); if (length == 0) { printf("服务器宕机!!n"); exit(1); pthread_exit(NULL); } buf[length] = ''; printf("33[5;;36m%s33[0mn",buf); if(strcmp(buf,"该用户不存在,请注册...") == 0) { flag1 = 1; } if(strcmp(buf,"对方不在线...") == 0) { flag3 = 0; } if(strcmp(buf,"密码输入错误..") == 0) { flag1 = 1; } if(strcmp(buf,"您已在线,请勿重复登录") == 0) { flag1 = 1; } if(strcmp(buf,"管理员申请成功") == 0) { flag1 = 2; } if(strcmp(buf,"该用户非管理员") == 0) { flag1 = 3; } if(strcmp(buf,"密码输入错误") == 0) { flag1 = 3; } if(strcmp(buf,"管理员已将你踢出聊天室") == 0) { exit(1); } if(strcmp(buf,"管理员已将你禁言") == 0) { flag2 = 0; } if(strcmp(buf,"管理员已将你解除禁言") == 0) { flag2 = 1; } if(strcmp(buf,"文件存在进行文件传输") == 0) { printf("正在接受文件n"); if((fd = open("1.txt",O_WRONLY | O_CREAT | O_TRUNC,0664)) == -1) { ERRLOG("open error"); } int ret; while((ret = recv(clientfd2,&msg,sizeof(msg),0)) != -1) { //printf("ret= %dn",ret); if(strcmp(msg.text,"0") == 0) { printf("33[0;36m文件接受完成33[0mn"); //sleep(1); close(fd); break; } else { write(fd,msg.text,msg.num); } memset(&msg,0,sizeof(msg)); } } putchar(10); } //pthread_exit(NULL); } void *send_thread(void *arg)//发送线程函数 { selectfun(); } void exit_room()//退出聊天室 { exit(0); }
client.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> #include <ctype.h> #include <unistd.h> #include <fcntl.h> #include <sqlite3.h> #define N 256 #define ERRLOG(errmsg) do{ perror(errmsg); printf("%s - %s - %dn",__FILE__,__func__,__LINE__); exit(1); }while(0) int clientfd2;//客户端sockfd typedef struct file //文件传输结构体 { char text[N]; int num; }MSG; typedef struct client { char emojio[20]; //头像保存 char name[32]; //姓名 char msg[50]; //聊天内容 char password[32]; //密码 char to_name[50]; //聊天对象 char buf[256]; //文件内容 int num; //文件读取大小 int root; //管理员标志 int flag; //功能标志 注册标志1 登录2 私聊3 修改密码4 群聊界面5 查看在线用户6 注销用户7 查看聊天记录8 下载文件9 }clientlist; clientlist ts; void funcinto();//第二阶段选择进入 void recvmessage();//消息接受 void n_init();//初始化客户端 void selectfun();//进入目录选择功能 void user_login();//用户登录 void user_register();//用户注册 void privatechat();//私聊 void *recv_thread(void *arg);//客户端接受消息线程函数 void *send_thread(void *arg);//客户端发送消息函数 void changpassword(); //修改密码 void groupchat(); //群聊 void viewonline_user();//查看所有在线用户 void deleteuser();//注销用户 void phrase();//快捷短语 char *selectphrase(char *num);//快捷短语的选择 void checkrecord();//查看聊天记录 void filetransfer();//文件传输 void applyroot();//申请成为管理员 void rootlogin();//管理员登录 void rootgroupchat();//管理员群聊界面 void rootkick();//踢出群聊 void silent();//管理员禁言 void remsilent();//解除禁言 void rootviewonline_user();//管理员查看在线用户 void cancelroot();//取消管理员身份 void root_login();//管理员登录 void exit_room();//退出聊天室
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "clientaddr.h" int main(int argc, char const *argv[]) { n_init(); int ret; pthread_t tid_recv; pthread_t tid_send; ret = pthread_create(&tid_recv,NULL,(void *)recv_thread,(void *)&clientfd2); ret = pthread_create(&tid_send,NULL,(void *)send_thread,(void *)&clientfd2); pthread_join(tid_recv,NULL); pthread_join(tid_send,NULL); close(clientfd2); return 0; }
最后
以上就是淡然歌曲最近收集整理的关于(c语言)即时通讯系统---epoll+线程池 版本注意一 .项目功能二.项目简介三.项目演示四.项目功能基本介绍四.代码部分的全部内容,更多相关(c语言)即时通讯系统---epoll+线程池内容请搜索靠谱客的其他文章。
发表评论 取消回复