网页html版——在线查字典的一个web服务器
HTML(HyperText Markup Language)
HTML是一种用于创建网页的标准标记语言。可以用dreamwave这个工具来写
使用文本编辑器(如Notepad++、Sublime Text、Visual Studio Code等)创建一个新的文件,并将其保存为 .html 文件。
1.格式
<!DOCTYPE html>
<html >
<head>
<meta charset="utf-8">
<title>中文测试。。。。</title>
</head>
<body>
这里是测试body测试内容。。。
</body>
</html>
文档类型声明 (<!DOCTYPE html>):告诉浏览器这是一个HTML5文档。
根元素 (<html>):包含整个HTML文档的所有内容。
文档头部 (<head>):包含了文档的元数据,比如字符集设置、视口设置以及文档的标题。
字符集 (<meta charset="UTF-8">):设置文档的字符编码为UTF-8。
标题 (<title>):显示在浏览器标签页上的文本
主体 (<body>):包含网页的所有可见内容。
2.标签
在body内
<h1></h1>双标签 标题 ,加粗,换行 1-6 ---》小
<p></p> 双标签 段落,有换行功效
<hr> 单标签 左到右分割符
<!-- -->注释
3.元素的属性
给元素提供更多的属性,大部分的元素属性
语法:<标签 属性1=参数1 属性2=参数2>
1)align left,right,center
2) bgcolor ,body的属性设置网页的背景色
<body bgcolor="0xff1234" bgcolor="0xff1234">
4.文本元素属性
b 元素 <b>内容</b> 加粗
br 换行<br> 如果是p标签中间有间隔
i元素, 字体倾斜<i></i>
del元素 删除文字<del></del>
strong 强调一段文字,效果类似 b标签
u元素,下划线<u></u>
small元素, 超小字体<small></small>
sub 下标<sub></sub>
sup 上标<sup></sup>
<br>h<sub>2</sub>0
<br>100m<sup>2</sup>
ruby,拼音,<ruby>二姐 <rt>(er) (jie)<rt></ruby>,可能部分浏览器不支持。
mark 元素 <mark> </mark> 加黄色背景
5.超链接
5种形式
1,链接外部网站
2,链接本地文件
3,图片链接
4,电子邮件链接打开电子邮件
5,下载文件链接
<a href="http://www.baidu.com">baidu</a>
<br><a href="1.html">1111</a>
<br><a href="1.html"><img src="abc.jpg"></a>
<br><a href="mailto:123@13.com">contract me</a>
<br><a href="abc.jpg">下载</a>
上面的方法在打开新网页时,老的网页会关闭
target 属性
_self :当前位置打开 默认值
_blank 新窗口中打开
<a href="http://www.baidu.com" target="_blank">baidu</a>
字符串处理函数strtok、strstr
strtok
用于将一个字符串分割成多个子字符串(标记)。strtok 函数通常用于解析文本数据,例如从逗号分隔的字符串中提取各个字段。
char *strtok(char *str, const char *delim);
str:指向要分割的字符串的指针。
delim:包含一个或多个分隔符的字符串。
返回值 如果成功分割出一个子字符串,strtok 返回指向该子字符串的指针。
如果没有更多的子字符串可分割,strtok 返回 NULL。
重复调用:strtok 函数需要重复调用来获取所有的子字符串。
首次调用时,str 应该指向原始字符串;
后续调用时,str 应该为 NULL,delim 应该保持不变。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Name,Age,Occupation\nJohn,30,Developer\nJane,28,Designer";
const char *delimiters = "\n,";
char *line = strtok(str, "\n"); // 按行分割
while (line != NULL) {
printf("Line: %s\n", line);
char *field = strtok(line, ","); // 按字段分割
while (field != NULL) {
printf("Field: %s\n", field);
field = strtok(NULL, ",");
}
line = strtok(NULL, "\n"); // 下一行
}
return 0;
}
strstr
用于在一个字符串中查找另一个字符串首次出现的位置。
如果找到了子字符串,strstr 将返回指向该子字符串的第一个字符的指针;
如果没有找到,则返回 NULL。
char *strstr(const char *haystack, const char *needle);
haystack:要搜索的字符串的指针。
needle:指向要查找的子字符串的指针。
#include <stdio.h>
#include <string.h>
int main() {
const char *haystack = "Hello, world! Welcome to the programming world.";
const char *needle = "world";
// 查找子字符串
char *found = strstr(haystack, needle);
if (found != NULL) {
printf("Found substring '%s' at position %ld.\n", needle, found - haystack);
} else {
printf("Substring '%s' not found.\n", needle);
}
return 0;
}
access()
用于检查指定文件的访问权限。
它可以用来判断一个文件是否存在,以及当前进程是否有权对该文件执行特定类型的访问。
#include <unistd.h>
int access(const char *pathname, int mode);
pathname:指向文件路径的字符串指针。
mode:指定要检查的访问模式,可以是以下常量之一或它们的按位或组合:
F_OK:文件存在即可。
R_OK:文件可读。
W_OK:文件可写。
X_OK:文件可执行。
返回值
如果检查成功,access() 返回 0。
如果检查失败,access() 返回 -1,并且设置 errno 为相应的错误码。
if(access("dict.db",F_OK))
{
LoadDictToDB();
}
memset()
用于将一块内存区域中的每个字节都设置为同一个值。这个函数通常用于初始化内存块,清零缓冲区
#include <string.h>
void *memset(void *ptr, int value, size_t num);
// 使用 memset 将缓冲区初始化为 0
memset(buffer, 0, sizeof(buffer));
ptr:指向要填充的内存区域的指针。
value:要设置到每个字节的值。注意,这个值会被转换为无符号字符类型 unsigned char。
num:要填充的字节数。
#ifndef __HEAD_H__
#define __HEAD_H__
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sqlite3.h>
/* HTTP请求报文解析信息 */
typedef struct httprequest{
char *pmethod; //方法
char *purl; //请求资源路径
char *pcontent; //正文
}httprequest_t;
/* 查询单词结果类型 */
typedef struct callbackarg
{
char mean[4096]; //单词含义
int flag; //是否被找到标志
}arg_t;
#endif
#include"head.h"
int LoadDictToDB(void)
{
sqlite3 *pdb = NULL;
char cmdbuf[4096] = {0};
int ret = 0;
char *perrmsg = NULL;
FILE *fp = NULL;
char tmpbuff[4096] = {0};
char *pret = NULL;
char *ptmpword =NULL;
char *ptmpmean = NULL;
long len = 0;
long curlen = 0;
ret = sqlite3_open("dict.db",&pdb);
if(ret != SQLITE_OK)
{
fprintf(stderr,"fail to sqlite3_open:%s\n",sqlite3_errmsg(pdb));
return -1;
}
sprintf(cmdbuf,"create table if not exists dict (number integer primary key asc,Word varchar(64),Mean varchar(4096));");
ret = sqlite3_exec(pdb,cmdbuf,NULL,NULL,&perrmsg);
if(ret!= SQLITE_OK)
{
fprintf(stderr,"fail to sqlite3_exec%s\n",perrmsg);
sqlite3_free(perrmsg);
sqlite3_close(pdb);
return -1;
}
fp = fopen("dict.txt","r");
if(NULL == fp)
{
perror("fail to open");
return -1;
}
fseek(fp,0,SEEK_END);
len = ftell(fp);
rewind(fp);
while(1)
{
pret = fgets(tmpbuff,sizeof(tmpbuff),fp);
if(NULL == pret)
{
break;
}
curlen = ftell(fp);
printf("已加载%.2lf%%\r",(double)curlen/(double)len*100);
fflush(stdout);
ptmpword = strtok(tmpbuff," ");
ptmpmean = strtok(NULL,"\r");
sprintf(cmdbuf,"insert into dict values(NULL,\"%s\",\"%s\");",ptmpword,ptmpmean);
ret = sqlite3_exec(pdb,cmdbuf,NULL,NULL,&perrmsg);
if(ret!=SQLITE_OK)
{
fprintf(stderr,"fail to sqlite3_exec:%s\n",perrmsg);
sqlite3_free(perrmsg);
sqlite3_close(pdb);
return -1;
}
}
sqlite3_close(pdb);
return 0;
}
int callback(void *arg,int col,char **pcontent,char **ptitle)
{
arg_t *pmeanmsg = arg;
pmeanmsg->flag = 1;
strcpy(pmeanmsg->mean,pcontent[0]);
return 0;
}
int FindWordMean(char *pword,arg_t *pmeanmsg)
{
sqlite3 *pdb = NULL;
char cmdbuf[4096] = {0};
int ret = 0;
char *perrmsg = NULL;
ret = sqlite3_open("dict.db",&pdb);
if(ret!= SQLITE_OK)
{
fprintf(stderr,"fail to sqlite3_open:%s\n",sqlite3_errmsg(pdb));
return -1;
}
memset(pmeanmsg,0,sizeof(*pmeanmsg));
sprintf(cmdbuf,"select Mean from dict where Word =\"%s\";",pword);
ret = sqlite3_exec(pdb,cmdbuf,callback,pmeanmsg,&perrmsg);
if(ret!=SQLITE_OK)
{
fprintf(stderr,"fail to sqlite3_exec:%s\n",perrmsg);
sqlite3_free(perrmsg);
sqlite3_close(pdb);
return -1;
}
sqlite3_close(pdb);
return 0;
}
int CreateListenSocket(char *pip,int port)
{
int ret = 0;
int sockfd = 0;
struct sockaddr_in seraddr;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("fail to socket");
return -1;
}
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(port);
seraddr.sin_addr.s_addr = inet_addr(pip);
ret = bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));
if(-1 == ret)
{
perror("fail to listen");
return -1;
}
ret = listen(sockfd,10);
if(-1 == ret)
{
perror("fail to listen");
return -1;
}
return sockfd;
}
int RecvHttpRequest(int confd,char *precvbuffer,int maxlen)
{
ssize_t nsize = 0;
memset(precvbuffer,0,maxlen);
nsize = recv(confd,precvbuffer,maxlen,0);
if(-1 == nsize)
{
perror("fail to recv");
return -1;
}
printf("==============RECV============\n");
printf("%s\n",precvbuffer);
printf("==============================\n");
return nsize;
}
int SpliteHttpRequest(char *precvbuffer,httprequest_t *ptmprequest)
{
char *pmethod = NULL;
char *purl = NULL;
ptmprequest->pcontent = strstr(precvbuffer,"\r\n\r\n")+4;
ptmprequest->pmethod = strtok(precvbuffer," ");
ptmprequest->purl = strtok(NULL," ");
return 0;
}
int SendHttpResponseSuccessHeader(int confd)
{
char tmpbuff[4096] = {0};
ssize_t nsize = 0;
sprintf(tmpbuff,"HTTP/1.1 200 OK\r\n");
sprintf(tmpbuff,"%sconnection:Keep-alive\r\n\r\n",tmpbuff);
nsize = send(confd,tmpbuff,strlen(tmpbuff),0);
if(nsize <= 0);
{
perror("fail to sned");
return -1;
}
return 0;
}
int SendHttpResponseFailureHeader(int confd)
{
char tmpbuff[4096] = {0};
ssize_t nsize = 0;
sprintf(tmpbuff,"HTTP/1.1 404 NotFound\r\n");
sprintf(tmpbuff,"%sconnection:close\r\n\r\n",tmpbuff);
nsize = send(confd,tmpbuff,strlen(tmpbuff),0);
if(nsize <= 0);
{
perror("fail to send");
return -1;
}
return 0;
}
int SendHttpResponseHtml(int confd,char *presourcepath)
{
int fd = 0;
char tmpbuff[4096] = {0};
ssize_t nsize = 0;
ssize_t nret = 0;
fd = open(presourcepath,O_RDONLY);
if(-1 == fd)
{
perror("fail to open");
return -1;
}
while(1)
{
nsize = read(fd,tmpbuff,sizeof(tmpbuff));
if(nsize<=0)
{
break;
}
nret = send(confd,tmpbuff,nsize,0);
if(-1 == nret)
{
perror("fail to send");
break;
}
}
close(fd);
return 0;
}
int SpliteSearchWordValue(char *pcontent,char *pword,int maxlen)
{
strtok(pcontent,"=");
strncpy(pword,strtok(NULL,"="),maxlen-1);
return 0;
}
int GenerateWordMeanHtml(char *htmlpath,char *pmean)
{
FILE *fp = NULL;
fp = fopen(htmlpath,"w");
if(NULL == fp)
{
perror("fail to fopen");
return -1;
}
fprintf(fp,"<html>\n");
fprintf(fp,"<head>\n");
fprintf(fp,"</head>\n");
fprintf(fp,"<body>\n");
fprintf(fp,"%s\n",pmean);
fprintf(fp,"</body>\n");
fprintf(fp,"</html>\n");
fclose(fp);
return 0;
}
int SendHttpResponse(int confd,httprequest_t tmprequest)
{
char resourcepath[512] = {0};
char word[512] = {0};
arg_t meanmsg;
if(!strcmp(tmprequest.pmethod,"GET"))
{
//如果 tmprequest.purl 是 / 则strcmp 的返回值是0 取反 变成1 进入if语句中
if(!strcmp(tmprequest.purl,"/"))
{
sprintf(resourcepath,"www/index.html");
}
else if(!strcmp(tmprequest.purl,"/favion.ico")) // 这个是请求网站图标 我们没有所以直接返回0 退出
{
return 0;
}
else
{
sprintf(resourcepath,"www%s",tmprequest.purl);
}
if(0 == access(resourcepath,F_OK))
{
SendHttpResponseSuccessHeader(confd);
SendHttpResponseHtml(confd,resourcepath);
}
else
{
SendHttpResponseFailureHeader(confd);
return 0;
}
}
else if(!strcmp(tmprequest.pmethod,"POST"))
{
if(!strcmp(tmprequest.purl,"/searchword"))
{
SpliteSearchWordValue(tmprequest.pcontent,word,512);
FindWordMean(word,&meanmsg);
printf("pmeanmsg.flag=%d\n",meanmsg.flag);
if(meanmsg.flag)
{
GenerateWordMeanHtml("www/mean.html",meanmsg.mean);
}
else
{
GenerateWordMeanHtml("www/mean.html","can not find this word");
}
SendHttpResponseSuccessHeader(confd);
SendHttpResponseHtml(confd,"www/mean.html");
}
}
return 0;
}
int main(int argc, const char *argv[])
{
int confd = 0;
int sockfd = 0;
char recvbuffer[4096] = {0};
httprequest_t request; // 请求报文解析出的各类信息 结构体
char word[256] = {0};
if(access("dict.db",F_OK))
{
LoadDictToDB();
}
sockfd = CreateListenSocket("192.168.95.131",8080);//创建服务器
while(1)
{
//当服务器监听某个端口 并收到客户端的连接请求时,accept函数就会被调用
//accept成功被调用时,会返回一个新的socket套接字,这个套接字用于与特定的客户端通信
confd = accept(sockfd,NULL,NULL);
if(-1 == confd)
{
perror("fail to accept");
return -1;
}
RecvHttpRequest(confd,recvbuffer,4096);//接收http 请求报文
SpliteHttpRequest(recvbuffer,&request);//对请求报文进行拆分解析 并把解析出的信息放入request结构体中
SendHttpResponse(confd,request);//回复响应报文
close(confd);//释放tcp连接
}
return 0;
}