C/C++编程日记:用C语言实现的简单Web服务器(Linux),全代码分享!
相信大家对Apache都有所听闻,Apache是目前使用最为广泛我Web服务器。大家可以从news.netcraft.com/这个网站得到证实。
这是腾讯的uptime.netcraft.com/up/graph?site=www.qq.com.Apache强大的功能和高效的性能并且开放源代码的这种模式对我很有吸引力,但无赖自己水平有限,无法从Apache庞大的source code里面理清头绪。于是,我就冒出了个自己动手写一个小型的简单的Web服务器的想法,希望对这方面也和我一样感兴趣的朋友有所帮助。
我的实验环境为:
OS:Red Hat Enterprise Linux 5
gcc:4.1.2
libc:2.5
editor:Vim
lang:C
阅读该源代码需要以下预备知识:
C语言基础
Linux编程基础
socket编程基础(Linux)
TCP/IP基本原理
HTTP基本原理
关键字(Key Words):
Linux C, Web HTTP Server, Linux Socket.
-----------------------------------------------------------------------------------
下面是Mutu的第一个版本(0.1 Alpha),实现了WEB 服务器的最基本功能
包括以下源文件:
webserver.c----程序入口
init_socket.h init_socket.c----完成一些WEB服务器的初始化工作
get_time.h get_time.c----获得服务器的时间
http_session.h http_session.c----处理一次HTTP会话
以下是各文件源码:
webserver.c:
/*
* file:webserver.c
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"get_time.h"
#include"init_socket.h"
#include"http_session.h"
intmain(intargc,char*argv[])
{
intlisten_fd;
intconnect_fd;
structsockaddr_inserver_addr;
structsockaddr_inclient_addr;
bzero(&server_addr,sizeof(structsockaddr_in));
bzero(&client_addr,sizeof(structsockaddr_in));
if(init_socket(&listen_fd,&server_addr)==-1)
{
perror("init_socket() error. in webserver.c");
exit(EXIT_FAILURE);
}
socklen_taddrlen=sizeof(structsockaddr_in);
pid_tpid;
while(1)
{
if((connect_fd=accept(listen_fd,(structsockaddr*)&client_addr,&addrlen))==-1)
{
perror("accept() error. in webserver.c");
continue;
}
if((pid=fork())>0)
{
close(connect_fd);
continue;
}
elseif(pid==0)
{
close(listen_fd);
printf("pid %d process http session from %s : %d\n",getpid(),inet_ntoa(client_addr.sin_addr),htons(client_addr.sin_port));
if(http_session(&connect_fd,&client_addr)==-1)
{
perror("http_session() error. in webserver.c");
shutdown(connect_fd,SHUT_RDWR);
printf("pid %d loss connection to %s\n",getpid(),inet_ntoa(client_addr.sin_addr));
exit(EXIT_FAILURE);/* exit from child process, stop this http session */
}
printf("pid %d close connection to %s\n",getpid(),inet_ntoa(client_addr.sin_addr));
shutdown(connect_fd,SHUT_RDWR);
exit(EXIT_SUCCESS);
}
else
{
perror("fork() error. in webserver.c");
exit(EXIT_FAILURE);
}
}
shutdown(listen_fd,SHUT_RDWR);
return0;
}
init_socket.h
/*
* file:init_socket.h
*/
#ifndefINIT_SOCKET_H
#defineINIT_SOCKET_H
#include<netinet/in.h>
#defineBACKLOG 20/* length of listening queue on socket */
#definePORT 8080/* web server listening port */
/* initialize the socket on server, include below
socket();
bind();
listen();
*/
/* listen_fd : the web server listen file decriptor
server_addr: the web server ipv4 address
RETURNS: success on 0, error on -1
*/
intinit_socket(int*listen_fd,structsockaddr_in*server_addr);
#endif
init_socket.c
/*
* file:init_socket.c
*/
#include<stdio.h>
#include<strings.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include"init_socket.h"
intinit_socket(int*listen_fd,structsockaddr_in*server_addr)
{
if((*listen_fd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket() error. in init_socket.c");
return-1;
}
/* set reuse the port on server machine */
intopt=SO_REUSEADDR;
if(setsockopt(*listen_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))==-1)
{
perror("setsockopt() error. in init_socket.c");
return-1;
}
server_addr->sin_family=AF_INET;
server_addr->sin_port=htons(PORT);
server_addr->sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(*listen_fd,(structsockaddr*)server_addr,sizeof(structsockaddr_in))==-1)
{
perror("bind() error. in init_socket.c");
return-1;
}
if(listen(*listen_fd,BACKLOG)==-1)
{
perror("listen() error. in init_socket.c");
return-1;
}
return0;
}
get_time.h
/*
* file: get_time.h
*/
#ifndefGET_TIME_H
#defineGET_TIME_H
#defineTIME_BUFFER_SIZE 40/* buffer size of time_buffer */
char*get_time_str(char*time_buf);
#endif
get_time.c
/*
* file:get_time.c
*/
#include<time.h>
#include<stdio.h>
#include<string.h>
#include"get_time.h"
/* get the time on server,
return: the ascii string of time , NULL on error
argument: time_buf the buffer to store time_string
*/
char*get_time_str(char*time_buf)
{
time_tnow_sec;
structtm*time_now;
if(time(&now_sec)==-1)
{
perror("time() in get_time.c");
returnNULL;
}
if((time_now=gmtime(&now_sec))==NULL)
{
perror("localtime in get_time.c");
returnNULL;
}
char*str_ptr=NULL;
if((str_ptr=asctime(time_now))==NULL)
{
perror("asctime in get_time.c");
returnNULL;
}
strcat(time_buf,str_ptr);
returntime_buf;
}
http_session.c
/*
* file: http_session.h
*/
#ifndefHTTP_SESSION_H
#defineHTTP_SESSION_H
#include<netinet/in.h>
#defineRECV_BUFFER_SIZE 1024/* 1KB of receive buffer */
#defineSEND_BUFFER_SIZE 1050000/* 1.xMB of send buffer */
#defineURI_SIZE 128/* length of uri request from client browse */
#defineTIME_OUT_SEC 10/* select timeout of secend */
#defineTIME_OUT_USEC 0/* select timeout of usecend */
#defineFILE_OK 200
#defineFILE_FORBIDEN 403/* there are no access permission*/
#defineFILE_NOT_FOUND 404/* file not found on server */
#defineUNALLOW_METHOD 405/* un allow http request method*/
#defineFILE_TOO_LARGE 413/* file is too large */
#defineURI_TOO_LONG 414/* */
#defineUNSUPPORT_MIME_TYPE 415
#defineUNSUPPORT_HTTP_VERSION 505
#defineFILE_MAX_SIZE 1048576/* 1MB the max siee of file read from hard disk */
#defineALLOW"Allow:GET"/* the server allow GET request method*/
#defineSERVER"Server:Mutu(0.1 Alpha)/Linux"
/* if the connect protocol is http then this function deal with it */
inthttp_session(int*connect_fd,structsockaddr_in*client_addr);
/* if http protocol return 1, else return 0 */
intis_http_protocol(char*msg_from_client);
/* get the request header's uri */
char*get_uri(char*req_header,char*uri_buf);
/* get the uri status,access return 0, not exist return 1, permission deny return 2, error return -1 */
intget_uri_status(char*uri);
/* get the mime type of the file request in uri from client's browse */
char*get_mime_type(char*uri);
/* read the file which requested by client in uri ,and store in entity_buf.
success return bytes readed,error return -1
*/
intget_file_disk(char*uri,unsignedchar*entity_buf);
/* set http replay header's status:
200:ok
404:file not found
*/
intset_rep_status();
intset_error_information(unsignedchar*send_buf,interrorno);
intreply_normal_information(unsignedchar*send_buf,unsignedchar*file_buf,intfile_size,char*mime_type);
#endif
如何访问该服务器呢?
首先你要知道运行服务器主机的IP,在服务器主机上输入如下命令(需要超级用户权限):
ifconfig
如果你的是以太网(ethernet),那么会看到这样一行
inet addr:xxx.xxx.xxx broadcast:xxx.xxx.xxx.xxx mask:255.xxx.xxx.xxx
xxx代表数字(000-255),第一个inet addr后面的数字便是你的网卡地址。

如果你是在本机进行测试,那IP地址可以直接用127.0.0.1(回环地址,localhost)
取得服务器的IP后,用你喜欢的一款浏览器便可以访问WEB SERVER的内容了。
方法为:在浏览器的地址栏内输入:
http://xxx.xxx.xxx.xxx:8080
回车,即可(xxx.xxx.xxx.xxx无刚取得的服务器IP地址,8080为预设的端口)。
C/C++编程日记:用C语言实现的简单Web服务器(Linux),全代码分享!的更多相关文章
- Socket网络编程--简单Web服务器(1)
这一次的Socket系列准备讲Web服务器.就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd.这个服务器才500多行的代码 ...
- Socket网络编程--简单Web服务器(6)
本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...
- 伯克利SocketAPI(一) socket的C语言接口/最简单的服务器和对应的客户端C语言实现
1. 头文件 2. API函数 3. 最简单的服务器和对应的客户端C语言实现 3.1 server #include <sys/types.h> #include <sys/sock ...
- Socket网络编程--简单Web服务器(5)
这一小节我们将实现服务器对get和post的请求进行对cgi程序的调用.对于web服务器以前的章节已经实现了对get和post请求的调用接口,接下来给出对应接口的实现. int WebServer:: ...
- C/C++编程笔记:C语言开发球球大作战(源码分享),你想试试吗?
游戏背景 <球球大作战>是Superpop一款自主研du发的免费手机网络游戏. 以玩家间的实时互动PK产生游戏乐趣为设计宗旨,通过简单的规则将玩家操作直接转化为游戏策略,体验智谋碰撞的战斗 ...
- Python网络编程(3)——SocketServer模块与简单并发服务器
主要类型 该模块有四个比较主要的类,其中常用的是 TCPServer 和 UDPServer. 1. TCPServer 2. UDPServer 3. UnixStreamServer,类似于TCP ...
- Socket网络编程--简单Web服务器(2)
上一小节通过阅读开源的Web服务器--tinyhttpd.大概知道了一次交互的请求信息和应答信息的具体过程.接下来我就自己简单的实现一个Web服务器. 下面这个程序只是实现一个简单的框架出来.这次先实 ...
- Socket网络编程--简单Web服务器(3)
上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...
- Socket网络编程--简单Web服务器(4)
上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式.我们增加一个函数用于判断格式 int WebServer::get_filetype(char *type,char ...
随机推荐
- idea导入spring源码
1.环境: Intellij idea 2018.2 gradle 4.10.2 spring framework:5.2.0 注意版本不符合可能会导致编译失败. 参考版本: 1.首先下载安装 Int ...
- 三年之久的 etcd3 数据不一致 bug 分析
问题背景 诡异的 K8S 滚动更新异常 笔者某天收到同事反馈,测试环境中 K8S 集群进行滚动更新发布时未生效.通过 kube-apiserver 查看发现,对应的 Deployment 版本已经是最 ...
- FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- C#开发PACS医学影像处理系统(十八):Dicom使用LUT色彩增强和反色
在医生阅片确诊的过程中,当发线疑似病灶时在灰度显示下有时并不清晰,这时候就需要色彩增强效果来使灰度图像变为彩色图像. LUT可以简单的理解为0-255的颜色映射值,例如:彩虹编码,将其打包成LUT格式 ...
- (专题一)03 matlab变量及其操作
给内存单元取名字就可以访问内存单元 变量的命名:变量名区分大小写 标准函数名以及命名方式必须用小写字母 matlab赋值语句有两种表达式 变量的管理 1.预定义变量 ans 是默认赋值变 ...
- hystrix总结之限流
hystrix使用舱壁隔离模式来隔离和限制各个请求,设计了两种隔离方式:信号量和线程池.线程池隔离:对每个command创建一个自己的线程池,执行调用.通过线程池隔离来保证不同调用不会相互干扰和每一个 ...
- redis实现计数器
用redis实现计数器 社交产品业务里有很多统计计数的功能,比如: 用户: 总点赞数,关注数,粉丝数 帖子: 点赞数,评论数,热度 消息: 已读,未读,红点消息数 话题: 阅读数,帖子数,收藏数 统计 ...
- 第二篇 配置wcf
老老实实学WCF 第二篇 配置WCF 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾一下服务端的代码: using System; using System.Col ...
- 小程序开发-iView app的NoticeBar 通告栏修改背景颜色
NoticeBar 通告栏 这是个比较好用的组件,具体使用方法见 http://inmap.talkingdata.com/wx/index_prod.html#/components/notice- ...
- flutter,跟着官网一步一步创建第一个flutter应用
创建第一个flutter 编辑器: vscode 一.创建flutter项目 1.启动vscode 2.按ctrl+shift+p打开命令面板 3.输入flutter 选择Flutter: New P ...