这里涉及了多线程,使功能更加丰富
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//基于TCP通信,使用数据库完成电子词典功能
//服务端(实现一个服务端对多个客户端)
//登录管理
char* login(sqlite3* mydb,int socket_ok){
char** resultp; //resultp里面存储了数据表中的所有数据
int row;
int column;
//接收账号
char id[12];
memset(id,0,sizeof(id));
recv(socket_ok,id,sizeof(id),0);
//接收密码
char password[12];
memset(password,0,sizeof(password));
recv(socket_ok,password,sizeof(password),0);
//接收名字
char name2[12];
memset(name2,0,sizeof(name2));
recv(socket_ok,name2,sizeof(name2),0);
char sql2[512];
memset(sql2,0,sizeof(sql2));
snprintf(sql2,sizeof(sql2),"select * from user where id = '%s' and password = '%s' and name = '%s'",id,password,name2);
//执行sql
sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);
char resultStr[4096] = "";//存储结果集
memset(resultStr,0,sizeof(resultStr));
//拼接字符串
for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
{
strcat(resultStr, resultp[i]);//拼接字符串
strcat(resultStr, "\t\t"); // 使用制表符分隔
if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
{
strcat(resultStr, "\n");//换行
}
}
//发送数据
send(socket_ok,resultStr,sizeof(resultStr),0);
memset(sql2,0,sizeof(sql2));
//返回用户名字
char* name = malloc(12*sizeof(char));
strcpy(name,name2);
return name;
}
//注册管理
void user_register(sqlite3* mydb,int socket_ok){
char** resultp;
int row;
int column;
//接收账号
char id[12];
memset(id,0,sizeof(id));
recv(socket_ok,id,sizeof(id),0);
//接收账号
char password[12];
memset(password,0,sizeof(password));
recv(socket_ok,password,sizeof(password),0);
//接收名字
char name[12];
memset(name,0,sizeof(name));
recv(socket_ok,name,sizeof(name),0);
//首先检查账号合不合法
char sql2[128] = "select * from user;";
sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);
for(int i=0;i<(row+1)*column;i++){
if(strcmp(id,resultp[i])==0){//账号重复,非法
char msg[12] = "-1";
send(socket_ok,msg,strlen(msg),0);
return;
}
}
//到这里账号合法
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"insert into user(id,password,name)values('%s','%s','%s')",id,password,name);
//执行sql
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
char msg2[12] = "1";
send(socket_ok,msg2,strlen(msg2),0);
memset(sql,0,sizeof(sql));
}
//记录查询单词
void history(sqlite3* mydb,char str1[],char str2[],char name[]){
char** resultp;
int row;
int column;
//拼接sql
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"insert into history(name,word,explain)values('%s','%s','%s');",name,str1,str2);
printf("%s\n",sql);
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
memset(sql,0,sizeof(sql));
}
//字典功能
void dict(sqlite3* mydb,int socket_ok,char name[]){
//首先读出字典的数据
//使用标准io打开字典文件
FILE* fp = fopen("./dict.txt","r");
if(fp==NULL){
perror("open dict.txt failed");
return;
}
//接收查询的单词
char msg[30];
memset(msg,0,sizeof(msg));
recv(socket_ok,msg,sizeof(msg),0);
printf("查询%s\n",msg);
char buf[1024];//存储一行数据
memset(buf,0,sizeof(buf));
char msg2[1024];//存储单词解释
//feof 函数用于检查文件流的文件结束标志。如果 feof(fp) 返回 0(假),
//表示文件流 fp 还没有到达文件的末尾,如果返回非零值(真),表示文件流 fp 已经到达文件的末尾。
while(fgets(buf,sizeof(buf),fp)!=NULL && !feof(fp)){//确保读到了文件尾
//这里为了避免记录单词查询记录时出错,我们把buf最后的回车符去掉
size_t ret = strcspn(buf,"\n");// 使用strcspn函数找到回车符的位置
// 如果找到回车符,则将其替换为字符串结束符'\0'
if (buf[ret] == '\n') {
buf[ret] = '\0';
}
char dest[25];//存储读出来的单词
memset(dest,0,sizeof(dest));//清0
//sscanf 函数在提取数据时是以空白字符(例如空格、制表符、换行符等)作为分隔符的。当你使用 "%s" 格式指定来提取一个字符串时
//,sscanf 会从输入字符串 input 中找到第一个非空白字符,然后开始提取字符,直到再次遇到空白字符为止。
sscanf(buf,"%s",dest);//观察字典文件可知,只需要拷贝前17个字节中的单词部分
if( strcmp(msg,dest) == 0 ){//匹配查询的单词
memset(msg2,0,sizeof(msg2));
strcpy(msg2,&buf[17]);//从第18个字节开始一直到最后,就是单词的解释
send(socket_ok,msg2,strlen(msg2),0);
history(mydb,msg,msg2,name);//记录查询
return;
}
memset(buf,0,sizeof(buf));
}
//程序到这里说明没有找到单词
char msg3[64] = "-1";
send(socket_ok,msg3,strlen(msg3),0);
fclose(fp);
}
//查看单词查询记录
void dict_history(sqlite3* mydb,int socket_ok,char name[]){
//操作数据库,执行特定的sql语句
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"select * from history where name = '%s';",name);
printf("%s\n",sql);
//操作数据库
char** resultp; //resultp里面存储了数据表中的所有数据
int row;
int column;
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
char resultStr[4096] = "";//存储结果集
memset(resultStr,0,sizeof(resultStr));
//拼接字符串
for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
{
strcat(resultStr, resultp[i]);//拼接字符串
strcat(resultStr, "\t\t"); // 使用制表符分隔
if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
{
strcat(resultStr, "\n");//换行
}
}
//发送数据
send(socket_ok,resultStr,sizeof(resultStr),0);
memset(sql,0,sizeof(sql));
}
//收藏单词
void shoucang_word(sqlite3* mydb,int socket_ok,char name[]){
//操作数据库
char** resultp;
int row;
int column;
//接收要收藏的单词
char word[12];
memset(word,0,sizeof(word));
recv(socket_ok,word,sizeof(word),0);
//操作数据库,执行特定的sql语句
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"insert into shoucang(name,word)values('%s','%s')",name,word);
printf("%s\n",sql);
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
//返回
char msg[12]="1";
send(socket_ok,msg,sizeof(msg),0);
memset(sql,0,sizeof(sql));
}
//查看收藏的单词
void sel_shoucnag(sqlite3* mydb,int socket_ok,char name[]){
//操作数据库
char** resultp;
int row;
int column;
//操作数据库,执行特定的sql语句
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"select distinct shoucang.*,history.explain from shoucang,history where shoucang.word = history.word and shoucang.name='%s';",name);
printf("%s\n",sql);
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
char resultStr[4096] = "";//存储结果集
memset(resultStr,0,sizeof(resultStr));
//拼接字符串
for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
{
strcat(resultStr, resultp[i]);//拼接字符串
strcat(resultStr, "\t\t"); // 使用制表符分隔
if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
{
strcat(resultStr, "\n");//换行
}
}
//发送数据
send(socket_ok,resultStr,sizeof(resultStr),0);
memset(sql,0,sizeof(sql));
}
//删除收藏的单词
void del_shoucang(sqlite3* mydb,int socket_ok,char name[]){
//操作数据库
char** resultp;
int row;
int column;
//先查询所有收藏的单词
char sql2[128];
//拼接字符串
snprintf(sql2,sizeof(sql2),"select * from shoucang where name = '%s';",name);
sqlite3_get_table(mydb,sql2,&resultp,&row,&column,NULL);
char resultStr[4096] = "";//存储结果集
memset(resultStr,0,sizeof(resultStr));
//拼接字符串
for(int i=0;i<(row+1)*column;i++)//(row+1)这里加1,是因为没有把头算进去,我们要想输出头,就需要+1
{
strcat(resultStr, resultp[i]);//拼接字符串
strcat(resultStr, "\t\t"); // 使用制表符分隔
if((i+1)%column == 0)//这里是换行,每当下标i取模列为0的时候换行
{
strcat(resultStr, "\n");//换行
}
}
//发送数据
send(socket_ok,resultStr,sizeof(resultStr),0);
//接收要删除的单词
char del_word[12];
memset(del_word,0,sizeof(del_word));
recv(socket_ok,del_word,sizeof(del_word),0);
//拼接字符串
char sql[512];
memset(sql,0,sizeof(sql));
snprintf(sql,sizeof(sql),"delete from shoucang where word = '%s'and name = '%s';",del_word,name);
printf("%s\n",sql);
sqlite3_get_table(mydb,sql,&resultp,&row,&column,NULL);
//返回
char msg[12]="1";
send(socket_ok,msg,sizeof(msg),0);
memset(sql,0,sizeof(sql));
}
//线程函数
void* jieshou(void* arg){
//取出每个客户端对应的套接字
int socket_ok2 = *((int *)arg);
//打开数据库
sqlite3* mydb = NULL;
int ret = sqlite3_open("./dict.db",&mydb);
if(ret==-1){
perror("open failed");
exit(0);
}
char name[12];//存储当前登录人的名字
//在这里执行匹配逻辑
char buf[128];
while(1){
//5.接收客户端发来的操作标志
memset(buf,0,sizeof(buf));
recv(socket_ok2,buf,sizeof(buf),0);//阻塞等待,接收操作标志位
printf("服务端接收到 %s 号操作\n",buf);
int input = atoi(buf);
switch (input)
{
case 1:
strcpy(name,login(mydb,socket_ok2));//注意这里接收了登录时用户的名字
break;
case 2:
user_register(mydb,socket_ok2);
break;
case 3:
dict(mydb,socket_ok2,name);
break;
case 4:
dict_history(mydb,socket_ok2,name);
break;
case 5:
shoucang_word(mydb,socket_ok2,name);
break;
case 6:
sel_shoucnag(mydb,socket_ok2,name);
break;
case 7:
del_shoucang(mydb,socket_ok2,name);
break;
case 0:
exit(0);
break;
default:
printf("输入错误,请重新输入\n");
break;
}
}
close(socket_ok2);
}
int main(int argc,char** argv)
{
//1. 创建套接字
int socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(socket_fd == -1){
printf("创建套接字失败\n");
return -1;
}
//2. 绑定套接字与服务端网络地址
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
s_addr.sin_addr.s_addr = inet_addr(argv[1]);
//绑定
int bind_ok = bind(socket_fd,(struct sockaddr*)&s_addr,sizeof(s_addr));
if(bind_ok==-1){
perror("bind failed");
}
//3. 设置监听
int socket_listen = listen(socket_fd,4);
while(1){//在这个死循环里循环等待,对端发来的请求,来一个我就开一个线程
//4.等待对端连接
printf("等待连接\n");
struct sockaddr_in c_addr;//保存客户端地址信息
socklen_t size_len = sizeof(c_addr);
int socket_ok = accept(socket_fd,(struct sockaddr*)&c_addr,&size_len);
if(socket_ok==-1){
perror("连接失败\n");
return -1;
}
printf("连接成功\n");
//定义线程号
pthread_t tid;
pthread_create(&tid,NULL,&jieshou&socket_ok);
}
close(socket_fd);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//基于TCP通信,使用数据库完成学生信息管理系统,并增加电子词典功能
//客户端
int socket_fd = -1;
char result[4096];
//登录管理
int login(){
//发送操作标志位
char buf[12] = "1";
send(socket_fd,buf,sizeof(buf),0);
char id[12];
printf("请输入4位账号:");
scanf("%s",id);
//发送账号
send(socket_fd,id,strlen(id),0);
char password[12];
printf("请输入3位密码:");
scanf("%s",password);
//发送密码
send(socket_fd,password,strlen(password),0);
char name[12];
printf("请输入你的姓名:");
scanf("%s",name);
send(socket_fd,name,strlen(name),0);
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(result[0] != '\0'){//有账号且密码正确
return 1;
}else{//无账号或账号密码错误
return -1;
}
}
//注册管理
void user_register(){
//发送操作标志位
char buf[12] = "2";
send(socket_fd,buf,sizeof(buf),0);
char id[12];
printf("请输入4位账号:");
scanf("%s",id);
send(socket_fd,id,strlen(id),0);
char password[12];
printf("请输入3位密码:");
scanf("%s",password);
send(socket_fd,password,strlen(password),0);
char name[12];
printf("请输入你的姓名:");
scanf("%s",name);
send(socket_fd,name,strlen(name),0);
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(strcmp(result,"1")==0){//注册成功
printf("账号注册成功\n");
}else if(strcmp(result,"-1")==0){//账号非法
printf("账号重复,请重新输入\n");
}
}
//退出
void quit(){
//发送操作标志位
char buf[12] = "0";
send(socket_fd,buf,sizeof(buf),0);
}
//收藏单词
void shoucang_word(char word[]){
//发送操作标志位
char buf[12] = "5";
send(socket_fd,buf,sizeof(buf),0);
//发送给收藏的单词给服务端
send(socket_fd,word,strlen(word),0);
//接收结果
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);
if(strcmp(result,"1")==0){
printf("收藏成功\n");
}else{
printf("收藏失败\n");
}
}
//字典功能
void dict(){
//发送操作标志位
char buf[12] = "3";
send(socket_fd,buf,sizeof(buf),0);
char search[30];
printf("请输入你要查询的单词:");
scanf("%s",search);
//发送给服务端查询
send(socket_fd,search,strlen(search),0);
//接收查询结果
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);
if(strcmp(result,"-1")==0){
printf("抱歉你的输入有误 或者 本词典没有收录此单词\n");
}else{//查询成功
printf("%s\n",result);
printf("\n");
//只有查询成功,才有收藏的机会
char input[12];
memset(input,0,sizeof(input));
printf("是否收藏此单词(yes/no)?");
scanf("%s",input);
if(strcmp(input,"yes")==0){
//调用收藏函数
shoucang_word(search);
}
}
}
//查看单词查询记录
void dict_history(){
//发送操作标志位
char buf[128] = "4";
send(socket_fd,buf,sizeof(buf),0);
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(result[0] != '\0'){
printf("%s\n",result);
}else{
printf("查询失败\n");
}
}
//查看收藏的单词
void sel_shoucnag(){
//发送操作标志位
char buf[128] = "6";
send(socket_fd,buf,sizeof(buf),0);
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(result[0] != '\0'){
printf("%s\n",result);
}else{
printf("查询失败\n");
}
}
//删除收藏的单词
void del_shoucang(){
//发送操作标志位
char buf[128] = "7";
send(socket_fd,buf,sizeof(buf),0);
//接收所有收藏的单词数据,供用户选择
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(result[0] != '\0'){
printf("%s\n",result);
char del_word[30];
printf("请输入要删除的单词:");
scanf("%s",del_word);
send(socket_fd,del_word,strlen(del_word),0);
//接收消息
memset(result,0,sizeof(result));
recv(socket_fd,result,sizeof(result),0);//阻塞等待
if(result[0] != '\0'){
printf("删除成功\n");
}else{
printf("删除失败\n");
}
}else{
printf("查询失败\n");
}
//接收消息
}
void menu(){
printf("*********************************************************\n");
printf("**** 1. dict 2. dict_history ****\n");
printf("**** 3. sel_shoucnag 4. del_shoucang ****\n");
printf("**** 0. exit ****\n");
printf("*********************************************************\n");
}
void menu2(){
printf("*********************************************************\n");
printf("**** 1.login 2.register ****\n");
printf("*********************************************************\n");
}
void caidan(){
int input;
do{
printf("\n");
sleep(1);
menu();
printf("请输入你的操作:");
scanf("%d",&input);
switch (input)
{
case 1:
dict();
break;
case 2:
dict_history();
break;
case 3:
sel_shoucnag();
break;
case 4:
del_shoucang();
break;
case 0:
quit();
break;
default:
printf("输入错误,请重新输入\n");
break;
}
}while(input);
}
int main(int argc,char** argv)
{
//1. 创建套接字
socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(socket_fd == -1){
printf("创建套接字失败\n");
return -1;
}
//2.初始化服务端网络地址
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
s_addr.sin_addr.s_addr = inet_addr(argv[1]);
//3. 请求连接
connect(socket_fd,(struct sockaddr*)&s_addr,sizeof(s_addr));
//先登录
int in;
do{
printf("\n");
sleep(1);
menu2();
printf("请输入你的操作:");
scanf("%d",&in);
int ret = -1;
switch (in)
{
case 1:
ret = login();
if(ret==1){
printf("登录成功\n");
caidan();
exit(0);
}else if(ret == -1){
printf("账号或者密码错误\n");
}
break;
case 2:
user_register();
break;
default:
printf("输入错误,请重新选择\n");
break;
}
}while(in);
close(socket_fd);
return 0;
}