相信大家对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),全代码分享!的更多相关文章

  1. Socket网络编程--简单Web服务器(1)

    这一次的Socket系列准备讲Web服务器.就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd.这个服务器才500多行的代码 ...

  2. Socket网络编程--简单Web服务器(6)

    本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...

  3. 伯克利SocketAPI(一) socket的C语言接口/最简单的服务器和对应的客户端C语言实现

    1. 头文件 2. API函数 3. 最简单的服务器和对应的客户端C语言实现 3.1 server #include <sys/types.h> #include <sys/sock ...

  4. Socket网络编程--简单Web服务器(5)

    这一小节我们将实现服务器对get和post的请求进行对cgi程序的调用.对于web服务器以前的章节已经实现了对get和post请求的调用接口,接下来给出对应接口的实现. int WebServer:: ...

  5. C/C++编程笔记:C语言开发球球大作战(源码分享),你想试试吗?

    游戏背景 <球球大作战>是Superpop一款自主研du发的免费手机网络游戏. 以玩家间的实时互动PK产生游戏乐趣为设计宗旨,通过简单的规则将玩家操作直接转化为游戏策略,体验智谋碰撞的战斗 ...

  6. Python网络编程(3)——SocketServer模块与简单并发服务器

    主要类型 该模块有四个比较主要的类,其中常用的是 TCPServer 和 UDPServer. 1. TCPServer 2. UDPServer 3. UnixStreamServer,类似于TCP ...

  7. Socket网络编程--简单Web服务器(2)

    上一小节通过阅读开源的Web服务器--tinyhttpd.大概知道了一次交互的请求信息和应答信息的具体过程.接下来我就自己简单的实现一个Web服务器. 下面这个程序只是实现一个简单的框架出来.这次先实 ...

  8. Socket网络编程--简单Web服务器(3)

    上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...

  9. Socket网络编程--简单Web服务器(4)

    上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式.我们增加一个函数用于判断格式 int WebServer::get_filetype(char *type,char ...

随机推荐

  1. request的各种方法

    protected void doPost(HttpServletRequest request, HttpServletResponse response)        throws Servle ...

  2. 一起来读官方文档-----SpringIOC(03)

    1.4.依存关系 典型的企业应用程序不坑你只包含单个对象或单个bean.即使是最简单的应用程序,也有一些对象可以协同工作,以呈现最终用户视为一致的应用程序.下一部分将说明如何从定义多个独立的Bean定 ...

  3. SpringMVC-08-整合SSM之CRUD

    查询书籍功能 完善Controller:BookController @Controller @RequestMapping("/book") public class BookC ...

  4. Python实现加密的ZIP文件解压(密码已知)

    博主在上篇博文介绍了<Python实现加密的RAR文件解压(密码已知)>后,又尝试了ZIP文件的解压方法,下面开始分享. 当ZIP文件的压缩密码已知时,可以通过调用zipfile库进行解压 ...

  5. 如何把Github上好的项目pull到本地或者fork到本地(码云仓库同理)?

    首先Github账户的注册我就不想再啰嗦了,我想大家都会的. 其次怎么把自己的项目push到自己的Github仓库请参考我的另一篇博客: 如何把自己开发的项目上传到GitHub仓库或者码云仓库? 最后 ...

  6. [LeetCode]1084. 销售分析III(Mysql,having+聚合函数)

    题目 Table: Product +--------------+---------+ | Column Name | Type | +--------------+---------+ | pro ...

  7. Win10系统安装Tensorflow-GPU和VSCode构建Tensorflow开发环境

    [前言] 1. 最近因为上课需要安装Anaconda和Tensorflow-GPU,Anaconda安装很容易,但Tensorflow-GPU版本的安装较为复杂,因为需要考虑版本匹配的一些问题,很容易 ...

  8. Java 里的 for (;;) 与 while (true),哪个更快?

    在 JDK8u 的 jdk 项目下做个很粗略的搜索: mymbp:/Users/me/workspace/jdk8u/jdk/src$ egrep -nr "for \\(\\s?;\\s? ...

  9. 10.Atomic-原子性操作

  10. list、set、map的区别和联系

    结构特点 List和Set是存储单列数据的集合,Map是存储键值对这样的双列数据的集合: List中存储的数据是有顺序的,并且值允许重复:Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许 ...