• 基于TCP的简易电子词典


    头文件:

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. #include
    4. #define N 32
    5. typedef struct {
    6. int type;
    7. char name[N];
    8. char data[256];
    9. int option;
    10. int flag;
    11. }MSG;
    12. #define R 1 // 用户注册
    13. #define L 2 // 用户登录
    14. #define Q 3 // 查询单词
    15. #define H 4 // 历史记录
    16. #define DATABASE "my.db" //创建的数据库
    17. #define SERADDR "192.168.114.156"
    18. #define SERPORT 8888
    19. #endif

    服务器

    1. #include "head.h"
    2. void init_sql(sqlite3 *db);
    3. int do_client(int acceptfd, sqlite3 *db); //客户端请求入口
    4. void do_register(int acceptfd, MSG *msg, sqlite3 *db);//注册用户实现
    5. int do_login(int acceptfd, MSG *msg, sqlite3 *db);//用户登录实现
    6. int do_query(int acceptfd, MSG *msg, sqlite3 *db);//用户查询单词实现
    7. int do_history(int acceptfd, MSG *msg, sqlite3 *db);//查询历史记录
    8. int get_data(char *date);//获取时间
    9. int main(int argc, const char *argv[])
    10. {
    11. int sockfd;
    12. struct sockaddr_in serveraddr;
    13. int acceptfd;
    14. sqlite3 *db;
    15. pid_t pid;
    16. //打开数据库
    17. if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
    18. {
    19. printf("%s\n", sqlite3_errmsg(db));
    20. return -1;
    21. }
    22. else
    23. {
    24. printf("open DATABASE success.\n");
    25. }
    26. //套接字
    27. if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
    28. {
    29. perror("fail to socket.\n");
    30. return -1;
    31. }
    32. bzero(&serveraddr, sizeof(serveraddr));
    33. serveraddr.sin_family = AF_INET;
    34. serveraddr.sin_addr.s_addr = inet_addr(SERADDR);
    35. serveraddr.sin_port = htons(SERPORT);
    36. int reuse = 1;
    37. if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    38. {
    39. perror("setsockopt");
    40. return -1;
    41. }
    42. //绑定
    43. if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    44. {
    45. perror("fail to bind.\n");
    46. return -1;
    47. }
    48. //监听
    49. if(listen(sockfd, 5) < 0)
    50. {
    51. printf("fail to listen.\n");
    52. return -1;
    53. }
    54. signal(SIGCHLD, SIG_IGN); //处理僵尸进程
    55. if (sqlite3_open("./my.db", &db) != SQLITE_OK)
    56. {
    57. fprintf(stderr, "line:%d sqlite_open:%s\n", __LINE__, sqlite3_errmsg(db));
    58. return -1;
    59. }
    60. init_sql(db);
    61. struct sockaddr_in cin;
    62. socklen_t cin_len = sizeof(cin);
    63. while(1)
    64. {
    65. //接收
    66. if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
    67. {
    68. perror("fail to accept");
    69. return -1;
    70. }
    71. //创建子进程
    72. if((pid = fork()) < 0)
    73. {
    74. perror("fail to fork");
    75. return -1;
    76. }
    77. //子进程
    78. else if(pid == 0)
    79. {
    80. close(sockfd);
    81. do_client(acceptfd, db);
    82. }
    83. //父进程
    84. else
    85. {
    86. close(acceptfd);
    87. }
    88. }
    89. return 0;
    90. }
    91. //客户端请求入口
    92. int do_client(int acceptfd, sqlite3 *db)
    93. {
    94. MSG msg;
    95. while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
    96. {
    97. switch(msg.option)
    98. {
    99. case R:
    100. do_register(acceptfd, &msg, db);
    101. break;
    102. case L:
    103. do_login(acceptfd, &msg, db);
    104. break;
    105. case Q:
    106. do_query(acceptfd, &msg, db);
    107. break;
    108. case H:
    109. do_history(acceptfd, &msg, db);
    110. break;
    111. default:
    112. printf("Invalid data msg.\n");
    113. }
    114. }
    115. printf("用户已退出\n");
    116. close(acceptfd);
    117. exit(0);
    118. return 0;
    119. }
    120. //数据库操作
    121. void init_sql(sqlite3 *db)
    122. {
    123. printf("正在初始化...\n");
    124. //创建表
    125. char sql[256] = "";
    126. char *errmsg = NULL;
    127. strcpy(sql, "create table if not exists usr (name char PRIMARY KEY,passwd char,status char);");
    128. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    129. {
    130. printf("sqlite3_exec error:%s\n", errmsg);
    131. return;
    132. }
    133. strcpy(sql, "create table if not exists log (name char,word char,explain char,time char);");
    134. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    135. {
    136. printf("sqlite3_exec error:%s\n", errmsg);
    137. return;
    138. }
    139. strcpy(sql, "create table if not exists dict (Word char,Explain char);");
    140. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    141. {
    142. printf("sqlite3_exec error:%s\n", errmsg);
    143. return;
    144. }
    145. //判断词库存不存在
    146. char **result = NULL;
    147. int rows = 1;
    148. int columns = 0;
    149. // char sql[128] = "select * from stu";
    150. strcpy(sql, "select * from dict");
    151. if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
    152. {
    153. printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
    154. return;
    155. }
    156. sqlite3_free_table(result);
    157. if (rows < 7987)
    158. {
    159. printf("正在导入词库...\n");
    160. FILE *fp = fopen("./dict.txt", "r");
    161. if (NULL == fp)
    162. {
    163. perror("fopen");
    164. return;
    165. }
    166. char buff[300];
    167. char Word[64];
    168. char Explain[256];
    169. char *p = NULL;
    170. while (NULL != fgets(buff, sizeof(buff), fp))
    171. {
    172. p = buff;
    173. while (1)
    174. {
    175. if (*p != ' ' || (*p == ' ' && *(p + 1) != ' '))
    176. p++;
    177. else
    178. break;
    179. }
    180. *p = '\0';
    181. p++;
    182. //获取单词
    183. strcpy(Word, buff);
    184. //跳过空格
    185. while (*p == ' ')
    186. {
    187. p++;
    188. }
    189. //截取解释
    190. strcpy(Explain, p);
    191. sprintf(sql, "insert into dict values(\"%s\",\"%s\")", Word, Explain);
    192. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    193. {
    194. printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
    195. return;
    196. }
    197. }
    198. }
    199. printf("单词库导入成功\n");
    200. }
    201. void do_register(int acceptfd, MSG *msg, sqlite3 *db)//注册用户实现
    202. {
    203. char sql[512] = {0};
    204. char *errmsg;
    205. sprintf(sql, "insert into usr values(\"%s\",\"%s\",'no');", msg->name, msg->data);
    206. // name为主键,插入失败则用户名已经存在
    207. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    208. {
    209. // printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
    210. sprintf(msg->data, "用户名 %s 已存在!!", msg->name);
    211. }
    212. else
    213. { printf("新用户:%s 已注册\n",msg->name);
    214. strcpy(msg->data, "注册成功!!");
    215. }
    216. send(acceptfd, msg, sizeof(MSG), 0);
    217. return;
    218. }
    219. int do_login(int acceptfd, MSG *msg, sqlite3 *db)//用户登录实现
    220. {
    221. char sql[512] = {0};
    222. char *errmsg, **result;
    223. int rows, columns;
    224. //通过sqlite3_get_table函数查询记录是否存在
    225. sprintf(sql, "select * from usr where name = '%s' and passwd = '%s'", msg->name, msg->data);
    226. if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
    227. {
    228. printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
    229. }
    230. //通过row参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到
    231. if (rows == 0)
    232. {
    233. strcpy(msg->data, "登录失败,用户名或密码错误");
    234. msg->flag = 0; //失败
    235. }
    236. else
    237. {
    238. strcpy(msg->data, "登录成功");
    239. sprintf(sql, "update usr set status = 'yes' where name = '%s'", msg->name); //登录之后状态设置为yes;
    240. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    241. {
    242. printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
    243. }
    244. msg->flag = 1; //成功
    245. printf("用户%s已登录\n", msg->name);
    246. }
    247. send(acceptfd, msg, sizeof(MSG), 0);
    248. return 0;
    249. }
    250. int do_query(int acceptfd, MSG *msg, sqlite3 *db)//用户查询单词实现
    251. {
    252. char sql[512] = "", *errmsg = NULL;
    253. int found = 0;
    254. char date[128];
    255. char **result = NULL;
    256. int rows = 0;
    257. int columns = 0;
    258. sprintf(sql, "select * from dict where Word='%s'", msg->data);
    259. if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
    260. {
    261. printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
    262. return -1;
    263. }
    264. if (0 == rows)//没有查到
    265. {
    266. strcpy(msg->data, "Not Found!!!");
    267. send(acceptfd, msg, sizeof(MSG), 0);
    268. }
    269. else
    270. {
    271. printf("%s\t\t%s\n", result[2], result[3]);
    272. strcpy(msg->data, result[3]);
    273. //如果执行成功,还需要保存历史记录
    274. //获取时间
    275. get_data(date);
    276. //通过sqlite3_exec函数插入数据
    277. bzero(sql, sizeof(sql));
    278. sprintf(sql, "insert into log values('%s', '%s', '%s', '%s')", msg->name, result[2], result[3], date);
    279. if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    280. {
    281. printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
    282. }
    283. printf("%s 查询成功\n",msg->name);
    284. send(acceptfd, msg, sizeof(MSG), 0);
    285. }
    286. return 0;
    287. }
    288. int do_history(int acceptfd, MSG *msg, sqlite3 *db)//查询历史记录
    289. {
    290. char sql[512] = "", *errmsg = NULL;
    291. int found = 0;
    292. char info[512];
    293. char **result = NULL;
    294. int rows = 0;
    295. int columns = 0;
    296. printf("%s 正在查询记录...\n", msg->name);
    297. sprintf(sql, "select * from log where name='%s'", msg->name);
    298. if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
    299. {
    300. printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
    301. return -1;
    302. }
    303. //将记录逐条发送给客户端
    304. for (int i = 1; i <= rows; i++)
    305. {
    306. sprintf(info, "%s:\t%s\t%s\t%s\n", result[i * columns], result[i * columns + 1], result[i * columns + 2], result[i * columns + 3]);
    307. send(acceptfd, info, sizeof(info), 0);
    308. }
    309. strcpy(info, "已到末尾");
    310. send(acceptfd, info, sizeof(info), 0);
    311. return 1;
    312. }
    313. int get_data(char *date)//获取时间
    314. {
    315. time_t t;
    316. struct tm *tp;
    317. time(&t);
    318. tp = localtime(&t);
    319. sprintf(date, "历史时间:%d-%02d-%02d %02d:%02d:%02d",
    320. 1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,
    321. tp->tm_hour, tp->tm_min, tp->tm_sec);
    322. }

    客户端

    1. #include "head.h"
    2. int do_register(int sockfd, MSG *msg); //注册用户
    3. int do_login(int sockfd, MSG *msg); //用户登录
    4. int do_query(int sockfd, MSG *msg); //查询单词
    5. int do_history(int sockfd, MSG *msg); //查询历史
    6. int SubMenu(int sockfd); //查询界面
    7. char name[20];
    8. int flag=0;
    9. int main(int argc, const char *argv[])
    10. {
    11. int sockfd;
    12. struct sockaddr_in serveraddr;
    13. int n;
    14. MSG msg;
    15. if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
    16. {
    17. perror("fail to socket.\n");
    18. return -1;
    19. }
    20. bzero(&serveraddr, sizeof(serveraddr));
    21. serveraddr.sin_family = AF_INET;
    22. serveraddr.sin_addr.s_addr = inet_addr(SERADDR);
    23. serveraddr.sin_port = htons(SERPORT);
    24. if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    25. {
    26. perror("fail to connect");
    27. return -1;
    28. }
    29. while(1)
    30. {
    31. printf("*****************************登录界面****************************\n");
    32. printf("**********************请输入序号进行对应操作*********************\n");
    33. printf("****************************1.注册*******************************\n");
    34. printf("****************************2.登录*******************************\n");
    35. printf("****************************3.退出*******************************\n");
    36. printf("请输入>>>");
    37. scanf("%d", &n);
    38. getchar();
    39. switch(n)
    40. {
    41. case 1:
    42. do_register(sockfd, &msg);
    43. break;
    44. case 2:
    45. if(do_login(sockfd, &msg) == 1)
    46. {
    47. SubMenu(sockfd);
    48. }
    49. break;
    50. case 3:
    51. close(sockfd);
    52. exit(0);
    53. break;
    54. default:
    55. printf("输入不合法,请重新输入\n");
    56. }
    57. }
    58. return 0;
    59. }
    60. int SubMenu(int sockfd)
    61. {
    62. int n;
    63. MSG msg;
    64. while(1)
    65. {
    66. printf("*****************************查询界面****************************\n");
    67. printf("**********************请输入序号进行对应操作*********************\n");
    68. printf("**************************1.查询单词*****************************\n");
    69. printf("**************************2.查询历史记录*************************\n");
    70. printf("**************************3.退出*****************************\n");
    71. printf("请输入>>>");
    72. scanf("%d", &n);
    73. getchar();
    74. switch(n)
    75. {
    76. case 1:
    77. do_query(sockfd, &msg);
    78. break;
    79. case 2:
    80. do_history(sockfd, &msg);
    81. break;
    82. case 3:
    83. close(sockfd);
    84. exit(0);
    85. break;
    86. default :
    87. printf("Invalid data cmd.\n");
    88. }
    89. }
    90. return 0;
    91. }
    92. int do_register(int sockfd, MSG *msg) //注册用户
    93. {
    94. msg->option = R;
    95. printf("请输入要注册的用户名>>>");
    96. scanf("%s", msg->name);
    97. while (getchar() != 10)
    98. ;
    99. printf("请输入密码>>>");
    100. scanf("%s", msg->data);
    101. while (getchar() != 10)
    102. ;
    103. //将用户名及密码发送给服务器,判断是否存在
    104. send(sockfd, msg, sizeof(MSG), 0);
    105. recv(sockfd, msg, sizeof(MSG), 0);
    106. //接收服务器发回来的消息来判断是否成功
    107. printf("Register: %s\n", msg->data);
    108. return 0;
    109. }
    110. int do_login(int sockfd, MSG *msg) //用户登录
    111. {
    112. //设置操作码
    113. msg->option = L;
    114. //输入用户名
    115. printf("请输入用户名>>>");
    116. scanf("%s", msg->name);
    117. while (getchar() != 10)
    118. ;
    119. //输入密码
    120. printf("请输入密码>>>");
    121. scanf("%s", msg->data);
    122. while (getchar() != 10)
    123. ;
    124. //发送数据给服务器
    125. send(sockfd, msg, sizeof(MSG), 0);
    126. //接收服务器发送的数据
    127. recv(sockfd, msg, sizeof(MSG), 0);
    128. //判断是否登录成功
    129. printf("%s\n", msg->data);
    130. if (msg->flag == 0)
    131. {
    132. return 0;
    133. }
    134. else
    135. {
    136. strcpy(name, msg->name);
    137. return 1;
    138. }
    139. }
    140. int do_query(int sockfd, MSG *msg) //查询单词
    141. {
    142. msg->option = Q;
    143. strcpy(msg->name, name);
    144. printf("-----------------------------单词查询中-----------------------------\n");
    145. while (1)
    146. {
    147. printf("请输入单词 (输入88退出): ");
    148. scanf("%s", msg->data);
    149. while (getchar() != 10)
    150. ;
    151. //如果输入的是#,返回
    152. if (strcmp(msg->data, "88") == 0)
    153. {
    154. break;
    155. }
    156. send(sockfd, msg, sizeof(MSG), 0);
    157. recv(sockfd, msg, sizeof(MSG), 0);
    158. printf("EXPLANTION %s\n", msg->data);
    159. }
    160. return 0;
    161. }
    162. int do_history(int sockfd, MSG *msg) //查询历史
    163. {
    164. char info[512];
    165. msg->option = H;
    166. strcpy(msg->name, name);
    167. send(sockfd, msg, sizeof(MSG), 0);
    168. while (1)
    169. {
    170. recv(sockfd, info, sizeof(info), 0);
    171. printf("%s\n", info);
    172. if (0 == strcmp(info, "已到末尾"))
    173. {
    174. break;
    175. }
    176. }
    177. return 0;
    178. }

  • 相关阅读:
    基础查缺 归并排序+尺取法
    TensorFlow之文本分类算法-6
    Kettle【实践 08】全国地铁线路信息及线路站点座标数据获取脚本及技巧说明(云资源分享:完整ktr脚本及20221008最新数据SQL)
    一分钟告诉你识别植物的软件哪个好?
    lsblk 硬盘属性查看
    MySQL的时区引起的前后端数据交互不畅的问题解决
    macos编译openssl
    计算机网络-IS-IS基础配置实验
    一文教你快速搭建数据驱动自动化测试框架
    Spring学习第5篇:自动注入(autowire)详解
  • 原文地址:https://blog.csdn.net/cwj442257772/article/details/132915054