功能:基于Linux操作系统,网络编程和数据库实现在线词典
(如果小编有哪个地方需要改进的,欢迎在评论区探讨哦~)
服务器端流程图(如下图所示),根据流程图编写对应的函数会相对来说简单很多,会帮助你理清思路:
客户端流程图(如下图所示):
.h文件如下:
#ifndef __DICT_H__
#define __DICT_H__
#include <stdio.h>
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <time.h>
typedef struct{
int type;
char name[32];
char data[500];
}MSG;
void do_register(int sockfd,MSG *msg);
int do_login(int sockfd,MSG *msg);
void do_query(int sockfd,MSG *msg);
void do_history(int sockfd, MSG *msg);
void server_register(int acceptfd,MSG *msg,sqlite3 *db);
void server_login(int acceptfd,MSG *msg,sqlite3 *db);
int server_search(int acceptfd,MSG *msg);
void server_query(int acceptfd,MSG *msg,sqlite3 *db);
void handler(int sig);
int history_callback(void *arg, int f_num, char **f_value, char **f_name);
void server_history(int acceptfd,MSG *msg,sqlite3 *db);
#endif
函数接口:
#include "dict.h"
//注册
void do_register(int sockfd, MSG *msg)
{
msg->type = 'R';
printf("input name:");
scanf("%s", msg->name);
printf("input password:");
scanf("%s", msg->data);
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("recv error");
return;
}
printf("%s\n", msg->data);
}
//登录
int do_login(int sockfd, MSG *msg)
{
msg->type = 'L';
printf("input name:");
scanf("%s", msg->name);
printf("input password:");
scanf("%s", msg->data);
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return -1;
}
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("recv error");
return -1;
}
if (strncmp(msg->data, "ok", 2) == 0)
{
printf("login success\n");
return 1;
}
printf("%s\n", msg->data);
return 0;
}
//查询
void do_query(int sockfd, MSG *msg)
{
msg->type = 'Q';
while (1)
{
printf("input word(# to quit) :");
scanf("%s", msg->data);
if (strncmp(msg->data, "#", 1) == 0)
{
break;
}
else
{
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("recv error");
return;
}
}
printf("%s\n",msg->data);
}
}
//历史记录
void do_history(int sockfd, MSG *msg)
{
msg->type = 'H';
if (send(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
while (1)
{
if (recv(sockfd, msg, sizeof(MSG), 0) < 0)
{
perror("recv error");
return;
}
if (strncmp(msg->data, "over", 4) == 0)
{
break;
}
printf("%s\n", msg->data);
}
}
//回收进程资源
void handler(int sig)
{
wait(NULL);
}
//服务器注册
void server_register(int acceptfd, MSG *msg, sqlite3 *db)
{
char *errmsg = NULL;
char sql[512];
sprintf(sql, "insert into usr values('%s','%s')", msg->name, msg->data);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_exec error %s\n", errmsg);
strcpy(msg->data, "用户已存在");
}
else
{
strcpy(msg->data, "register ok");
}
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
}
//服务器登录
void server_login(int acceptfd, MSG *msg, sqlite3 *db)
{
char *errmsg = NULL;
char sql[512];
int h, l;
char **result;
sprintf(sql, "select * from usr where name ='%s' and pwd ='%s' ", msg->name, msg->data);
if (sqlite3_get_table(db, sql, &result, &h, &l, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_get_table error %s\n", errmsg);
}
if (h == 0)
{
strcpy(msg->data, "用户名或密码错误,请重新登录");
}
else
{
strcpy(msg->data, "ok");
}
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
}
//根据传过来的数据在文件里进行查找
int server_search(int acceptfd, MSG *msg)
{
char buf[500];
char *p = NULL;
char word[256];
int s, len;
len = strlen(msg->data);
strcpy(word, msg->data);
FILE *fp = fopen("dict.txt", "r");
if (fp == NULL)
{
perror("fopen error");
strcpy(msg->data, "can't open file");
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return -1;
}
}
while (fgets(buf, 500, fp) != NULL)
{
if (strncmp(buf, word, len) == 0 && buf[len] == ' ')
{
p = buf + len;
while (*p == ' ')
p++;
strcpy(msg->data, p);
printf("%s\n",msg->data);
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return -1;
}
return 1;
}
}
return 0;
}
//服务器查询操作
void server_query(int acceptfd, MSG *msg, sqlite3 *db)
{
char *errmsg = NULL;
char sql[512];
char ltime[256];
int flag;
char word[256];
strcpy(word, msg->data);
flag = server_search(acceptfd, msg);
if (flag == 0)
{
strcpy(msg->data, "the word isn't exit\n");
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
}
if (flag == 1)
{
time_t seconds;
struct tm *NowTime;
time(&seconds);
NowTime = localtime(&seconds);
sprintf(ltime, "%d-%d-%d %d:%d:%d", 1900 + NowTime->tm_year, 1 + NowTime->tm_mon, NowTime->tm_mday, NowTime->tm_hour, NowTime->tm_min, NowTime->tm_sec);
sprintf(sql, "insert into record values('%s','%s','%s')", msg->name, ltime, word);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_exec error %s\n", errmsg);
}
}
}
//调用callback函数
int history_callback(void *arg, int f_num, char **f_value, char **f_name)
{
int acceptfd = *(int *)arg;
MSG msg;
sprintf(msg.data, "%s: %s" , f_value[1], f_value[2]);
if (send(acceptfd, &msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return -1;
}
return 0;
}
//查看对应用户的搜索记录
void server_history(int acceptfd, MSG *msg, sqlite3 *db)
{
char *errmsg = NULL;
char sql[256] = {0};
sprintf(sql, "select * from record where name = '%s'", msg->name);
if (sqlite3_exec(db, sql, history_callback, (void *)&acceptfd, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_exec error %s\n", errmsg);
}
strcpy(msg->data, "over");
if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
{
perror("send error");
return;
}
}
server(循环等待接受并处理客户端的请求 注册、登录、查询、退出):
#include"dict.h"
int main(int argc, char const *argv[])
{
int sockfd,acceptfd;
sqlite3 *db;
char *errmsg = NULL;
if(sqlite3_open("./dict.db",&db)!=0){
fprintf(stderr,"sqlite3_open error %s\n",sqlite3_errmsg(db));
return -1;
}
if (sqlite3_exec(db, "create table usr(name char primary key, pwd char);", NULL, NULL, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_exec error %s\n", errmsg);
}
if (sqlite3_exec(db, "create table record(name char,time char,word char);", NULL, NULL, &errmsg) != 0)
{
fprintf(stderr, "seqlite3_exec error %s\n", errmsg);
}
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
return -1;
}
struct sockaddr_in sockaddr,caddr;
sockaddr.sin_family=AF_INET;
sockaddr.sin_port=htons(atoi(argv[1]));
sockaddr.sin_addr.s_addr=inet_addr("0.0.0.0");
socklen_t len=sizeof(caddr);
if(bind(sockfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr))<0){
perror("bind error");
return -1;
}
if(listen(sockfd,5)<0){
perror("listen error");
return -1;
}
signal(SIGCHLD,handler);
while(1){
acceptfd=accept(sockfd,(struct sockaddr *)&caddr,&len);
if(acceptfd<0){
perror("accept error");
return -1;
}
printf("port: %d ip:%s \n",ntohs(caddr.sin_port),inet_ntoa(caddr.sin_addr));
pid_t pid;
pid=fork();
MSG msg;
if(pid<0){
perror("fork error");
return -1;
}
else if(pid==0){
close(sockfd);
while(1){
if(recv(acceptfd,&msg,sizeof(msg),0)<0){
perror("recv error");
return -1;
}
switch(msg.type){
case'R':server_register(acceptfd,&msg,db);break;
case'L':server_login(acceptfd,&msg,db);break;
case'Q':server_query(acceptfd,&msg,db);break;
case'H':server_history(acceptfd,&msg,db);break;
}
}
}close(acceptfd);
}
close(sockfd);
return 0;
}
client (获取用户数据并发送请求 注册、登录、查询、退出):
#include"dict.h"
int main(int argc, char const *argv[])
{
int sockfd;
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
return -1;
}
struct sockaddr_in sockaddr;
sockaddr.sin_family=AF_INET;
sockaddr.sin_port=htons(atoi(argv[1]));
sockaddr.sin_addr.s_addr=inet_addr(argv[2]);
if(connect(sockfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr))<0){
perror("connect error");
return -1;
}
MSG msg;
int n;
while(1){
printf("***********************************\n");
printf("* 1: register 2: login 3: quit *\n");
printf("***********************************\n");
printf("please chose:");
scanf("%d",&n);
switch(n){
case 1:do_register(sockfd,&msg);break;
case 2:if(do_login(sockfd,&msg)==1){
goto next;
};break;
case 3:close(sockfd);exit(0);break;
}
}
next:
while(1){
printf("**********************************************\n");
printf("* 1: query_word 2: history_record 3: quit *\n");
printf("**********************************************\n");
printf("please chose:");
scanf("%d",&n);
switch(n){
case 1:do_query(sockfd,&msg);break;
case 2:do_history(sockfd,&msg);break;
case 3:close(sockfd);exit(0);break;
}
}
return 0;
}