需求:
服务器:
1).提供英英方式的单词查询
2).同时记录用户的查询历史
2).客户机登陆需要密码
客户机:
1).登陆需要密码, 并且提供注册新用户功能, 注意在用户输入密码的时候不能显示密码,就像linux登陆时的那样
2).用户的查询即时给予回复
3).用户可以查询自己的查询历史
4).用户也可以清除自己的历史记录
下面是源码, 由于时间仓促,代码难免比较粗糙,希望谅解!
server.h:
/*************************************************************************
> File Name: server.h
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Wed 15 Jan 2014 09:39:40 AM CST
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFF_SIZE 32
/*The len of sql*/
#define SQL_LEN 512
/*The max len of username*/
#define MAX_USERNAME 256
/*The max len of word and password*/
#define MAX_WORD 128
/*The max len of explaintion to word*/
#define EXP_LEN 1024
/*The flag of status
* R for register
* L for login
* Q for quary
* H for history
* S for client stop
* C for clear history
* */
#define R 1
#define L 2
#define Q 3
#define H 4
#define S 5
#define C 6
/*flags to show user status*/
#define ON_LINE 1
#define OFF_LINE 0
/*network infomation*/
#define SERVER_IP "0.0.0.0"
#define SERVER_PORT 50000
/*text dictionary path*/
#define DIC_PATH "./dict/dic.txt"
/*system and user log path */
#define SYS_LOG "./log/sys.log"
#define USER_LOG "./log/user.log"
/*flags to set term display mode*/
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
/*error handler function*/
#define error_exit(_errmsg_) error(EXIT_FAILURE, errno, _errmsg_)
/*client message struct*/
typedef struct _client_msg_ {
char type;
char name[MAX_USERNAME];
char data[MAX_WORD];
} climsg_st;
/*server message struct*/
typedef struct _server_msg_ {
char type;
char text[EXP_LEN];
} sermsg_st;
/*functions to deal user quary*/
void menu(void);
void login_reg(void);
int show_history(sqlite3 *db, int connfd);
int clear_history(sqlite3 *db, int connfd);
int login(sqlite3 *db, int connfd);
int logout(sqlite3 *db, int connfd);
int regist(sqlite3 *db, int connfd);
int set_disp_mode(int fd,int option);
int quary(sqlite3 *db, int connfd);
/*************************************************************************
> File Name: server.c
> Author: Baniel Gao
> Mail: [email protected]
> Blog: blog.csdn.net/createchance
> Created Time: Wed 15 Jan 2014 11:52:12 AM CST
************************************************************************/
#include "server.h"
/*client and server message struct*/
climsg_st climsg;
sermsg_st sermsg;
int main(void)
{
FILE *dictfp, *sysfp, *userfp;
int sockfd, connfd;
int ret;
int lines = 0, alllines = 19661;
pid_t pid;
struct sockaddr_in server_addr, client_addr;
socklen_t addrlen;
sqlite3 *db;
char explain[EXP_LEN];
char *token;
char sql[SQL_LEN];
char *errmsg;
/*open local database my.db*/
if (0 != sqlite3_open("my.db", &db)) {
printf("error: %s \n", sqlite3_errmsg(db));
return -1;
}
/*open local text dictionary for read*/
if (NULL == (dictfp = fopen(DIC_PATH, "r")))
error_exit("fopen");
/*open system log for append*/
if (NULL == (sysfp = fopen(SYS_LOG, "a")))
error_exit("fopen");
/*open user log for append*/
if (NULL == (userfp = fopen(USER_LOG, "a")))
error_exit("fopen");
/*import the dictionary from local text dictionary*/
while (1) {
system("clear");
printf("Importing data...\n");
if (NULL == fgets(explain, EXP_LEN, dictfp))
break;
printf("\e[32m%.1f%% done!\e[0m \n", (lines++) * 100.0 / alllines);
token = strtok(explain, " ");
sprintf(sql, "insert into dictionary values(\"%s\", \"%s\");", token, explain + 17);
if (0 != (ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg))) {
if (19 != ret) {
printf("error: %s \n", errmsg);
return -1;
}
}
}
printf("Import done! \n");
/*create and open a socket for accept client connect*/
if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
error_exit("socket");
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
addrlen = sizeof(server_addr);
/*server needs to bind the opening socket to local address*/
if (-1 == bind(sockfd, (const struct sockaddr *)&server_addr, addrlen))
error_exit("bind");
/*server listen on the socket*/
if (-1 == listen(sockfd, 10))
error_exit("listen");
/* make server to ingore the child process exit signal(SIGCHLD),
* this can help to avoid zombie process
* */
signal(SIGCHLD, SIG_IGN);
while (1) {
/*when there is a connection has come, accept to deal it*/
if (-1 == (connfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen)))
error_exit("accept");
/*create child process to handler client quary*/
if (-1 == (pid = fork()))
error_exit("fork");
if (pid == 0) {
while (1) {
if (-1 == recv(connfd, &climsg, sizeof(climsg), 0))
error_exit("recv");
if (S == climsg.type) {
logout(db, connfd);
exit(0);
}
else if (L == climsg.type)
login(db, connfd);
else if (R == climsg.type)
regist(db, connfd);
else if (Q == climsg.type)
quary(db, connfd);
else if (H == climsg.type)
show_history(db, connfd);
else if (C == climsg.type)
clear_history(db, connfd);
}
} else {
close(connfd);
}
}
return 0;
}
int regist(sqlite3 *db, int connfd)
{
char regist[SQL_LEN];
char *errmsg;
sprintf(regist, "insert into userstat values('%s', '%s');", climsg.name, climsg.data);
if (SQLITE_OK != sqlite3_exec(db, regist, NULL, NULL, &errmsg)) {
sermsg.type = -1;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
} else {
sermsg.type = 0;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
sprintf(regist, "insert into userstat values('%s', %d);", climsg.name, OFF_LINE);
if (SQLITE_OK != sqlite3_exec(db, regist, NULL, NULL, &errmsg)) {
printf("error: %s \n", errmsg);
}
return 0;
}
int login(sqlite3 *db, int connfd)
{
char login[SQL_LEN];
int nrow, ncol;
char *errmsg;
char **resultp;
sprintf(login, "select * from userstat where username='%s' and status=%d;", climsg.name, OFF_LINE);
if (0 != sqlite3_get_table(db, login, &resultp, &nrow, &ncol, &errmsg))
printf("error: %s \n", errmsg);
if (0 == nrow) {
sermsg.type = -2;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
return -1;
}
sprintf(login, "select * from user where username='%s' and password='%s';", climsg.name, climsg.data);
if (0 != sqlite3_get_table(db, login, &resultp, &nrow, &ncol, &errmsg))
printf("error: %s \n", errmsg);
if (1 != nrow) {
sermsg.type = -1;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
} else {
sermsg.type = 0;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
sprintf(login, "update userstat set status=%d where username='%s';", ON_LINE, climsg.name);
if (SQLITE_OK != sqlite3_exec(db, login, NULL, NULL, &errmsg))
printf("error: %s \n", errmsg);
return 0;
}
int logout(sqlite3 *db, int connfd)
{
char logout[SQL_LEN];
char *errmsg;
sprintf(logout, "update userstat set status=%d where username='%s';", OFF_LINE, climsg.name);
if (SQLITE_OK != sqlite3_exec(db, logout, NULL, NULL, &errmsg))
printf("error: %s \n", errmsg);
return 0;
}
int quary(sqlite3 *db, int connfd)
{
char quary[SQL_LEN];
int nrow, ncol;
char *errmsg;
char **resultp;
sprintf(quary, "select explain from dictionary where word='%s';", climsg.data);
if (0 != sqlite3_get_table(db, quary, &resultp, &nrow, &ncol, &errmsg))
printf("error: %s \n", errmsg);
if (0 == nrow) {
sermsg.type = -1;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
} else {
sermsg.type = 0;
sprintf(sermsg.text, "%s", resultp[1]);
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
sprintf(quary, "insert into history values('%s', '%s');", climsg.name, climsg.data);
if (SQLITE_OK != sqlite3_exec(db, quary, NULL, NULL, &errmsg))
printf("error to write history\n");
return 0;
}
int show_history(sqlite3 *db, int connfd)
{
char show[SQL_LEN];
int i;
int nrow, ncol;
char *errmsg;
char **resultp;
sprintf(show, "select word from history where username='%s';", climsg.name);
if (0 != sqlite3_get_table(db, show, &resultp, &nrow, &ncol, &errmsg))
printf("error: %s \n", errmsg);
if (0 == nrow) {
sermsg.type = -1;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
} else {
for (i = 1; i <= nrow; i++) {
sermsg.type = 0;
sprintf(sermsg.text, "%s", resultp[i]);
printf("%s \n", sermsg.text);
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
sprintf(sermsg.text, "NULL");
printf("%s \n", sermsg.text);
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
return 0;
}
int clear_history(sqlite3 *db, int connfd)
{
char clear[SQL_LEN];
char *errmsg;
sprintf(clear, "delete from history where username='%s';", climsg.name);
if (SQLITE_OK != sqlite3_exec(db, clear, NULL, NULL, &errmsg)) {
printf("error to clear history\n");
sermsg.type = -1;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
} else {
sermsg.type = 0;
if (-1 == send(connfd, &sermsg, sizeof(sermsg), 0))
error_exit("send");
}
return 0;
}
/*************************************************************************
> File Name: client.h
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Wed 15 Jan 2014 09:39:40 AM CST
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFF_SIZE 32
#define SQL_LEN 512
#define MAX_USERNAME 256
#define MAX_WORD 128
#define RET_SIZE 1024
#define R 1
#define L 2
#define Q 3
#define H 4
#define S 5
/*clear history*/
#define C 6
#define SERVER_IP "192.168.140.10"
#define SERVER_PORT 50000
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
#define error_exit(_errmsg_) error(EXIT_FAILURE, errno, _errmsg_)
typedef struct _client_msg_ {
char type;
char name[MAX_USERNAME];
char data[MAX_WORD];
} climsg_st;
typedef struct _server_msg_ {
char type;
char text[RET_SIZE];
} sermsg_st;
void menu(void);
void login_reg(void);
int insert(int sockfd);
int delete(int sockfd);
int show_history(int sockfd);
int clear_history(int sockfd);
int login(int sockfd);
int logout(int sockfd);
int regist(int sockfd);
int set_disp_mode(int fd,int option);
int quary(int sockfd);
/*************************************************************************
> File Name: client.c
> Author: Baniel Gao
> Mail: [email protected]
> Blog: blog.csdn.net/createchance
> Created Time: Tue 14 Jan 2014 01:33:49 PM CST
************************************************************************/
#include "client.h"
climsg_st climsg;
sermsg_st sermsg;
int main(void)
{
char choice[BUFF_SIZE];
int fail_times = 0;
int ret;
int sockfd;
struct sockaddr_in server_addr;
socklen_t addrlen;
if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0)))
error_exit("socket");
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
addrlen = sizeof(server_addr);
if (-1 == connect(sockfd, (const struct sockaddr *)&server_addr, addrlen))
error_exit("connect");
while (1) {
login_reg();
while (1) {
printf("Please input: ");
if (strcmp("\n", fgets(choice, BUFF_SIZE, stdin)) && (2 == strlen(choice)))
break;
}
switch (choice[0]) {
case '1':
if (!strcmp(choice, "1\n"))
while (-1 == (ret = login(sockfd)) || -2 == ret) {
if (-1 == ret) {
printf("\n\e[31musername or password wrong!\e[0m \n");
fail_times++;
}
else
printf("\n\e[31m%s has already login!\e[0m \n", climsg.name);
if (3 <= fail_times) {
printf("\n\e[32mHave no account? Please join us! Do you want to register?(Yes/No):\e[0m ");
if (!strcmp("Yes\n", fgets(choice, BUFF_SIZE, stdin)) || !strcmp("yes\n", choice)) {
while (-1 == regist(sockfd))
printf("\n\e[31musername has been registered!\e[0m \n");
printf("\n\e[32mLet's login now!\e[0m\n");
}
}
}
break;
case '2':
while (-1 == regist(sockfd))
printf("\n\e[31musername has been registered!\e[0m \n");
printf("\n\e[32mLet's login now!\e[0m\n");
while (-1 == (ret = login(sockfd)))
printf("\n\e[31musername or password wrong!\e[0m \n");
break;
case '3':
return 0;
default:
printf("\e[31mUnknown choice!\e[0m \n");
}
if (0 == ret)
break;
}
while (1) {
while (1) {
menu();
printf("Your choice: ");
if (strcmp("\n", fgets(choice, BUFF_SIZE, stdin)), 2 == strlen(choice))
break;
}
switch (choice[0]) {
case '1':
quary(sockfd);
break;
case '2':
show_history(sockfd);
break;
case '3':
clear_history(sockfd);
break;
case '4':
logout(sockfd);
return 0;
default:
printf("\e[31mUnknown choice!\e[0m \n");
}
}
return 0;
}
int set_disp_mode(int fd,int option)
{
int err;
struct termios term;
if(tcgetattr(fd,&term)==-1){
perror("Cannot get the attribution of the terminal");
return 1;
}
if(option)
term.c_lflag|=ECHOFLAGS;
else
term.c_lflag &=~ECHOFLAGS;
err=tcsetattr(fd,TCSAFLUSH,&term);
if(err==-1 && err==EINTR){
perror("Cannot set the attribution of the terminal");
return 1;
}
return 0;
}
int regist(int sockfd)
{
char password_cfm[MAX_WORD];
printf("\e[32mJoin us! Just one minute!\e[0m \n");
while (1) {
printf("username: ");
if (strcmp("\n", fgets(climsg.name, MAX_USERNAME, stdin)))
break;
}
climsg.name[strlen(climsg.name) - 1] = '\0';
set_disp_mode(STDIN_FILENO, 0);
while (1) {
printf("password: ");
if (!strcmp("\n", fgets(climsg.data, MAX_WORD, stdin)))
continue;
printf("\nRetype password: ");
fgets(password_cfm, BUFF_SIZE, stdin);
if (!strcmp(climsg.data, password_cfm))
break;
else
printf("\n\e[31mpassword does not match!\e[0m \n");
}
climsg.data[strlen(climsg.data) - 1] = '\0';
climsg.type = R;
set_disp_mode(STDIN_FILENO, 1);
if (-1 == send(sockfd, &climsg, sizeof(climsg_st), 0)) {
printf("Network failure! \n");
return -1;
}
if (-1 == recv(sockfd, &sermsg, sizeof(sermsg_st), 0))
printf("Network failure! \n");
if (-1 == sermsg.type)
return -1;
printf("\n\e[32mregister done!\e[0m \n");
return 0;
}
int logout(int sockfd)
{
climsg.type = S;
if (-1 == send(sockfd, &climsg, sizeof(climsg_st), 0)) {
printf("Network failure! \n");
return -1;
}
return 0;
}
int login(int sockfd)
{
while (1) {
printf("username: ");
if (strcmp("\n", fgets(climsg.name, MAX_USERNAME, stdin)))
break;
}
climsg.name[strlen(climsg.name) - 1] = '\0';
set_disp_mode(STDIN_FILENO, 0);
while (1) {
printf("password: ");
if (strcmp("\n", fgets(climsg.data, MAX_WORD, stdin)))
break;
}
climsg.data[strlen(climsg.data) - 1] = '\0';
climsg.type = L;
set_disp_mode(STDIN_FILENO, 1);
if (-1 == send(sockfd, &climsg, sizeof(climsg_st), 0)) {
printf("Network failure! \n");
return -1;
}
if (-1 == recv(sockfd, &sermsg, sizeof(sermsg_st), 0))
printf("Network failure! \n");
if (-1 == sermsg.type)
return -1;
else if (-2 == sermsg.type)
return -2;
printf("\n\e[32mWelcome %s!\e[0m \n", climsg.name);
return 0;
}
void login_reg(void)
{
printf("*********************************\n");
printf("* 1.login 2.register 3.quit *\n");
printf("*********************************\n");
}
void menu(void)
{
printf("\e[35m****************************************************\n");
printf("* 1.quary 2.show history 3.clear history 4.quit*\n");
printf("****************************************************\e[0m\n");
}
int show_history(int sockfd)
{
climsg.type = H;
if (-1 == send(sockfd, &climsg, sizeof(climsg), 0)) {
printf("\e[31mNetwork failure!\e[0m \n");
return -1;
}
printf("\e[33m-----------------\n");
while (1) {
if (-1 == recv(sockfd, &sermsg, sizeof(sermsg), 0)) {
printf("\e[31mNetwork failure!\e[0m \n");
return -1;
}
if (-1 == sermsg.type) {
printf("\e[31mNo history found!\e[0m \n");
break;
}
if (!strcmp("NULL", sermsg.text))
break;
printf("|\t%s\t|\n", sermsg.text);
}
printf("\e[33m-----------------\e[0m\n\n");
return 0;
}
int clear_history(int sockfd)
{
climsg.type = C;
if (-1 == send(sockfd, &climsg, sizeof(climsg), 0)) {
printf("\e[31mNetwork failure!\e[0m \n");
return -1;
}
if (-1 == recv(sockfd, &sermsg, sizeof(sermsg), 0)) {
printf("\e[31mNetwork failure!\e[0m \n");
return -1;
}
if (0 == sermsg.type)
printf("\e[32mClear done!\e[0m \n");
else
printf("\e[31mClear failed!\e[0m \n");
return 0;
}
int quary(int sockfd)
{
int i;
while (1) {
printf("Input the word: ");
if (!strcmp("\n", fgets(climsg.data, MAX_WORD, stdin)))
continue;
if (!strcmp("#\n", climsg.data))
return -1;
climsg.data[strlen(climsg.data) - 1] = '\0';
for (i = 0; i < strlen(climsg.data); i++) {
if (climsg.data[i] >= 'A' && climsg.data[i] <= 'Z')
climsg.data[i] = climsg.data[i] + ' ';
else if (climsg.data[i] >= 'a' && climsg.data[i] <= 'z')
continue;
else
break;
}
if (i != strlen(climsg.data)) {
printf("\e[31mInput invalid!\e[0m \n");
continue;
} else
break;
}
climsg.type = Q;
if (-1 == send(sockfd, &climsg, sizeof(climsg), 0)) {
printf("\e[31mNetwork failure!\e[0m \n");
return -1;
}
if (-1 == recv(sockfd, &sermsg, sizeof(sermsg), 0))
printf("\e[31mNetwork failure!\e[0m \n");
if (0 == sermsg.type) {
printf("\e[33m----------------------------------------------------------------\n");
printf("|%s\t| %s\n", climsg.data, sermsg.text);
printf("----------------------------------------------------------------\e[0m\n");
}
else
printf("\e[31mSorry, %s not found!\e[0m \n", climsg.data);
return 0;
}
登陆:
查询:
查询历史记录:
删除历史记录: