1.功能演示
2.功能说明
大方向一共四个功能:
注册
登录
查询单词
查询历史记录
3.流程图
3.功能实现
1.搭建程序框架
2.实现注册和登录功能
3.查单词
4.查历史记
4. 代码实现
服务器代码:
#include "myhead.h"
int main(int argc, char const *argv[])
{
if (argc != 3){
printf("Please enter in format");
exit(-1);
}
int socketfd;
int acceptfd;
pid_t pid;
sqlite3* db;
if (SQLITE_OK != sqlite3_open(DATABASE, &db)){
printf("error:%s\n", sqlite3_errmsg(db));
exit(-1);
}
//创建套接字
if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
ERROR("socket error");
}
//填充网络信息结构体
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t serveraddr_len = sizeof(serveraddr);
//将网络信息结构体与套接字进行绑定
if (-1 == bind(socketfd, (struct sockaddr*)&serveraddr, serveraddr_len)){
ERROR("Server_connect error");
}
//将套接字设置为被动监听状态
if (-1 == listen(socketfd, 5)){
ERROR("listen error");
}
if (SIG_ERR == signal(SIGCHLD, handler)){
ERROR("Server_signal error");
}
while (1){
if (-1 == (acceptfd = accept(socketfd, NULL, NULL))){
ERROR("accept error");
}
if ((pid = fork()) == -1){
ERROR("Server_fork error");
}else if(pid == 0){
Server_Process(acceptfd, db);
}else {
close(acceptfd);
}
}
return 0;
}
服务器代码函数:
#include "myhead.h"
void handler(int sig)
{
wait(NULL);
}
void Server_Process(int acceptfd,sqlite3 *db)
{
msg_t msg;
while (recv(acceptfd, &msg, sizeof(msg_t), 0) > 0){
printf("code = %c\n", msg.operator_code);
printf("type = %s\n", msg.data);
switch(msg.operator_code) {
case 'r':
Server_Register(acceptfd, &msg, db);
break;
case 'l':
Server_Login(acceptfd, &msg, db);
break;
case 'h':
Server_History(acceptfd, &msg, db);
break;
case 'c':
Server_Refer(acceptfd, &msg, db);
break;
}
}
}
void Server_Register(int acceptfd,msg_t* msg, sqlite3* db)
{
char buff[K] = {0};
sprintf(buff, "insert into usr values('%s', '%s')", msg->name, msg->data);
if (SQLITE_OK != sqlite3_exec(db, buff, NULL, NULL, NULL)){
sprintf(msg->data, "user %s already exist!!!", msg->name);
}else {
strcpy(msg->data, "ok");
}
if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
ERROR("Server_Register send error");
}
return;
}
void Server_Login(int acceptfd,msg_t* msg, sqlite3* db)
{
char buff[K] = {0};
int now;
int column;
char** result;
sprintf(buff, "select * from usr where name='%s' and char='%s'", msg->name, msg->data);
if (SQLITE_OK != sqlite3_get_table(db, buff, &result, &now, &column, NULL)){
ERROR("Server_Login sqlite3_get_table error");
}
if (now == 1){
strcpy(msg->data, "ok");
}else {
strcpy(msg->data, "login failure");
}
if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
ERROR("Server_Login send error");
}
return;
}
int Server_Refer_searchword(int acceptfd,msg_t* msg)
{
FILE* fp;
char temp[F];
int len;
char *p;
//保存单词长度
len = strlen(msg->data);
if (NULL == (fp = fopen("dict.txt", "r"))){
strcpy(msg->data, "Server_Refer_searchword open error");
if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
ERROR("Server_Refer_searchword send error");
}
}
while (fgets(temp, sizeof(temp), fp) != NULL){
if (!strncmp(msg->data, temp, len) && temp[len] == ' '){
p = temp + len;
while (*p == ' '){
p++;
}
strcpy(msg->data, p);
fclose(fp);
return 1;
}
}
strcpy(msg->data, "not found");
fclose(fp);
return 0;
}
void Server_Refer_getdata(char* data)
{
time_t t;
struct tm* tm;
if (-1 ==(t = time(NULL))){
ERROR("Server_Refer_getdata get time error");
}
if (NULL == (tm = localtime(&t))){
ERROR("Server_Refer_getdata localtime error");
}
sprintf(data,"%d-%02d-%02d %02d:%02d:%02d\n", tm->tm_year+1900,\
tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
return;
}
void Server_Refer(int acceptfd,msg_t* msg, sqlite3* db)
{
char buff[K] = {0};//用来插入历史记录
char data[F] = {0};//用来记录时间
char word[F] = {0};//用来提前保存一下单词
int flag;
strcpy(word, msg->data);
flag = Server_Refer_searchword(acceptfd, msg);
if (flag){
Server_Refer_getdata(data);
sprintf(buff, "insert into record values('%s', '%s', '%s')", msg->name, data, word);
if (SQLITE_OK != sqlite3_exec(db, buff, NULL, NULL, NULL)){
ERROR("Server_Refer sqlite3_exec error");
}
}
printf("%s\n", msg->data);
if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
ERROR("Server_Refer send error");
}
}
int history_callback(void* arg, int f_num, char** f_value, char** f_name)
{
msg_t msg;
int acceptfd = *(int *)arg;
sprintf(msg.data, "%s:%s", f_value[1],f_value[2]);
if (-1 == send(acceptfd, &msg, sizeof(msg_t), 0)){
ERROR("history_callback send error");
}
return 0;
}
void Server_History(int acceptfd,msg_t* msg, sqlite3* db)
{
char buff[K];
sprintf(buff, "select * from record where name ='%s'", msg->name);
if (SQLITE_OK != sqlite3_exec(db, buff, history_callback, (void*)&acceptfd, NULL)){
printf("Server_History errmsg >>%s\n", sqlite3_errmsg(db));
exit(-1);
}
strcpy(msg->data, "over");
if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){
printf("Server_History\n");
}
}
客户端代码:
#include "myhead.h"
int main(int argc, char const *argv[])
{
if (argc != 3){
printf("Please enter in format");
exit(-1);
}
int socketfd;
char choose;//用来做选择的
msg_t msg;
if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
ERROR("client_socket error");
}
struct sockaddr_in cilentaddr;
cilentaddr.sin_family = AF_INET;
cilentaddr.sin_port = htons(atoi(argv[2]));
cilentaddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t cilentaddr_len = sizeof(cilentaddr);
if (-1 == connect(socketfd, (struct sockaddr*)&cilentaddr, cilentaddr_len)){
ERROR("connect error");
}
while (1){
printf("******************************\n");
printf(" r注册 l登录 q退出\n");
printf("*******************************\n");
scanf("%c", &choose);
switch (choose) {
case 'r':
Client_Register(socketfd, &msg);
break;
case 'l':
if (Client_Login(socketfd, &msg)){
goto next;
}
break;
case 'q':
close(socketfd);
exit(-1);
break;
}
}
next:
while (1){
printf("***************************\n");
printf(" c查阅 h历史 q退出\n");
printf("***************************\n");
scanf("%c", &choose);
switch (choose) {
case 'c':
Client_Refer(socketfd, &msg);
break;
case 'h':
Client_History(socketfd, &msg);
break;
case 'q':
close(socketfd);
exit(-1);
break;
}
}
return 0;
}
客户端代码函数:
#include "myhead.h"
void Client_Register(int socketfd, msg_t* msg)
{
msg->operator_code = 'r';
printf("input your name>>");
scanf("%s", msg->name);
printf("input your password>>");
scanf("%s", msg->data);
if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_Register send error");
}
if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_Register recv error");
}
printf("log-on message>>%s\n", msg->data);
return;
}
int Client_Login(int socketfd, msg_t* msg)
{
msg->operator_code = 'l';
printf("input your name>>");
scanf("%s", msg->name);
printf("input your password>>");
scanf("%s", msg->data);
if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_Login send error");
}
if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_Login recv error");
}
if (!strncmp(msg->data, "ok", 3)){
printf("login:ok\n");
return 1;
}else {
printf("login:%s\n", msg->data);
return 0;
}
}
void Client_Refer(int socketfd, msg_t* msg)
{
msg->operator_code = 'c';
while(1) {
printf("Please enter the word you are looking for(is # is end)>>");
scanf("%s", msg->data);
if (!strncmp(msg->data, "#", 2)){
break;
}
if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_History send error");
}
if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_History recv error");
}
printf("The word meaning>>%s\n", msg->data);
}
}
void Client_History(int socketfd, msg_t* msg)
{
msg->operator_code = 'h';
if (-1 == send(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_History send error");
}
while (1){
if (-1 == recv(socketfd, msg, sizeof(msg_t), 0)){
ERROR("Client_History recv error");
}
if (!strcmp(msg->data, "over")){
break;
}
printf("history>>%s\n", msg->data);
}
return;
}
头文件:
#ifndef __MYHEAD_H__
#define __MYHEAD_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#define DATABASE "my.db" //定义数据库名
#define ERROR(msg) do{\
printf("%s %s %d\n", __func__, __FILE__, __LINE__);\
perror(msg);\
exit(-1);}while(0);
#define N 16 //姓名长度
#define M 256 //数据长度以及错误信息
#define K 512 //用来插入数据库命令
#define F 128 //用来记录时间,以及提前保存一下单词
typedef struct MSG{
char operator_code;//操作码
char name[N];//姓名
char data[M];//数据
}msg_t;
//服务器的函数声明
void handler(int sig);
void Server_Process(int acceptfd,sqlite3 *db);
void Server_Register(int acceptfd,msg_t* msg, sqlite3* db);
void Server_Login(int acceptfd,msg_t* msg, sqlite3* db);
void Server_History(int acceptfd,msg_t* msg, sqlite3* db);
void Server_Refer(int acceptfd,msg_t* msg, sqlite3* db);
//客户端的函数声明
void Client_Register(int socketfd, msg_t* msg);
int Client_Login(int socketfd, msg_t* msg);
void Client_Refer(int socketfd, msg_t* msg);
void Client_History(int socketfd, msg_t* msg);
#endif