https://blog.youkuaiyun.com/m0_37542524/article/details/85001614
应用综合项目
在线词典 简介
1,在线词典功能,分为客户端和服务器端
2,客户端有三个模块:注册、登录、查询(查询单词、查询历史记录)
3,服务器端要实现多并发服务器,这里采用多进程并发服务器:注册、登录、查询(查询单词、查询历史记录)
4,用户分为普通用户和管理员用户:管理员用户可以查询所有普通用户的历史记录,还可以看到词库中未定义的单词查询记录,普通用户只能查到自己的,词库中中有定义的记录
5,客户端和服务器通信只要通过一个信息结构体实现:
客户端 Client
框架
代码
/*
*Client.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#define N 32
#define INIT_AVLUE -1;
#define R 1 //用户-注册
#define L 2 //用户-登录
#define Q 3 //用户-查询
#define H 4 //用户-历史记录
#define USR 1 //普通用户
#define ROOT 2 //超级用户
//定义通信双方的信息结构体
typedef struct _msg
{
int flag; //1:flag or 2:root
int type; //用户名
char name[N];
char data[256]; //pwssword or word
} MSG;
typedef int (*CallBackFunDiplay)(void * arg);
typedef int (*CallBackFunChoose)(int socketfd, MSG * msg);
typedef struct _display
{
int result; //存储函数返回值的结果
CallBackFunDiplay opt; //函数指针
} vDisplays;
typedef struct _functions
{
int result;
CallBackFunChoose opt;
} vFunctions;
// 函数声明
int Display_UserChoose(void *arg);
int Display_First_Menu(void *arg);
int Display_Second_Menu(void *arg);
int Init_Client(int *connfd, struct sockaddr_in *servaddr, const char* addr, const char *port);
int do_register(int sockfd, MSG *msg);
int do_login(int sockfd, MSG *msg);
int do_query(int sockfd, MSG *msg);
int do_history(int sockfd, MSG *msg);
int do_close(int sockfd, MSG *arg );
int main(int argc, const char *argv[])
{
int socketfd = INIT_AVLUE;
struct sockaddr_in servaddr;
int Input_Cmd;
int Input_Cmd_Second;
MSG msg;
vDisplays pDisplay;
vFunctions pFunction;
bzero(&msg, sizeof(msg));
bzero(&pDisplay, sizeof(pDisplay));
bzero(&pFunction, sizeof(pFunction));
if (argc < 3)
{
printf("Input Error: %s <ip> <port>\n", argv[0]);
return -1;
}
if (atoi(argv[2]) < 5000 )
{
printf("Input Port Error.\n");
return -1;
}
if (Init_Client(&socketfd, &servaddr, argv[1], argv[2]) == -1)
{
printf("Fail:Init_Client.\n");
return -1;
}
msg.flag = -1;
do {
pDisplay.opt = Display_UserChoose;
pDisplay.result = pDisplay.opt(NULL);
if (scanf("%d", &msg.flag) == 0)
msg.flag = -1;
while (getchar() != '\n');
if (msg.flag != 1 && msg.flag != 2)
msg.flag = -1;
} while (msg.flag < 0);
for (;;)
{
pDisplay.opt = Display_First_Menu;
pDisplay.result = pDisplay.opt(NULL);
Input_Cmd = -1;
if (scanf("%d", &Input_Cmd)) {};
getchar();
switch (Input_Cmd)
{
case 1:
pFunction.opt = do_register;
pFunction.result = pFunction.opt(socketfd, &msg);
break;
case 2:
pFunction.opt = do_login;
if ((pFunction.result = pFunction.opt(socketfd, &msg)) == 1)
{
goto _NEXT;
}
break;
case 3:
pFunction.opt = do_close;
pFunction.result = pFunction.opt(socketfd, NULL);
exit(0);
break;
default:
puts(" Input Error Number Cmd.");
break;
}
}
_NEXT:
#if 1
puts("NEXT");
#endif
for (;;)
{
pDisplay.opt = Display_Second_Menu;
pDisplay.result = pDisplay.opt(NULL);
Input_Cmd_Second = -1;
if (scanf("%d", &Input_Cmd_Second)) {};
getchar();
switch (Input_Cmd_Second)
{
case 1:
pFunction.opt = do_query;
pFunction.result = pFunction.opt(socketfd, &msg);
break;
case 2:
pFunction.opt = do_history;
pFunction.result = pFunction.opt(socketfd, &msg);
break;
case 3:
pFunction.opt = do_close;
pFunction.result = pFunction.opt(socketfd, NULL);
exit(0);
break;
default:
puts("Input Error Cmd.");
break;
}
}
return 0;
}
/**客户端:用户注册
* 1.输入注册信息 用户名和密码
*2.发送注册的信息给服务器
*3.接收从服务器的反馈信息
*/
int do_register(int sockfd, MSG *msg)
{
if (msg == NULL )
{
puts("do_register: msg parm NULL");
return -1;
}
char passwd_str[32];
int flag = -1;
msg->type = R;
//1.输入注册信息
//
printf("Input register name:");
if (scanf("%s", msg->name)) {};
getchar();
do {
printf("Input register password:");
if (scanf("%s", passwd_str)) {};
getchar();
printf("Please Confirm password:");
if (scanf("%s", msg->data)) {};
getchar();
if (strlen(msg->data) == strlen(passwd_str))
{
if (strncmp(msg->data, passwd_str, strlen(passwd_str)) == 0)
{
flag = 1;
}
else
{
flag = -1;
puts(" Error entering password ");
}
}
else
{
puts("Error entering password");
flag = -1;
}
} while (flag < 0);
//2.发送
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("do_register:Send Fail.\n");
return -1;
}
printf("Client Send msg %s\n",msg->data);
//接收
if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("do_register fail to recv");
return -1;
}
if (strncasecmp(msg->data, "OK", strlen("OK")) == 0)
{
printf("Receive:register OK.\n");
return 1;
}
else
{
// user name 已经注册存在了
printf("Receive: %s\n", msg->data);
}
return 0;
}
/**客户端:用户登录
*1.输入登录信息 用户名和密码
*2.发送注册的信息给服务器
*3.接收从服务器的反馈信息
*/
int do_login(int sockfd, MSG *msg)
{
if (msg == NULL)
{
puts("do_query: msg parm NULL ");
return -1;
}
msg->type = L;
//1.输入登录信息-用户
printf("Input login name:");
if (scanf("%s", msg->name)) {};
getchar();
//2.输入登录信息-密码
printf("Input login password:");
if (scanf("%s", msg->data)) {};
getchar();
//2.发送
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("Send Fail.\n");
return -1;
}
//3.接收
if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("Receive Fail.\n");
return -1;
}
//处理反馈消息
if (strncmp(msg->data, "OK", strlen("OK")) == 0)
{
printf("Login OK.\n");
return 1;
}
else
{
printf("%s\n", msg->data);
}
return 0;
}
/**客户端:用户查询
*1.输入查询信息 word
*2.发送查询信息给服务器
*3.接收从服务器的反馈信息
*/
int do_query(int sockfd, MSG *msg)
{
if (msg == NULL)
{
puts("do_query: msg parm NULL ");
return -1;
}
msg->type = Q;
while (1)
{
//1.输入查询信息
printf("Input word: ( '#' exit )");
if (scanf("%s", msg->data)) {};
getchar();
//客户端,输入#号,返回到上一级菜单
if (strncmp(msg->data, "#", strlen("#")) == 0)
{
break;
}
//2.发送: 将要查询的单词发送给服务器
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("Send Fail.\n");
return -1;
}
//3.接收:等待接受服务器,传递回来的单词的注释信息
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("Receive Fail.\n");
return -1;
}
//处理从服务器接受的信息
printf("%s\n", msg->data);
}
return 0;
}
/**客户端: 历史记录查询
*1.查询历史记录
*2.发送查询信息给服务器
*3.接收从服务器的反馈信息
*/
int do_history(int sockfd, MSG *msg)
{
if (msg == NULL)
{
puts("do_history: msg parm NULL");
return -1;
}
msg->type = H;
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("do_history: Send Fail.\n");
return -1;
}
// 接受服务器,传递回来的历史记录信息
while (1)
{
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
printf("do_history: Receive Fail.\n");
return -1;
}
//输出历史记录信息
// printf("%s\n", msg->data);
if (msg->data[0] == '\0')
{
break;
}
printf("%s\n", msg->data);
}
return 0;
}
int do_close(int sockfd, MSG * arg)
{
(void*)arg;
close(sockfd);
puts("Main exit");
}
/**
*1. 建立socket(connfd)
*2. 初始化服务器地址
*3. socket向服务器发送请求,建立连接
*/
int Init_Client(int *socketfd, struct sockaddr_in *servaddr, const char* addr, const char *port)
{
if ((*socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("fail to socket");
return -1;
}
bzero(servaddr, sizeof(struct sockaddr_in));
servaddr->sin_family = AF_INET; //指定协议族
servaddr->sin_port = htons(atoi(port)); //
servaddr->sin_addr.s_addr = inet_addr(addr);//
if (connect(*socketfd, (struct sockaddr*)servaddr, sizeof(struct sockaddr_in)) < 0)
{
perror("fail to connect.");
return -1;
}
return 0;
}
int Display_UserChoose(void *arg)
{
(void*)arg;
puts("---------------------------------------------------");
puts("----- Select User Mode [ 1:user 2: root] -----");
puts("---------------------------------------------------");
return 0;
}
int Display_First_Menu(void *arg)
{
(void*)arg;
puts("----------------------------------------------------");
puts("------------- Main Menu ---------------");
puts("----------- 1: New User Registrationu---------------");
puts("------------2: User Login ---------------");
puts("------------3: User Quit ---------------");
puts("----------------------------------------------------");
printf(" Please Input Select Number Function > \n");
return 0;
}
int Display_Second_Menu(void *arg)
{
(void*)arg;
puts("----------------------------------------------------");
puts("------------- Second Menu ---------------");
puts("----------- 1: Query World ---------------");
puts("------------2: Histroy Record ---------------");
puts("------------3: Quit ---------------");
puts("----------------------------------------------------");
printf(" Please Input Select Number Function > \n");
return 0;
}
服务器端 Server
框架
代码
/*
*Server.c
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <sqlite3.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>
#define N 32
#define INIT_AVLUE -1;
#define SIZE 128
#define R 1 //用户-注册
#define L 2 //用户-登录
#define Q 3 //用户-查询
#define H 4 //用户-历史记录
#define USR 1 //普通用户
#define ROOT 2 //超级用户
#define USE_DEBUG 1 //程序调试的宏 1 启动 0 失效
#define DATABASE "./table.db"
//定义通信双方的信息结构体
typedef struct _msg
{
int flag; //1:flag or 2:root
int type;
char name[N];
char data[256]; //pwssword or word
} MSG;
typedef struct _his
{
int fd;
MSG *msg;
}HIS_MSG;
typedef int (*CallBackFunChoose)(int socketfd, MSG * msg, sqlite3 *db);
typedef struct _functions
{
int result;
CallBackFunChoose opt;
} vFunctions;
// 函数声明
int do_client_handle(int newfd, struct sockaddr_in cin, sqlite3*db);
int Init_Server(int *listenfd, struct sockaddr_in *servaddr, const char* addr, const char *port);
int do_register(int sockfd, MSG *msg, sqlite3 *db);
int do_login(int sockfd, MSG *msg, sqlite3 *db);
int do_query(int sockfd, MSG *msg, sqlite3 *db);
int do_history(int sockfd, MSG *msg, sqlite3 *db);
int do_close(int sockfd, MSG *arg );
int do_create_table(sqlite3 *db);
const char *get_date(char * date);
int do_searchworld(MSG *msg);
int history_callback(void *his_msg, int f_num, char **f_value, char **f_name);
int main(int argc, const char *argv[])
{
// 入口参数判断
if (argc < 3)
{
printf("Input Error: %s <ip> <port>\n", argv[0]);
return -1;
}
if (atoi(argv[2]) < 5000 )
{
printf("Input Port Error.\n");
return -1;
}
sqlite3 *db;
// 数据库存在则打开,不存在则创建
if(sqlite3_open(DATABASE,&db) != SQLITE_OK)
{
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("open database:%s success.\n", DATABASE);
}
//表格不存在则创建数据库表格
if(do_create_table(db) < 0)
{
//创建数据库表格失败
return -1;
}
struct sockaddr_in servaddr;
int socketfd = INIT_AVLUE;
if (Init_Server(&socketfd, &servaddr, argv[1], argv[2]) == -1)
{
printf("Fail:Init_Serve");
return -1;
}
signal(SIGCHLD, SIG_IGN); //处理僵尸进程
pid_t pid;
int status;
int newfd = -1;
struct sockaddr_in cliaddr; //客户端的信息
socklen_t cliaddr_len = sizeof(cliaddr);
while(1)
{
//阻塞等待客户端连接
if ((newfd = accept(socketfd, (struct sockaddr *)&cliaddr, &cliaddr_len)) < 0)
{
perror("accept");
return -1;
}
//连接从成功,创建子进程
if ((pid = fork()) < 0)
{
perror("fork");
return -1;
}
else if (pid == 0)
{
//子进程:处理客户端具体的消息
close(socketfd);
do_client_handle(newfd, cliaddr, db);
}
else
{
//父进程:用来接受客户端的请求
close(newfd);
waitpid(-1, &status, WNOHANG);//以非阻塞方式回收当前进程的任意一个子进程
}
}
return 0;
}
/*
* 创建数据库表格
*/
int do_create_table(sqlite3 *db)
{
char sql[SIZE];
char **resultp;
int nrow;
int ncolumn;
char *errmsg;
//1:判断表格usr是否存在,不存在则创建
//
sprintf(sql,"select * from sqlite_master where type='table' and name='usr';");
sqlite3_get_table(db, sql, &resultp, &nrow, &ncolumn,&errmsg);
if(nrow == 0)
{
// usr: name | permission | password
sprintf(sql,"create table usr (name text primary key,permission integer, password txt);");
if(sqlite3_exec(db, sql, NULL, NULL,&errmsg) != SQLITE_OK )
{
printf("create table:%s %s\n", "usr", errmsg);
return -1;
}
else
{
puts("create table:usr success.");
}
}
else
{
puts("table:usr is OK.");
}
//2:判断表格record是否存在,不存在则创建
sprintf(sql,"select * from sqlite_master where type='table'and name='record';");
sqlite3_get_table(db, sql, &resultp, &nrow, &ncolumn,&errmsg);
if(nrow == 0)
{
//record: name | data | is_undefine
sprintf(sql,"create table record (name text,data text,word text,is_undefine integer);");
if (sqlite3_exec(db, sql, NULL, NULL,&errmsg) != SQLITE_OK)
{
printf("create table:%s %s\n", "record", errmsg);
return -1;
}
else
{
puts("create table:record success.");
}
}
else
{
puts("table:record is OK.");
}
return 0;
}
/*
* 客户端消息处理
*/
int do_client_handle(int newfd, struct sockaddr_in cin, sqlite3*db)
{
MSG msg;
char ipv4_addr[16];
int ret = -1;
vFunctions pFunction;
bzero(&pFunction, sizeof(pFunction));
inet_ntop(AF_INET, (void *)&cin.sin_addr.s_addr, ipv4_addr, sizeof(cin));
printf("client(ip:%s port:%d) is connected.\n", ipv4_addr, ntohs(cin.sin_port));
while(1)
{
bzero(&msg, sizeof(msg));
do{
ret = recv(newfd, &msg, sizeof(msg),0);
}while(ret < 0 && errno == EINTR);
if(ret < 0)
{
perror("recv");
close(newfd);
return -1;
}
if(ret == 0) //客户端已关闭
{
break;
}
//根据类型执行操作
printf("type:%d\n", msg.type);
switch(msg.type)
{
case R:
pFunction.opt = do_register;
pFunction.result = pFunction.opt(newfd, &msg, db);
break;
case L:
pFunction.opt = do_login;
pFunction.result = pFunction.opt(newfd, &msg, db);
break;
case Q:
pFunction.opt = do_query;
pFunction.result = pFunction.opt(newfd, &msg, db);
break;
case H:
pFunction.opt = do_history;
pFunction.result = pFunction.opt(newfd, &msg, db);
break;
default:
puts(" Input Error data msg");
break;
}
}
printf("client(ip:%s port:%d) exit.\n", ipv4_addr, ntohs(cin.sin_port));
close(newfd);
exit(0);
return 0;
}
/** 服务器:用户注册处理
* 1.用户信息插入数据库表格中
* 2.反馈消息给客户端
*/
int do_register(int sockfd, MSG *msg, sqlite3 *db)
{
if (msg == NULL )
{
puts("do_register: msg parm NULL");
return -1;
}
//将用户信息插入数据库表格usr(名字(主键),权限,密码
char sql[SIZE];
char *errmsg;
sprintf(sql, "insert into usr values('%s',%d,'%s');",msg->name, msg->flag, msg->data);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("do_register %s\n", errmsg);
//插入失败说明用户名已存在
strcpy(msg->data,"the usr already exit.");
}
else
{
printf("insert usr success.\n");
strcpy(msg->data, "OK");
}
//反馈给客户端
if(send(sockfd, msg, sizeof(MSG),0) < 0)
{
perror("do_register fail to send");
return -1;
}
#if USE_DEBUG
printf(" Server:(do_register) send msg data = %s\n",msg->data);
#endif
return 0;
}
/** 服务器:用户登录处理
* 1.在数据库表格中查询登录用户信息
* 2.反馈消息给客户端
*/
int do_login(int sockfd, MSG *msg, sqlite3 *db)
{
if (msg == NULL)
{
puts("do_login: msg parm NULL");
return -1;
}
char sql[SIZE] = {};
char *errmsg;
int nrow;
int ncloumn;
char **resultp;
//sql 查询登录的用户名
sprintf(sql,"select * from usr where name = '%s';",msg->name);
if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg) < 0)
{
printf("do_register %s", errmsg);
return -1;
}
if (nrow == 0)// 密码或者用户名错误
{
printf("login name:%s does not exit.\n", msg->name);
strcpy(msg->data, "the name does not exit.");
}
if(nrow == 1)
{
//用户存在: 查询成功,数据库中拥有此用户
//判断:用户和权限匹配
if(msg->flag == atoi(resultp[ncloumn + 1]))
{
//判断登录密码输入
if (strncmp(msg->data, resultp[ncloumn + 2], strlen(msg->data)) == 0)
{
//密码输入正确
printf("login success.\n");
strcpy(msg->data, "OK");
}
else
{
//密码输入错误
printf("login password is wrony.\n");
strcpy(msg->data, "password is wrong.");
}
}
//不匹配
else if ( msg->flag != atoi(resultp[ncloumn + 1]))
{
printf("login usr permissions not match.\n");
strcpy(msg->data, "usr permission not match.");
}
}
//发送数据给客户端
if(send(sockfd, msg, sizeof(MSG), 0) < 0 )
{
perror("do_login fail to send");
return -1;
}
return 0;
}
/** 服务器:用户查询处理
* 1.在单词库中寻找需要查询的单词
* 2.反馈消息给客户端
*/
int do_query(int sockfd, MSG *msg ,sqlite3 *db)
{
if (msg == NULL)
{
puts("do_query: msg parm NULL ");
return -1;
}
char word[SIZE];
int found = -1;
char date[SIZE] = {};
char sql[SIZE] = {};
int is_undefine;
char *errmsg = NULL;
//获取本地时间
get_date(date);
//拿出msg结构体中,要查询的单词
strcpy(word,msg->data);
found = do_searchworld(msg);
// 表示找到了单词,那么此时应该将 用户名,时间,单词,插入到历史记录表中去。
if(found == 1)
{
// 0: 已有定义
is_undefine = 0;
}
else if (found == 0)
{
// 1: 未定义
is_undefine = 1;
}
//将查询信息发送给客户端:释义|The meaning of the word could not be found|错误信息
if(send(sockfd,msg, sizeof(MSG), 0) < 0)
{
perror("do_query fail to send.");
return -1;
}
// 一个单词查询完毕,服务端打印提示信息
printf("Word:%s query finished.\n", word);
//将查询信息插入数据库表格record(名字,日期时间,单词,是否未定义)
sprintf(sql,"insert into record values('%s','%s','%s','%d');",msg->name, date, word, is_undefine);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("do_query %s\n", errmsg);
return -1;
}
return 0;
}
/** 服务器:历史记录查询处理
* 1.在单词库中寻找需要查询的单词
* 2.反馈消息给客户端
*/
int do_history(int sockfd, MSG *msg, sqlite3 *db)
{
if (msg == NULL)
{
puts("do_history: msg parm NULL");
return -1;
}
char sql[SIZE] = {};
char *errmsg = NULL;
HIS_MSG his_msg;
//填充参数
his_msg.fd = sockfd;
his_msg.msg = msg;
//判断用户权限
if(msg->flag == USR)
{
//普通用户
sprintf(sql, "select * from record where name='%s' and is_undefine=%d;", msg->name, 0);
}
if (msg->flag == ROOT)
{
//ROOT用户
sprintf(sql, "select * from record;");
}
/* 查询历史记录,执行回调函数 */
if (sqlite3_exec(db, sql, history_callback, (void*)&his_msg, &errmsg) != SQLITE_OK)
{
printf("do_history %s\n", errmsg);
return -1;
}
else
{
printf("Query history record successful.\n");
/* 历史记录查询完了,给客户端发送查询完毕标志“\0” */
strcpy(msg->data, "\0");
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("do_history fail to send");
return -1;
}
return 1;
}
return 0;
}
// 得到查询结果,并且需要将历史记录发送给客户端
int history_callback(void *his_msg, int f_num, char **f_value, char **f_name)
{
HIS_MSG *h_msg = (HIS_MSG *)his_msg;
if (h_msg->msg->flag == USR)
{
sprintf(h_msg->msg->data, "%s %s", f_value[1], f_value[2]);
printf("%s\n", h_msg->msg->data);
}
if (h_msg->msg->flag == ROOT)
{
sprintf(h_msg->msg->data, "%-20s%s %-15s%s", f_value[0], f_value[1], f_value[2], f_value[3]);
}
if (send(h_msg->fd, h_msg->msg, sizeof(MSG), 0) < 0)
{
perror("history_callback fail to send");
return -1;
}
return 0;
}
int do_close(int sockfd, MSG * arg)
{
(void*)arg;
close(sockfd);
puts("Main exit");
}
/**
*1. 建立socket(listenfd)
*2. 初始化服务器地址(servaddr)
*3. socket与服务器地址绑定
*4. 监听socket(listenfd)
*/
int Init_Server(int *socketfd, struct sockaddr_in *servaddr, const char* addr, const char *port)
{
// 创建流式套接字
if ((*socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("fail to socket");
return -1;
}
/* 允许绑定地址快速重用 */
int b_reuse = 1;
setsockopt(*socketfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
bzero(servaddr, sizeof(struct sockaddr_in));
servaddr->sin_family = AF_INET;
servaddr->sin_port = htons(atoi(port));
servaddr->sin_addr.s_addr = inet_addr(addr);
//servaddr->sin_addr.s_addr = htonl(INADDR_ANY);// 让服务器可以绑定在任意的IP上
//绑定
if (bind(*socketfd, (struct sockaddr*)servaddr, sizeof(struct sockaddr_in)) < 0)
{
perror("connect to fail.");
return -1;
}
//监听
if(listen(*socketfd, 5) < 0)
{
perror("fail to listen");
return -1;
}
return 0;
}
//获取本地时间
const char *get_date(char * date)
{
time_t t;
struct tm tp;
time(&t);
//进行时间格式转换
tp = *localtime(&t);
sprintf(date, "%04d-%02d-%02d %02d:%02d:%02d", \
tp.tm_year + 1900, tp.tm_mon + 1, tp.tm_mday, tp.tm_hour, tp.tm_min, tp.tm_sec);
return date;
}
//查询词典数据库文件dict.txt中的单词释义
int do_searchworld(MSG *msg)
{
FILE *fp_r;
int len;
char str[512] = {};
int result;
char *p;
//打开文件,读取文件,进行比对
if((fp_r = fopen("./dict.txt","r")) == NULL)
{
perror("do_searchworld fail to fopen");
strcpy(msg->data,"Failed to open dict.txt" );
//发送错误消息
return -1;
}
//打印需要查询的单词
len = strlen(msg->data);
printf("%s , len = %d\n", msg->data, len);
//读文件,来查询单词
while( fgets(str, 512, fp_r ) != NULL )
{
result = strncmp(str, msg->data, len);
if(result < 0)
{
continue;
}
if(result > 0 || str[len] != ' ')
{
strcpy(msg->data, "The meaning of the word could not be found.\n");
break;
}
// 表示找到了,查询的单词
p = str + len;
while(*p == ' ') //去掉单词释义前的空格
{
p++;
}
// 找到了注释,跳跃过所有的空格
strcpy(msg->data, p);
// 注释拷贝完毕之后,应该关闭文件
fclose(fp_r);
return 1;
}
fclose(fp_r);
return 0;
}