网页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;
}