接触到的基于Linux的第一个实战小项目,在众多大牛的协助下完美实现。
在线词典功能的实现
1、用户的注册
2、用户登录
3、单词的查询
4、历史记录的查看
5、用户在登录后修改密码
头文件
#ifndef COMM_HH
#define COMM_HH
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <signal.h>
#include<time.h>
#define MSGTYPE_R 01 //用户注册
#define MSGTYPE_L 02 //用户登录
#define MSGTYPE_Q 03 //用户查询
#define MSGTYPE_H 04//用户历史记录
#define MSGTYPE_C 05//用户修改密码
#define DATABASE "lict.db"
typedef struct msg_struct{
char cmd; //1-register 2-log 3-exit 4-dic 5-history 6-passwd 12.服务器应答
char name[32];
char passwd[16];
char new_passwd[16];
char data[256];
int type;
//以下是服务器的回应
char ret; //0-success errno-失败原理
char response[128];
}MSG_T;
#endif
客户端的实现
#include "comm.h"
int do_register(int socket_cli, MSG_T *msg)//客户端注册
{
printf("用户注册注册中 ... \n");
int ret;
memset(msg, 0, sizeof(MSG_T));
msg->type = MSGTYPE_R;//11;
printf("请输入账号:"); scanf("%s", msg->name); getchar();
printf(" ________________\n");
printf("请输入密码:"); scanf("%s", msg->data); getchar();
ret=send(socket_cli, msg, sizeof(MSG_T), 0);
if (ret < 0){
perror("send err");
printf("注册信息发送失败.\n");
return -1;
}
if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("注册失败.\n");
return -1;
}
printf("%s\n", msg->data);
return 1;
}
int do_login(int socket_cli, MSG_T *msg)// 登录, 必服务器返回 "OK" 才表示登录成功
{
printf("正在登录 ...\n");
memset(msg, 0, sizeof(MSG_T));
msg->type = MSGTYPE_L;
printf(" 请输入账号:"); scanf("%s", msg->name); getchar();
printf(" ---------------\n");
printf(" 请输入密码:"); scanf("%s", msg->data); getchar();
if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("请重新登录\n");
return -1;
}
if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("登录失败 !\n");
return -1;
}
//登录成功
if (strncmp(msg->data, "OK", 3) == 0)
{
printf("登录成功 ! \n");
memset(msg, 0, sizeof(MSG_T));
return 1;
}
else
{
printf("%s\n", msg->data);
}
return 0;
}
int do_change(int socket_cli, MSG_T *msg)//修改用户密码
{
printf("正在修改用户密码,务必确认本人操作 \n");
int ret;
memset(msg, 0, sizeof(MSG_T));
msg->type = MSGTYPE_C;
printf("请输入账号:"); scanf("%s", msg->name); getchar();
printf(" ________________\n");
printf("请输入密码:"); scanf("%s", msg->data); getchar();
printf("\n");
printf(" ________________\n");
printf("请输入新密码:"); scanf("%s", msg->new_passwd); getchar();
ret=send(socket_cli, msg, sizeof(MSG_T), 0);
if (ret < 0){
perror("send err");
printf("修改请求发送失败.\n");
return -1;
}
memset(msg, 0, sizeof(MSG_T));
if (ret =0){
perror("change err");
printf("密码修改成功\n");
return -1;
}
if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("修改失败.\n");
return -1;
}
return 1;
}
int do_query(int socket_cli, MSG_T *msg) // 单词查询
{
printf("查询中 ...\n");
recv(socket_cli, msg, sizeof(MSG_T), 0);
memset(msg, 0, sizeof(MSG_T));
msg->type = MSGTYPE_Q;
while(1)
{
printf("请输入单词:"); scanf("%s", msg->data); getchar();
if (strncmp(msg->data, "*", 1) == 0)
break;//退出
if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("发送失败\n");
return -1;
}
memset(msg, 0, sizeof(MSG_T));
if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
perror("接收失败");
return -1;
}
printf("%s\n", msg->data);
}
return 1;
}
int do_history(int socket_cli, MSG_T *msg) // 历史记录查询
{
printf("...历史记录 ...\n");
msg->type = MSGTYPE_H;
//将消息发送给服务器
if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("发送失败\n");
return -1;
}
while(1)
{
if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
{
printf("接收失败\n");
return -1;
}
if (msg->data[0] == '\0')
break;
printf("%s\n", msg->data);
}
return 1;
}
int main(int argc, const char *argv[])
{
struct sockaddr_in server_addr;
int input_nbr;
MSG_T send_msg;
MSG_T msg;
int socket_cli = socket(AF_INET,SOCK_STREAM, 0 );
if(socket_cli <0){
perror("create client socket err");
return -3;
}
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(10050);
serv_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.17.129");
int ret = connect(socket_cli,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
if(ret <0){
perror("connect err");
return -3;
}
struct msg_struct cli_msg;
while (1)
{
printf(" ______________________________________________\n");
printf(" ______________________________________________\n");
printf(" ________ ________\n");
printf(" ________ 1.注册 2.登录 3.退出 ________\n");
printf(" ______________________________________________\n");
printf(" ______________________________________________\n");
printf(" ______________________________________________\n");
printf("\n");
printf("请选择:");
scanf("%d", &input_nbr);
getchar();//回收垃圾字符
switch (input_nbr)
{
case 1:
do_register(socket_cli, &send_msg);
break;
case 2:
if (do_login(socket_cli, &send_msg) ==1 )
{
goto _login;
}
break;
case 3:
close(socket_cli);
exit(0);
break;
default:
printf("Invalid data cmd. \n");
break;
}
}
_login:
while(1)//登录后的界面
{
printf(" ______________________________________________\n");
printf(" ______________________________________________\n");
printf("\n");
printf("1.查询(*退出) 2.历史查询 3.退出 4.修改用户密码 \n");
printf(" ______________________________________________\n");
printf(" ______________________________________________\n");
printf("\n");
printf("请选择:");
input_nbr = 0;
scanf("%d", &input_nbr);
getchar();
switch (input_nbr)
{
case 1:
do_query(socket_cli, &send_msg);
break;
case 2:
do_history(socket_cli, &send_msg);
break;
case 3:
close(socket_cli);
exit(0);
break;
/*case 4:
do_change(socket_cli, &send_msg);
exit(0);
break;*/
default:
printf("Invalid data cmd. \n");
break;
}
}
return 0;
}
服务器的实现
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <signal.h>
#include<time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "comm.h"
static int cnt=1;
static int num=0;
static int s=0;
static int n=0;
static int ave;
struct thread_msg{
int cli_socket;
pthread_t tid;
};
sqlite3 *db = NULL;
int do_query(int socket_cli, MSG_T *msg, sqlite3 *db);
int do_login(int socket_cli, MSG_T *msg, sqlite3 *db);
int do_history(int socket_cli, MSG_T *msg, sqlite3 *db);
void get_date(char *data);
int print(void *para,int f_num,char **f_value,char **f_name)
{
int i;
if(cnt)
{
printf("--------------------------------------------------\n");
cnt--;
for(i=0;i<f_num;i++)
{
printf("%-12s",f_name[i]);
}
printf("\n");
printf("--------------------------------------------------\n");
}
for(i=0;i<f_num;i++)
{
printf("%-12s",f_value[i]);
}
printf("\n");
printf("--------------------------------------------------\n");
return 0;
}
int do_register(int socket_cli, MSG_T *msg, sqlite3 *db) //用户注册
{
char sql[128] = {0};
int ret;
snprintf(sql,sizeof(sql), "insert into user values('%s', '%s');", msg->name, msg->data );
ret = sqlite3_exec(db,sql,print,NULL,NULL);
if (ret!= SQLITE_OK){
printf("%s\n",sqlite3_errmsg(db));
memset(msg->data, 0, strlen(msg->data));
snprintf(msg->data, sizeof (msg->data),"用户: %s 已存在!", msg->name);
}
else{
printf( "客户(%s)注册成功\n",msg->name );
memset(msg->data, 0, strlen(msg->data));
strcpy(msg->data, "register ok!");
}
//返回应答
ret=send(socket_cli, msg, sizeof(MSG_T), 0);
if(ret<0){
printf("发送失败\n");
return 0;
}
return 1;
}
void *serv_for_client(void *args)
{
int ret;
struct thread_msg *pmsg = args;
int socketx = pmsg->cli_socket;
struct msg_struct serv_msg;
while(1){
memset(&serv_msg,0,sizeof(serv_msg));
ret = recv(socketx,&serv_msg,sizeof(serv_msg),0);
if(ret<0){
perror("recv err"); close(socketx); free(pmsg); return NULL;
}else if(ret == 0){
printf("serv found peer shutdwon\n"); close(socketx); free(pmsg); return NULL;
}
printf("%s->%d\n",__func__,__LINE__);
switch(serv_msg.type)
{
case 01: //MSGTYPE_R
do_register(socketx, &serv_msg, db);
break;
case 02: //MSGTYPE_L:
do_login(socketx, &serv_msg, db);
break;
case 03: //MSGTYPE_Q:
do_query(socketx, &serv_msg, db);
break;
case 04: //MSGTYPE_H:
do_history(socketx, &serv_msg, db);
break;
default:
printf("invalid data msg.\n");
}
ret = send(socketx,&serv_msg,sizeof(serv_msg),0);
if(ret<0){
perror("send err"); return NULL;
}
}
/*while (recv(socketx, &serv_msg, sizeof(MSG_T), 0) > 0)
{
}
printf("client exit.\n");
close(socketx);
exit(0);
return 0;*/
close(socketx);
return NULL;
}
int do_login(int socket_cli, MSG_T *msg, sqlite3 *db)//用户登录
{
char sql[128] = {0};
char *errmsg = NULL, **result = NULL;
int nrow, ncolumn,ret;
snprintf(sql,sizeof(sql), "select * from user where name='%s' and passwd='%s';", msg->name, msg->data);
ret=sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) ;
if (ret != SQLITE_OK){
printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
}else{
printf("表格获取成功\n");
}
if (nrow == 1)//查询成功,数据库中拥有此用户
{
printf("用户:%s登录成功\n", msg->name);
memset(msg->data, 0, strlen(msg->data));
strcpy(msg->data, "OK");
}
else //用户名或密码错误
{
printf("用户:(%s) 登录失败! \n", msg->name);
perror("login err");
memset(msg->data, 0, strlen(msg->data));
strcpy(msg->data, "账号或密码错误! \n");
}
//返回应答
ret=send(socket_cli, msg, sizeof(MSG_T), 0);
if (ret<0){
perror("发送失败\n");
return 0;
}
return 1;
}
int do_searchword(MSG_T *msg, char *word)//根据单词从dirt.txt文本中查找对应的注释信息
{
FILE *fp = NULL;
int word_len = strlen(word);
char row_data[512] = {'\0'};
int res = 0;
int ret;
char *p; //指向注释
fp = fopen("dict.txt", "r") ;//打开词典文件
if (fp==NULL){
perror("fail to open dict.txt.\n");
return -1;
}
//打印客户端要查询的单词
word_len = strlen(word);
printf("%s, len = %d\n", word, word_len );
while (fgets(row_data, 512, fp) != NULL)
{
res = strncmp(row_data, word, word_len);//每行对比前word_len个字节
if (res != 0)
continue;
if (row_data[word_len] != ' ') //单词跟注释之间没有空格
goto _end;
p = row_data + word_len;// 找到了单词,跳过所有的空格
while (*p == ' ')
{
p++;
}
strcpy(msg->data, p);
fclose(fp);
return 1;
}
_end:
fclose(fp);
return 0; //文件对比完,单词未找到
}
int do_query(int socket_cli, MSG_T *msg, sqlite3 *db) // 单词查询
{
char sql[128] = {0};
char word[64] = {0};
int found = 0;
char date[128] = {0};
char *errmsg;
int ret;
printf("\n");
//单词查找
strcpy(word, msg->data);
//memset(msg->data, 0, strlen(msg->data));
found = do_searchword(msg, word);//调用函数
if (found == 1) {
get_date(date);//获取系统时间
snprintf(sql, 128,"insert into record values('%s', '%s', '%s')", msg->name, date, word);
ret=sqlite3_exec(db, sql,print, NULL, NULL );
if (ret != SQLITE_OK){
printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
return -1;
}
}
else if (found == 0)//没有找到
{
memset(msg->data, 0, strlen(msg->data));
strcpy(msg->data, "单词未找到!\n");
}
else if (found == -1)//dict.txt代开失败
{
memset(msg->data, 0, strlen(msg->data));
strcpy(msg->data, "打开 dict.txt.失败了");
}
send(socket_cli, msg, sizeof(MSG_T), 0);//将查询的结果发送给客户端
return 0;
}
int history_callback(void* arg,int colCount,char** colValue,char** colName)// 得到查询结果,并且需要将历史记录发送给客户端
{
int socketx;
MSG_T msg;
socketx = *((int *)arg);
sprintf(msg.data, "%s , %s", colValue[1], colValue[2]);
send(socketx, &msg, sizeof(MSG_T), 0);
return 0;
}
int do_history(int socket_cli, MSG_T *msg, sqlite3 *db)// 历史记录查询
{
char sql[128] = {0};
char *errmsg;
int ret;
sprintf(sql, "select * from record where name = '%s'", msg->name);
ret=sqlite3_exec(db, sql, history_callback,(void *)&socket_cli,NULL );
if(ret!= SQLITE_OK){
printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
}
else
{
printf("sqlite3 query record done.\n");
}
msg->data[0] = '\0';// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
ret = send(socket_cli, &msg, sizeof(MSG_T), 0);
if(ret<0){
perror("histroy send err");
return -34;
}
return 0;
}
int do_change(int socket_cli, MSG_T *msg, sqlite3 *db) //修改用户密码
{
char sql[128] = {0};
int ret;
char **pt=NULL;
int nrow,ncolumn;
snprintf(sql,sizeof(sql), "select from user where user=\'%S\' and passwd=\'%s\';", msg->name, msg->data );//查看数据库是否存在
ret = sqlite3_get_table(db,sql,&pt,&norm,&ncolumn,NULL);
if (ret){
printf("gettabale err%s\n",sqlite3_errmsg(db));
return -2;
}
if(nrow!=0)
{
char **pt=NULL;
snprintf(sql,sizeof(sql), "updata user set passwd=\'%S\' and passwd=\'%s\';", msg->name, msg->data );//修改数据库中用户密码
ret = sqlite3_get_table(db,sql,&pt,NULL,NULL,NULL);
if (ret){
printf("recv gettabale err%s\n",sqlite3_errmsg(db));
return -2;
}
printf("密码修改成功");
strcpy(msg->data, "修改成功!");
ret = send(socket_cli, &msg, sizeof(MSG_T), 0);
if(ret<0){
perror("change send err");
return -34;
}
}
else{
strcpy(msg->data, "输入有误!");
ret=send(socket_cli, msg, sizeof(MSG_T), 0);
if(ret<0){
perror("change send err");
return -34;
memset(msg->data, 0, strlen(msg->data));
}
//返回应答
if(ret<0){
printf("发送失败\n");
return 0;
}
return 1;
}
void get_date(char *data)//获取系统时间
{
time_t rowtime;
struct tm *info;
time(&rowtime);
info = localtime(&rowtime);
sprintf(data, "%d-%d-%d %d:%d:%d", info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec);
printf("get date is : %s\n", data);
}
int main(int argc, const char *argv[])
{
int ret;
int socket_cli ;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
char sql[128] = {0};
pid_t pid;
char ipv4_addr[16];
/*********************数据库操作*********************/
ret = sqlite3_open("./dict.db",&db);
if(ret)
{
printf("sqlite3_open():%s\n",sqlite3_errmsg(db));
exit(-1);
}
printf("sqlite3 open %s success.\n", DATABASE);
//snprintf(sql,128, "");
sqlite3_exec(db, sql, print ,NULL, NULL );
if(ret != SQLITE_OK){
printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
return -1;
}
memset(sql, 0, sizeof(sql));
sprintf(sql, " " );
ret=sqlite3_exec(db, sql, print , NULL, NULL );//打开记录表
if (ret != SQLITE_OK){
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
/*********************网络通信*********************/
int main_socket=socket(AF_INET,SOCK_STREAM,0);
if(main_socket<0){
perror("crreat main_socket err");
return -5;
}
int enable=1;
setsockopt(main_socket,SOL_SOCKET,SO_REUSEADDR,&enable,sizeof(enable));
struct sockaddr_in serv_addr;
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(10050);
serv_addr.sin_addr.s_addr=INADDR_ANY;
ret=bind(main_socket,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(ret<0){
perror("bind err");
return -15;
}
ret = listen(main_socket,5);
if(ret<0){
perror("listen err");
return -3;
}
struct sockaddr_in cli_addr;
addrlen=sizeof(cli_addr);
struct thread_msg*pmsg=NULL;
int socket_new;
int cli_socket1;
loop:
cli_socket1=accept(main_socket,(struct sockaddr*)&cli_addr,&addrlen);
if(cli_socket1<0){
perror("accept err");
return -5;
}
pmsg=malloc(sizeof(*pmsg));
pmsg->cli_socket=cli_socket1;
pthread_create( &pmsg->tid,NULL,serv_for_client, pmsg );
goto loop;
close(main_socket);
return 0;
}
运行结果
服务器:
客户端: