网络编程项目——在线电子词典
目录
项目要求:
代码
服务器代码
客户端
运行截图
注册
首次注册
重复注册
数据库
登录
正常登录
重复登录
数据库
查询
数据库
查询历史
退出
数据库
编辑
项目要求:
登录注册功能,不能重复登录,重复注册
单词查询功能
历史记录功能,存储单词,意思,以及查询时间
基于TCP,支持多客户端连接
采用数据库保存用户信息与历史记录
将dict.txt的数据导入到数据库中保存。
按下ctrl+c退出客户端后,注销该客户端的登录信息
格式要求:
main函数只跑逻辑,不允许跑功能代码
功能代码封装成函数
代码
服务器代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include <sqlite3.h>
#include<time.h>
//打印错误信息的宏函数
#define ERR_MSG(msg) do{\fprintf(stderr," __%d__",__LINE__);\perror(msg);\
}while(0);#define PORT 8888 //1024~49151端口号
#define IP "192.168.31.31" //本机IP,用ifcongfig查看//定义协议
#define R 1 //注册
#define L 2 //登录
#define O 3 //注销退出
#define M 4 //修改
#define Q 5 //查询
#define H 6 //历史记录typedef struct
{int type; //存储协议char name[128];char data[128];int flag; //判断是否登录
}MSG;int do_register(int newfd,MSG *msg,sqlite3 *db);
int do_login(int newfd,MSG *msg,sqlite3 *db);
int do_query(int newfd,MSG *msg,sqlite3 *db);
int do_history(int newfd,MSG *msg,sqlite3 *db);
int do_logout(int newfd,MSG *msg,sqlite3 *db);
int do_clint(int newfd,sqlite3 *db)
{MSG msg;memset(&msg,0,sizeof(msg));//服务器接收客户端信息,通过规定协议判断客户端请求while (recv(newfd,&msg,sizeof(MSG),0)>0)//while (1){//recv(newfd,&msg,sizeof(msg),0);printf("type %d\n",msg.type);printf("name %s\n",msg.name);printf("data %s\n",msg.data);//根据结构体中的协议号调用程序响应处理switch(msg.type){case R:do_register(newfd,&msg,db);break;case L:do_login(newfd,&msg,db);break;case Q:do_query(newfd,&msg,db);break;case H:do_history(newfd,&msg,db);break;case O:do_logout(newfd,&msg,db);break;default: printf("GGGGGGGGG\n");break;}}char sql[128];sprintf(sql,"delete from msg where name='%s';",msg.name);//printf("%s\n",sql);char* errmsg = NULL;if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}else{printf("用户注销>>>>X_X\n");strcpy(msg.data,"退出成功~");}printf("客户端退出...............\n");close(newfd);exit(0);
}int do_register(int newfd,MSG *msg,sqlite3 *db)//注册函数
{char * errmsg;char sql[300];//查重int nrow, ncloumn; //数据库行数和列数char **resultp; //定义二级指针保存SOL语句执行的结果//拼接SOL语句,查询用户名和密码与数据库内容是否匹配sprintf(sql, "select * from msg where name='%s';", msg->name);//printf("%s\n", sql); //调试语句if (sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg)!=SQLITE_OK){printf("%s\n",errmsg);return -1;}//printf("%d\n",nrow);if(nrow==1){strcpy(msg->data,"重复注册!!!");send(newfd,msg,sizeof(*msg),0);return 1;}else{//printf("%s\n",sql);//printf("%s\n",msg->data);//printf("flag=%d\n",msg->flag);//向数据库中插入信息,flag为0,表示未登录sprintf(sql,"insert into msg values('%s',\'%s\',%d);",msg->name,msg->data,msg->flag);//printf("%s\n",sql);char* errmsg = NULL;if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}//printf("insert success\n");//strcpy(msg->data,"插入成功");else{strcpy(msg->data,"注册成功");}if (send(newfd,msg,sizeof(*msg),0)<0){ERR_MSG("send");return -1;}}
}int do_login(int newfd,MSG *msg,sqlite3 *db)//登录处理函数
{char * errmsg;char sql[300];//查重//char *errmsg;int nrow, ncloumn; //数据库行数和列数char **resultp; //定义二级指针保存SOL语句执行的结果//拼接SOL语句,查询用户名和密码与数据库内容是否匹配sprintf(sql, "select * from msg where name='%s' and passwd='%s';", msg->name,msg->data);//printf("%s\n", sql); //调试语句if (sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg)!=SQLITE_OK){printf("%s\n",errmsg);return -1;}if(nrow==1){//if(resultp[5]==1)if(strcmp(resultp[5],"1")==0)//flag=1表示用户已登录 返回信息给客户端{strcpy(msg->data,"该用户已登录,洗洗睡吧");send(newfd,msg,sizeof(*msg),0);return -1;}bzero(sql,sizeof(sql));msg->flag=1;sprintf(sql,"update msg set flag=%d where name='%s' and passwd='%s';",msg->flag,msg->name,msg->data);//printf("%s\n",sql);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}strcpy(msg->data,"OK");send(newfd,msg,sizeof(*msg),0);return 1;}else{strcpy(msg->data,"!!!账号密码有误!!!");send(newfd,msg,sizeof(MSG),0);}return 0;}int do_query(int newfd,MSG *msg,sqlite3 *db)//查询单词
{char tm[128];char * errmsg;char sql[300];//查重//char *errmsg;int nrow, ncloumn; //数据库行数和列数char **resultp; //定义二级指针保存SOL语句执行的结果//拼接SOL语句,查询用户名和密码与数据库内容是否匹配sprintf(sql, "select * from dict where word='%s';", msg->data);//printf("%s\n", sql); //调试语句if (sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg)!=SQLITE_OK){printf("%s\n",errmsg);return -1;}//printf("%d\n",nrow);if(nrow==1){time_t t;struct tm *info = NULL;t = time(NULL);info = localtime(&t);//\r转义字符,将光标重新移动回开头sprintf(tm,"%d-%02d-%02d %02d:%02d:%02d\r", \info->tm_year+1900, info->tm_mon+1, info->tm_mday,\info->tm_hour, info->tm_min, info->tm_sec);//strcpy(tm,asctime(t));//printf("%s\n",tm);//printf("zhongwen %s\n",resultp[3]);sprintf(sql,"insert into history values('%s',\'%s\','%s');",msg->name,tm,msg->data);//printf("%s\n",sql);char* errmsg = NULL;if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}strcpy(msg->data,resultp[3]);send(newfd,msg,sizeof(*msg),0);return 1;}else{strcpy(msg->data,"NO");send(newfd,msg,sizeof(MSG),0);}return 0;
}
int do_history(int newfd,MSG *msg,sqlite3 *db)//历史记录查询
{printf("test history\n");//char his[256];//拼接历史记录char * errmsg;char sql[300];//查重//char *errmsg;int nrow, ncloumn; //数据库行数和列数char **resultp; //定义二级指针保存SOL语句执行的结果//拼接SOL语句,查询用户名和密码与数据库内容是否匹配//sprintf(sql, "select * from history;");strcpy(sql,"select * from history;");//printf("%s\n", sql); //调试语句if (sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg)!=SQLITE_OK){printf("%s\n",errmsg);return -1;}if(nrow!=0){//printf("query successful.\n");//printf("test hang:%d lie:%d\n",nrow,ncloumn);int i=0;for (i=3; i<(nrow+1)*ncloumn; i+=3){bzero(msg->data,sizeof(msg->data));/* printf("ceshi %s\n",msg->data);printf("%s\n",resultp[i]);printf("%s\n",resultp[i+1]);printf("%s\n",resultp[i+2]);*/sprintf(msg->data,"%s %s %s",resultp[i],resultp[i+2],resultp[i+1]);//拼接记录信息写入结构体printf("%s\n",msg->data);if(send(newfd,msg,sizeof(*msg),0)<0){ERR_MSG("send");return -1;}bzero(msg->data,sizeof(msg->data));}msg->data[0]='\0';if(send(newfd,msg,sizeof(MSG),0)<0){ERR_MSG("send");return -1;}return 1;}elsereturn 0;}
int do_logout(int newfd,MSG* msg,sqlite3 *db)//注销函数
{char sql[128];sprintf(sql,"delete from msg where name='%s';",msg->name);//从数据库中删除用户信息printf("%s\n",sql);char* errmsg = NULL;if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}else{printf("用户已注销,客户端GG。X_X\n");strcpy(msg->data,"退出成功~");}if(send(newfd,msg,sizeof(MSG),0)<0){ERR_MSG("send");return -1;}}
int main(int argc, const char *argv[])
{//创建流式套接字int sfd=socket(AF_INET,SOCK_STREAM,0);if (sfd < 0){ERR_MSG("socket");return -1;}printf("create socket success\n");//允许端口快速复用int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0){ERR_MSG("setsockopt");return -1;}//填充地址信息结构体,真实地址信息结构体与协议族相关//AF_INET,所以详情看》man 7 ipstruct sockaddr_in sin;sin.sin_family =AF_INET;sin.sin_port =htons(PORT); //网络字节序sin.sin_addr.s_addr =inet_addr(IP); //网络字节序的IP地址//将地址信息结构体绑定到套接字上if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("bind");return -1;}printf("bind success\n");//将套接字设置为被动监听状态,让内核去监听是否有客户端链接if (listen(sfd,10)<0){ERR_MSG("listen");return -1;}printf("listen success\n");//打开数据库sqlite3* db = NULL;if(sqlite3_open("./dict.db", &db) != SQLITE_OK){printf("err_code:%d\n", sqlite3_errcode(db));printf("errmsg:%s\n", sqlite3_errmsg(db));fprintf(stderr, "__%d__ sqlite3_open failed\n", __LINE__);return -1;}printf("sqlite3_open:dict.db success\n");//创建信息表char* sql = "create table if not exists msg ( name char, passwd char,flag int);" ;char* errmsg = NULL;if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}printf("create table msg success\n");//创建历史记录表char* sql2 = "create table if not exists history (name char, datatime char, word char);" ;
//char* errmsg2 = NULL;if(sqlite3_exec(db, sql2, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);return -1;}printf("create table success\n"); struct sockaddr_in cin;socklen_t addrlen= sizeof(cin);//从已完成的队列头中,取出一个客户端的信息,创建生成一个新的套接字文件描述符//该文件描述符才是与客户端通信的文件描述符!!!!
/* int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);if (newfd<0){perror("accept");return -1;}*///网络字节序的IP--->点分十进制 网络字节序port转换成主机字节序///printf("[%s : %d] newfd = %d \n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);printf("***************************等待客户端链接*****************************\n");while (1){int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);if (newfd<0){perror("accept");return -1;}
printf("[%s : %d] newfd = %d \n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);pid_t pid=fork();if (pid<0){ERR_MSG("fork");exit(-1);}else if(pid==0)//子进程{//处理客户端请求close(sfd);do_clint(newfd,db);}else{//父进程close(newfd);}close(newfd);}close(sfd);
// close(newfd);return 0;
}
客户端
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define ERR_MSG(msg) do{\fprintf(stderr," __%d__",__LINE__);\perror(msg);\
}while(0);#define PORT 8888 //1024~49151端口号
#define IP "192.168.31.31" //本机IP,用ifcongfig查看
typedef struct
{int type; //存储协议char name[128];char data[128];int flag; //判断是否登录
}MSG;//定义协议
#define R 1 //注册
#define L 2 //登录
#define O 3 //注销退出
#define Q 5 //查询
#define H 6 //历史记录//注册函数
int do_register(int sfd,MSG *msg)
{//printf("%ld\n",sizeof(*msg));msg->type=R;msg->flag=0;printf("请输入账号>>>");//账号输入scanf("%s",msg->name);getchar();printf("请输入密码>>>");//密码输入scanf("%s",msg->data);getchar();//printf("ceshi %s\n",msg->name);//printf("ceshi %s\n",msg->data);//memcpy(send_buf,&msg,sizeof(msg));//客户端先发送if (send(sfd,msg,sizeof(*msg),0)<0)//if (send(sfd,send_buf,sizeof(send_buf),0)<0){ERR_MSG("send");return -1;}//memset(&msg,0,sizeof(msg));//后接收if (recv(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("recv");return -1;}printf("%s\n",msg->data);return 0;
}//登录函数
int do_login(int sfd,MSG *msg)
{msg->type=L;printf("请输入账号>>>");//账号输入scanf("%s",msg->name);getchar();printf("请输入密码>>>");//密码输入scanf("%s",msg->data);getchar();//客户端先发送if (send(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("send");return -1;}//后接收if (recv(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("recv");return -1;}//if(strncmp(msg->data,"OK",3)==0)if(strcmp(msg->data,"OK")==0){printf("***************登陆成功****************\n\n");// printf("***************************************\n");return 1;}else{//printf("登录失败\n");printf("%s\n",msg->data);return 0;}return 0;}//退出登录函数
int do_logout(int sfd,MSG *msg)
{if (msg->flag==0){printf("用户未登录\n");return -1;}msg->type=O;//发送退出登录协议printf("%d\n",msg->type);//客户端先发送if (send(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("send");return -1;}//后接收if (recv(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("recv");return -1;}printf("%s\n",msg->data);return 0;
}//查询函数
int do_query(int sfd,MSG *msg)
{msg->type=Q;//输入要查询的单词printf("请输入要查询的单词\n");fgets(msg->data,sizeof(msg->data),stdin);msg->data[strlen(msg->data)-1]='\0';//printf("test %s\n",msg->data);//客户端先发送if (send(sfd,msg,sizeof(MSG),0)<0){ERR_MSG("send");return -1;}//后接收if (recv(sfd,msg,sizeof(*msg),0)<0){ERR_MSG("recv");return -1;}if (strcmp(msg->data,"NO")==0){printf("XXXXXXX未查询到对应单词XXXXXXXXX\n");}else{printf("中文意思为:%s\n",msg->data);}return 0;
}//查询历史记录
int do_history(int sfd,MSG *msg)
{msg->type=H;//printf("test %d\n",msg->type);if (send(sfd,msg,sizeof(MSG),0)<0){printf("发送失败\n");return -1;}while (1){if (recv(sfd,msg,sizeof(MSG),0)<0){ERR_MSG("recv");return -1;}if (msg->data[0]==0){break;}printf("%s\n",msg->data);}return 0;
}int main(int argc, const char *argv[])
{MSG msg;//printf("%ld\n",sizeof(msg));//创建流式套接字int sfd=socket(AF_INET,SOCK_STREAM,0);if (sfd<0){ERR_MSG("socket");return -1;}//绑定客户端的地址信息结构体》非必须填写//填充要连接的服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family =AF_INET;sin.sin_port =htons(PORT);sin.sin_addr.s_addr=inet_addr(IP);//链接服务器if (connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){ERR_MSG("connect");return -1;}start: while (1) //登录交互界面{printf("***************************************\n");printf("****************1:注册*****************\n");printf("****************2:登录*****************\n");printf("****************3:退出*****************\n");printf("***************************************\n");printf("请选择>>>");int n;scanf("%d",&n);getchar();//吸收垃圾字符switch(n){case 1:do_register(sfd,&msg);break;case 2:if(do_login(sfd,&msg)==1)goto next;break;case 3:close(sfd);exit(0);break;default:printf("请输入正确选项!!!\n");}}
next:while (1){printf("***************************************\n");printf("****************1:查询翻译*************\n");printf("****************2:查询历史*************\n");printf("****************3:退出登录*************\n");printf("***************************************\n");printf("请选择>>>");int n;scanf("%d",&n);getchar();//吸收垃圾字符switch(n){case 1:do_query(sfd,&msg);break;case 2:do_history(sfd,&msg);break;case 3:do_logout(sfd,&msg);goto start;break;default:printf("请输入正确选项!!!\n");break;}}close(sfd);return 0;
}
运行截图
注册
首次注册
重复注册
数据库
登录
正常登录
重复登录
数据库
登陆后flag为1
查询
数据库
查询后将信息插入数据库
查询历史
退出
按程序退出或者ctrl+c结束,都将注销用户,从数据库中删除用户信息
数据库
网络编程项目——在线电子词典相关推荐
- 基于数据库及TCP网络编程实现的电子词典
目录 一.前言 二.项目介绍 三.功能实现 3.1. 用户注册 3.1.1 功能演示 3.1.2 功能函数实现 3.2. 用户登录 3.2.1 功能演示 3.2.2 功能函数实现 3.3. 查询单词 ...
- 【基于TCP 在线电子词典】
基于TCP 在线电子词典 项目功能 流程图 客户端 服务器端 功能实现 服务器 客户端 功能演示 注册功能 登录功能 查询单词功能 查询记录 注销登录(返回上级) 不允许重复登录 Ctrl + C注销 ...
- 基于 Netty 网络编程项目实战课程
一 基于 Netty 网络编程项目实战课程 1项目介绍 2Netty 介绍与相关基础知识 2.1Netty 介绍 简介 Netty 是由 JBOSS 提供的一个 java 开源框架.Netty 提供异 ...
- 基于Linux的socket网络编程项目——游侠手机商城
基于Linux的socket网络编程项目--游侠手机商城 一.项目说明 二.项目使用的技术 三.客户端搭建 四.服务器端搭建 一.项目说明 本项目是一个仿真手机商城类系统,基本功能: 登录界面功能:用 ...
- python网络编程项目_python网络编程详解
最近在看<UNIX网络编程 卷1>和<FREEBSD操作系统设计与实现>这两本书,我重点关注了TCP协议相关的内容,结合自己后台开发的经验,写下这篇文章,一方面是为了帮助有需要 ...
- Linux操作系统C语言网络编程学生在线考试系统(带完整项目源码)
目录 一.项目功能 1.用户登录 2.教师登录 3.学生登录 二.需求分析 1.多用户登录,有并发需求. 2.需要数据库存储一堆信息. 三.软硬件开发平台 1.硬件 2.软件 四.技术点 1.使用并发 ...
- 网络编程项目(聊天室项目)
一.实现目标 一个在Linux下可以使用的聊天软件,要求至少实现如下功能: 1. 采用Client/Server架构 2. Client A 登陆聊天服务器前,需要注册自己的ID和密码 3. 注册成功 ...
- python网络编程项目_Python网络编程攻略
第1章套接字.IPv4和简单的客户端/服务器编程 本章攻略: 打印设备名和IPv4地址 获取远程设备的IP地址 将IPv4地址转换成不同的格式 通过指定的端口和协议找到服务名 主机字节序和网络字节序之 ...
- C网络编程项目 图书借阅系统(一)
1.项目名称 图书借阅系统 2.项目需求 对于图书馆中的书籍信息的管理,可以增.删.改.查书籍的信息,完成借阅.归还书籍的要求. 3.项目功能 1.采用并发服务器,可以同时处理多个客户端的请求. 2. ...
- Linux网络编程之六 --在线英英字典的实现
综合项目:在线英英字典 服务器端 head.h: server.c do_client.c Makefile 客户端 head.h client.c Makefile 关注微信公众号获取更多资讯
最新文章
- Android Color 判断色值小结
- JavaScript学习历程和心得
- 金融贷款逾期的模型构建1
- make时候说找不到makefile_找不到答案的时候,就去看一看这个世界
- ubuntu开启端口_RChain节点运行无门槛教程(二)--Windows-Ubuntu
- 【page-monitor 前端自动化 上篇】初步调研
- app启动速度阶段指标
- unity ppr_智能自动PPR更改事件策略
- 维基媒体宣布采用 Vue.js 进行前端开发
- 常用的Linux操作命令
- Ububtu 18.04 安装 mysql 和 phpmyadmin 过程记录
- 2020-07-07
- QT高级编程技巧(一)-- 编写高效的signal slot通信代码
- UDP与TCP报文格式,字段意义
- STP配置 HSRP配置 端口追踪
- excel批量改名字(含识别区分)
- xss漏洞原因以及如何应对
- 51单片机_7-2 使用内部计时器实现时钟显示
- 我做了一个艰难的决定
- 基于Java的开源3D游戏引擎jMonkeyEngine