在学习Linux高并发web服务器开发总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
11_服务器开发-第02天(web服务器 - 2)
目录:
一、sourceInsight安装及使用
二、学习目标
三、复习
四、服务器端代码实现
》epoll服务器各部分代码
问题:中文显示乱码?
》代码优化
1)通过文件名获取文件的类型?
2)如果文件不存在,提示404
3)浏览器一直请求,一直转圈?
》程序测试
》scanf和正则表达式
》scandir
》数据转码
一、sourceInsight安装及使用
SourceInsight 这款软件,可以用来编辑代码,在嵌入式Linux开发中,很多人用它来修改代码和查看代码,再将代码同步到linux下,用嵌入式(一般是ARM for GNU toolchain)交叉编译工具链来进行代码编译。是一个面向项目开发的程序编辑器和代码浏览器,可支持C/C++或Java等多种语言,还可以创建自己的符号数据库,方便实用。
》解决的问题:可能你还是不明白用SourceInsight来干嘛,简单举个例子,写过代码的你都知道,你有一个代码工程,有很多个文件,你为了找到一个全局变量或者函数,找老半天没有找到。有了SourceInsight,你就直接双击这个函数或者全局变量,就可以跳到定义的地方。
》下载:
从百度云中下载文件,链接:https://pan.baidu.com/s/1ml75LW0ft4bo4s9T3AiQRA
提取码:oyat
》安装及破解:
双击“sourceinsight4085-setup.exe”进行安装,一路默认即可,最后记得安装完那一步把运行先勾选掉。——>然后把“sourceinsight4.exe”替换掉安装目录(默认安装目录:C:Program Files (x86)Source Insight 4.0)下的“sourceinsight4.exe”——>双击“sourceinsight4.exe”打开——>选择“Import a new licence file”,然后使用“si4.pediy.lic”文件来破解。
》打开其他project目录方法:
方法一:在菜单栏中的project目录下新建新的工程,然后将自己想看的代码放入这个工程中,就可以在source insight中看这个文件(一般新建的时候都是默认在C盘的base文件夹中,要记得修改好)
方法二:将想要看的代码从库中复制出来,然后将它作为新建的工程目录,它就可以会生成si4.prooject目录,就可以打开它直接在软件上看代码了
》界面布局设置:
1.界面一打开方式:
在菜单栏选择 View,之后在下面勾选 *Symbol Window *或者直接 Alt+F8
2.界面二的代码行数显示
View------>Line Numbers,就可以显示代码行数
3.界面二的Overview
View------>Overview
4.剩下的操作按照图片来操作即可,将打钩的框图打钩好就可以;出现的框图可以拖动,按照自己想要的方式放好即可
》界面颜色设置:
按照图片来设置,颜色我是设置为R199 G237 U204
二、学习目标
三、复习
1、html标签
2、http协议
四、服务器端代码实现
》epoll服务器各部分代码:
(1)主体函数:epoll_run

void epoll_run(int port) { // 创建一个epoll树的根节点 int epfd = epoll_create(MAXSIZE); if(epfd == -1) { perror("epoll_create error"); exit(1); } // 添加要监听的节点 // 先添加监听lfd int lfd = init_listen_fd(port, epfd); // 委托内核检测添加到树上的节点 struct epoll_event all[MAXSIZE]; while(1) { int ret = epoll_wait(epfd, all, MAXSIZE, -1); if(ret == -1) { perror("epoll_wait error"); exit(1); } // 遍历发生变化的节点 for(int i=0; i<ret; ++i) { // 只处理读事件, 其他事件默认不处理 struct epoll_event *pev = &all[i]; if(!(pev->events & EPOLLIN)) { // 不是读事件 continue; } if(pev->data.fd == lfd) { // 接受连接请求 do_accept(lfd, epfd); } else { // 读数据 do_read(pev->data.fd, epfd); } } } }
(2)添加要监听的节点的函数:init_listen_fd

int init_listen_fd(int port, int epfd) { // 创建监听的套接字 int lfd = socket(AF_INET, SOCK_STREAM, 0); if(lfd == -1) { perror("socket error"); exit(1); } // lfd绑定本地IP和port struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_port = htons(port); serv.sin_addr.s_addr = htonl(INADDR_ANY); // 端口复用 int flag = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv)); if(ret == -1) { perror("bind error"); exit(1); } // 设置监听 ret = listen(lfd, 64); if(ret == -1) { perror("listen error"); exit(1); } // lfd添加到epoll树上 struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = lfd; ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev); if(ret == -1) { perror("epoll_ctl add lfd error"); exit(1); } return lfd; }
(3)接收连接请求函数:do_accept

// 接受新连接处理 void do_accept(int lfd, int epfd) { struct sockaddr_in client; socklen_t len = sizeof(client); int cfd = accept(lfd, (struct sockaddr*)&client, &len); if(cfd == -1) { perror("accept error"); exit(1); } // 打印客户端信息 char ip[64] = {0}; printf("New Client IP: %s, Port: %d, cfd = %d ", inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)), ntohs(client.sin_port), cfd); // 设置cfd为非阻塞 int flag = fcntl(cfd, F_GETFL); flag |= O_NONBLOCK; fcntl(cfd, F_SETFL, flag); // 得到的新节点挂到epoll树上 struct epoll_event ev; ev.data.fd = cfd; // 边沿非阻塞模式 ev.events = EPOLLIN | EPOLLET; int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev); if(ret == -1) { perror("epoll_ctl add cfd error"); exit(1); } }
(4)读数据函数:do_read

// 读数据 void do_read(int cfd, int epfd) { // 将浏览器发过来的数据, 读到buf中 char line[1024] = {0}; // 读请求行 int len = get_line(cfd, line, sizeof(line)); if(len == 0) { printf("客户端断开了连接... "); // 关闭套接字, cfd从epoll上del disconnect(cfd, epfd); } else { printf("请求行数据: %s", line); printf("============= 请求头 ============ "); // 还有数据没读完 // 继续读 while(len) { char buf[1024] = {0}; len = get_line(cfd, buf, sizeof(buf)); printf("-----: %s", buf); } printf("============= The End ============ "); } // 请求行: get /xxx http/1.1 // 判断是不是get请求 if(strncasecmp("get", line, 3) == 0)//strncasecmp比较前3个字符且不区分大小写 { // 处理http请求 http_request(line, cfd); // 关闭套接字, cfd从epoll上del disconnect(cfd, epfd); } }
(5)解析http请求消息的每一行内容函数:getline

// 解析http请求消息的每一行内容 int get_line(int sock, char *buf, int size) { int i = 0; char c = '