一、设计思路流程图
二、网页代码
①一级页面(denglu.html)
创建一个.html使用记事本打开,可自己命名(我的为denglu.html)
使用html基础知识完成网页的创建!!!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>单词含义查询</title>
</head>
<body background = "1.jpg">//自己添加的照片,不添加照片也行
<br><br> <br> <br> <br><br><br> <br> <br> <br><br>
<h3 align="center"><font color="000000">登录账号</font><h3>
<form action="./word.html" align="center" method="POST">//post的使用方法,点击登陆后跳转当前目录下的word.html
<font color="000000">登陆账号: </font><input type="text" placeholder="请输入账号" name="username" required><br>
<font color="000000">账号密码: </font><input type="password" placeholder="请输入密码" name="password" required><br><br>
<input type="reset" name = "reset">  <input type="submit" value="登录">
</form>
</body>
</html>
②二级页面(world.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>单词含义查询</title>
</head>
<body background = "2.jpg">
<br><br> <br> <br> <br><br><br> <br> <br> <br><br>
<h3 align="center"><font color="000000">输入要查询的单词</font><h3>
<form action="./sign.html" align="center"" method="POST">
<font color="000000">单词: </font><input type="text" placeholder="请输入要查询的单词" name="word" required><br><br><br>
<input type="reset" name = "reset">  <input type="submit" value="查询"><br><br><br>
<button><a href="/.html">返回主页面</button></a><br>
</form>
</body>
</html>
③三级页面(sign.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>单词含义查询</title>
</head>
<body background = "4.jpg">
<br><br> <br> <br> <br><br><br> <br> <br> <br><br>
<h3 align="center"><font color="FFCC66">该单词的含义</font><h3>
<form action="./word.html" align="center" method="POST">
<font color="FFCC66">该单词的含义: <br><br><br><br>
<input type="submit" value="重新查找单词"><br><br><br><br>
<button><a href="/.html">返回主页面</button></a><br>
</form>
</body>
</html>
三、单词和含义插入数据库
①查看文件ditx(1)获取单词和含义
②插入文件ditx(1)获取单词和含义在数据库中
只插入一次,所以这个代码只使用一次!!!!一次插入结束后,完成后面单词查找的功能
#include "head.h"
#include <sqlite3.h>
int main(int argc, char const *argv[])
{
long len = 0;
char cmp[4096] = {0};
char *name = NULL;
char *mean = NULL;
FILE *fp = fopen("./dict(1).txt","r");//打开我们的单词文件,使用读的方式
if(NULL == fp)
{
perror("fail to open");
return -1;
}
sqlite3 *q = NULL;
int ret = sqlite3_open("./info.db",&q);//打开当前目录下info.db数据库
if(ret != SQLITE_OK)
{
fprintf(stderr,"fail sqlite3_open:%s\n",sqlite3_errmsg(q));
sqlite3_close(q);
return -1;
}
sprintf(cmp,"create table if not exists dict(name char(20),mean char(1024));");
//创建表,一列为name(单词),一列为mean(意义)。if no exists不存的话就创建,存在的话直接插入
ret = sqlite3_exec(q,cmp,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
fprintf(stderr,"fail sqlite3_create:%s\n",sqlite3_errmsg(q));
sqlite3_close(q);
return -1;
}
printf("==============================1\n");
while(1)//循环插入单词和含义
{
char ch[4096] = {0};
char *p = fgets(ch, sizeof(ch), fp); //fgets接一行
if(NULL == p)
{
break;
}
name = strtok(ch," ");//截取前面单词
mean = strtok(NULL,"\r");//截取后面的单词含义
sprintf(cmp, "insert into dict values( \"%s\", \"%s\");",name,mean);
//在名为dict的表中插入name和mean;
ret = sqlite3_exec(q, cmp, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
fprintf(stderr, "sqlite3_exec insert: %s\n", sqlite3_errmsg(q));
sqlite3_close(q);
return -1;
}
}
fclose(fp);//关闭文件描述符
sqlite3_close(q);//关闭数据库
return 0;
}
③检查数据库dict表中单词列数是否一致
四、设计代码dict.c
(sqlite3.c和sqlite3.h自行查找放入当前目录下)
①将html和图片放入当前目录下
②完成dixt.c设计
#include "head.h"
#include "sqlite3.h"
int init_tcp_ser(char *ip,unsigned short port)//TCP协议
{
struct sockaddr_in ser;
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("fail sockfd");
return -1 ;
}
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret = bind(sockfd,(struct sockaddr *)&ser, sizeof(ser));
if (-1 == ret)
{
perror("fail bind");
exit(1);
}
ret = listen(sockfd, 100);
return sockfd;
}
int recv_http_request(int connfd, char *req_data, int maxlen)//接收对方发来的HTTP报文
{
memset(req_data, 0, maxlen);
ssize_t size = recv(connfd, req_data, maxlen, 0);
if (size < 0)
{
perror("fail recv");
return -1;
}
return 0;
}
int prase_http_request(char *req_data, HTTP_REQ_s *http_data)//解析报文
{
memset(http_data, 0, sizeof(HTTP_REQ_s));
char *ptmp= strtok(req_data, " ");
if (NULL == ptmp)
{
return -1;
}
strcpy(http_data->method, ptmp);
ptmp = strtok(NULL, " ");
if (NULL == ptmp)
{
return -1;
}
strcpy(http_data->url, ptmp);
ptmp = strtok(NULL, "\0");
if (NULL == ptmp)
{
return -1;
}
ptmp = strstr(ptmp, "\r\n\r\n");
if (NULL == ptmp)
{
return -1;
}
ptmp += 4;
strcpy(http_data->content, ptmp);
return 0;
}
int send_http_head(int connfd)//发送报文的头部
{
char *http_head = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html;charset=UTF-8\r\n"
"Connection: close\r\n"
"Server: WEB SERVER\r\n\r\n";
ssize_t size = send(connfd, http_head, strlen(http_head), 0);
if (size < 0)
{
perror("fail send");
return -1;
}
return 0;
}
int send_file(int connfd, char *filename)//发送文件
{
int fd = open(filename, O_RDONLY);
if (-1 == fd)
{
fprintf(stderr, "fail open: %s\n", filename);
return -1;
}
while (1)
{
char buff[1024] = {0};
ssize_t size = read(fd, buff, sizeof(buff));
if (size <= 0)
{
break;
}
send(connfd, buff, size, 0);
}
close(fd);
}
char center[1024] = {0};//全局变量
char *ss = NULL;//全局变量
int flag = -1;//全局变量
int send_http_response(int connfd, HTTP_REQ_s *http_data)
{
char filename[1024] = {0};
send_http_head(connfd);
if (!strcmp(http_data->method, "GET"))
{
if (!strcmp(http_data->url, "/"))
{
sprintf(filename, "./denglu.html");
}
else if (strstr(http_data->url, ".jpg") || strstr(http_data->url, ".png"))
{
sprintf(filename, ".%s", http_data->url);//输出自己选用的照片
}
else if (!strcmp(http_data->url, "/favicon.ico"))
{
return 0;
}
else if (!strcmp(http_data->url, "/denglu.html"))
{
sprintf(filename, "./denglu.html");//跳转登录页面
}
}
else if (!strcmp(http_data->method, "POST"))
{
if (!strcmp(http_data->url, "/word.html"))//如果是POST方法,后面是/word.html
{
sprintf(filename, "./word.html");//输出该页面(直接跳转)
}
if (!strcmp(http_data->url, "/sign.html"))
{
sqlite3 *qdb = NULL;
int ret = 0;
int i = 0;
char *perrmsg = NULL;
char cmdbuff[1024] = {0};
ret = sqlite3_open("./info.db",&qdb);//打开数据库
if(ret != SQLITE_OK)
{
fprintf(stderr,"sqlite3_open fail :%s\n",sqlite3_errmsg(qdb));
return -1;
}
printf("数据库文件打开成功!\n");
ss = strstr(http_data->content,"=")+1;//将该报文截取,截取需要的单词内容
printf("===============ss=%s===========\n",ss);
sprintf(cmdbuff,"select name,mean from dict where name = \"%s\";",ss);//从数据库中选择和name一样的单词,从而找到他的含义
ret = sqlite3_exec(qdb,cmdbuff,goodsback,NULL,&perrmsg);
if( ret != SQLITE_OK)
{
fprintf(stderr,"sqlite3_exec failed:%s\n",perrmsg);
sqlite3_free(perrmsg);
sqlite3_close(qdb);
return -1;
}
if(0 == flag)//定义的全局变量flag,如果变化说明找到该单词
{
char head[1024] ={"<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>单词含义查询</title></head><body background = \"4.jpg\"><br><br> <br> <br> <br><br><br> <br> <br> <br><br><h3 align=\"center\"><font color=\"#6F00D2\">该单词的含义</font><h3><form action=\"./word.html\" align=\"center\" method=\"POST\"><font color=\"#6F00D2\">该单词的含义:"};//该html的前面部分
strcat(head,ss);//将找到的单词拼接在中间
strcat(head,center);//将单词含义拼接在单词后面
char end[1024] = {"<br><br><br><br> <input type=\"submit\" value=\"重新查找单词\"><br><br><br><br><button><a href=\"denglu.html\">返回主页面</button></a><br></form></body></html>"};
strcat(head,end);//将后面的html完成。这样可以不用像一级页面跳转二级页面那样完成跳转页面,直接将页面输入了。
send(connfd,head,strlen(head),0);//发送该内容
flag = -1;//将flag重置
}
if(-1 == flag)//如果没有找到,中间改变写上未找到该单词
{
char head[1024] ={"<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>单词含义查询</title></head><body background = \"4.jpg\"><br><br> <br> <br> <br><br><br> <br> <br> <br><br><h3 align=\"center\"><font color=\"#6F00D2\">该单词的含义</font><h3><form action=\"./word.html\" align=\"center\" method=\"POST\"><font color=\"#6F00D2\">没有该单词!"};
char end[1024] = {"<br><br><br><br> <input type=\"submit\" value=\"重新查找单词\"><br><br><br><br><button><a href=\"denglu.html\">返回主页面</button></a><br></form></body></html>"};
strcat(head,end);
send(connfd,head,strlen(head),0);
}
sqlite3_close(qdb);
}
}
send_file(connfd, filename);
return 0;
}
int goodsback(void *arg,int n ,char **pcontent,char **ptitle)//当数据库打开,条件符合时调用goodsback
{
printf("(char *)arg = %s\n",(char *)arg);
printf("pcontent[0] = %s\n",pcontent[0]);//因为select了name和mean,两个。所以pcontent[0]为name,pcontent[1]为mean;
printf("pcontent[1] = %s\n",pcontent[1]);
printf("n = %d\n",n);
printf("ss=%s\n",ss);
if(!strcmp(pcontent[0],ss))//如果名字和搜索的ss符合的话
{
sprintf(center,"%s",pcontent[1]);//将改单词含义拼接在中间Center
flag = 0;
}
flag = 0;
return 0;
}
int add_epoll_fd(int epfd,int fd,uint32_t events)
{
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
if(-1 == ret)
{
perror("fail epoll_ctl add");
return -1;
}
}
int delet_epoll_fd(int epfd,int fd)
{
int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
if(-1 == ret)
{
perror("epll_ctl del");
return -1;
}
return 0 ;
}
int main(int argc, char const *argv[])
{
char req_data[1024] = {0};
HTTP_REQ_s http_data;
int sockfd = init_tcp_ser("192.168.1.192",8080);//绑定自己的IP地址,端口号
struct sockaddr_in cli;
socklen_t clilen = sizeof(cli);
int epfd = epoll_create(1024);//完成多个客户端连接,可以忽略,直接发送和接收也行,epoll加不加入都行
if(-1 == epfd)
{
perror("fail epoll_create");
return -1;
}
add_epoll_fd(epfd,sockfd,EPOLLIN);
struct epoll_event evs[1024];
while(1)
{
int ret = epoll_wait(epfd, evs, 1024, -1);
if (-1 == ret)
{
perror("fail to epoll_wait");
continue;
}
for (int i = 0; i < ret; i++)
{
if (sockfd == evs[i].data.fd )
{
int fd_acc = accept(sockfd, (struct sockaddr *)&cli, &clilen);
if (-1 == fd_acc)
{
perror("fail to accept");
continue;
}
add_epoll_fd(epfd, fd_acc, EPOLLIN);
char usertmp[4096] = {0};
sprintf(usertmp,"IP:%s PORT:%d已连接\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));
}
else
{
char tmpbuff[4096 * 2] = {0};
memset(tmpbuff, 0, sizeof(tmpbuff));
int nsize = recv_http_request(evs[i].data.fd,tmpbuff,1024);
if (nsize < 0)
{
perror("fail to recv");
delet_epoll_fd(epfd, evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
prase_http_request(tmpbuff,&http_data);//解析
int cont = send_http_response(evs[i].data.fd, &http_data);//发送报文
if (-1 == cont)
{
delet_epoll_fd(epfd, evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
close(evs[i].data.fd);
continue;
}
}
}
close(sockfd);
return 0;
}
也可以分成几个.c来写,一个.c文件看起来比较多,其实需要写的,比较难的只有中间部分的数据库查找
③makefile
OBJ:=main
OBJS+=dict.c
OBJS+=sqlite3.o$(OBJ):$(OBJS)
gcc $^ -o $@ -lpthread -ldl
%.o:%.c
gcc -c $^ -o $@
.PHONY:
clean:
rm $(OBJ)
④运行结果展示
发布的视频中(7月25日)
2023年7月25日
五、头文件
#ifndef __HEAD_H__//防止头文件被重复定义
#define __HEAD_H__//防止头文件被重复定义#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <poll.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/epoll.h>typedef struct http
{
char method[32]; //请求方法
char url[512]; //请求的内容URL
char content[1024]; //请求报文中的正文
}HTTP_REQ_s;
extern int goodsback(void *arg,int n ,char **pcontent,char **ptitle);
#endif//防止头文件被重复定义