文档章节

Socket实现简单Web服务器

IT周见智
 IT周见智
发布于 2015/06/05 17:17
字数 1897
阅读 35
收藏 1

上一篇博客中介绍了怎样使用socket访问web服务器。关键有两个:

  • 熟悉Socket编程;
  • 熟悉HTTP协议。

上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重点在浏览器端。本篇博客则反过来讲一下怎样使用socket来实现Web服务器,怎样去接收、分析、处理最后回复来自浏览器的HTTP请求。

HTTP协议是浏览器和Web服务器都需要遵守的一种通信规范,如果我们编写一个程序,正确遵守了HTTP协议,那么理论上讲,这个程序可以具备浏览器、甚至Web服务器的功能。

图1

如上图1所示,Web服务器和浏览器之间无论是发送数据还是接收(解析)数据均遵守了HTTP协议。可以很确定地讲,只要我们充分熟悉HTTP协议结构,那么无论浏览器的实现还是Web服务器的实现,均只是“简单的”Socket程序的开发过程,除此之外,无其它神秘高深的东西。而Socket程序开发,稍微知道一点socket的有关知识,均能写得出一个大概demo。

从系统架构来讲,Web架构形式的系统均符合“生产者-消费者”模式(实质上,现实生活中大部分系统均属于该模式)。浏览器端不断产生数据(请求),而Web服务器端不断处理请求,长时间持续如此。

图2

如上图2所示,图中左边部分为Web服务器中的“泵”结构,所谓泵,就是指它能够持续长时间循环运作。图中右边显示“来自浏览器请求”部分即为“生产者”,生产者不断发出请求,由左边(Web服务器)不断进行处理,最后回复给浏览器。注意图2中显示,Web服务器中处理数据在循环体内部,换句话说,前一次HTTP请求处理结束之前,后一次HTTP请求不能开始,也就是每次请求处理均会阻塞循环的执行。这种串行处理数据的方式明显效率不高,为了解决该问题,我们可以在接收到浏览器端的HTTP请求后,并不马上在当前线程中进行处理,而是开辟独立线程来处理请求(在.NET中可以使用异步编程实现)。这样一来,请求处理并不会阻塞当前循环过程,见下图3

图3

如上图3所示,接收到请求后,开辟其它线程来处理,这种并行处理数据的方式不会影响后续请求处理。

如果对Socket编程比较熟悉,以上所说的完全可以轻松实现(完全按照Socket编程去做)。现在难点是,Web服务器端怎样解析来自浏览器的请求数据(一串字符串文本),以及应该以怎样的格式去回复浏览器?答案就是必须充分了解HTTP协议格式。上一篇博客中已经提到过,有关HTTP协议格式请参见http://www.cnblogs.com/riky/archive/2007/04/09/705848.html。我们必须读懂浏览器发送的请求数据,并按照正确格式发送回复。下图4显示浏览器请求数据格式:

图4

图中红色部分即为数据传输方式(post或get)、请求路径(url中不含主机地址部分)以及HTTP协议版本号。下面以“键:值”格式的文本均为浏览器发送给服务器的一系列数据信息(注意这些项可选),如果浏览器以post方式提交数据,那么数据会紧跟在下面(图中没显示)。Web服务器读懂浏览器发送的请求数据,并处理完毕后,必须按照图5的格式将结果回复给浏览器:

图5

如上图5所示,最上面的以“键:值”的格式文本是Web服务器发送给浏览器的一些数据信息(这些项部分可选),紧接着,下面便是需要发送给浏览器的HTML文档(如果返回的是页面)。浏览器必须读懂Web服务器发送的回复数据,然后进行渲染(显示)。

图6

图6显示了浏览器发起的一次HTTP请求,显示展示了Web服务器端处理该请求的过程。我们可以看到,Web服务器在一次Socket连接过程中只处理一个HTTP请求。多次HTTP请求会伴随着Socket不断的连接与断开。

文章最后上传一个使用Socket编写的简单Web服务器,能够实现以下功能:

  • 运行Web服务器后,可以绑定端口,接收来自任何浏览器的HTTP请求;
  • 能够显示一个默认首页,如index.html;
  • 首页提供“登录”功能,按照Post方式传递数据到处理页面“login.zsp”(后缀名可自定义);
  • Web服务器端接收接收浏览器发送的数据,能够解析(解析方式很随意)出post传递的参数,并模拟访问数据库检查登录情况、模拟耗时等待等;
  • Web服务器生成登录成功后的静态页,回复给浏览器。页面显示登录名和当前时间。

整个demo完全就是一个Socket程序,只是增加了“HTTP协议”的环节,服务器端无论是接收(解析)数据还是发送数据,均需要遵守HTTP协议。Web服务器中最终的请求处理泵代码如下:

 1         static Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  //侦听socket
 2         static void Main(string[] args)
 3         {
 4             _socket.Bind(new IPEndPoint(IPAddress.Any, 8081));
 5             _socket.Listen(100);
 6             _socket.BeginAccept(new AsyncCallback(OnAccept), _socket);  //开始接收来自浏览器的http请求(其实是socket连接请求)
 7             Console.Read();
 8         }
 9         static void OnAccept(IAsyncResult ar)
10         {
11             try
12             {
13                 Socket socket = ar.AsyncState as Socket;
14                 Socket new_client = socket.EndAccept(ar);  //接收到来自浏览器的代理socket
15                 //NO.1  并行处理http请求
16                 socket.BeginAccept(new AsyncCallback(OnAccept), socket); //开始下一次http请求接收   (此行代码放在NO.2处时,就是串行处理http请求,前一次处理过程会阻塞下一次请求处理)
17 
18                 byte[] recv_buffer = new byte[1024 * 640];
19                 int real_recv = new_client.Receive(recv_buffer);  //接收浏览器的请求数据
20                 string recv_request = Encoding.UTF8.GetString(recv_buffer, 0, real_recv);
21                 Console.WriteLine(recv_request);  //将请求显示到界面
22 
23                 Resolve(recv_request,new_client);  //解析、路由、处理
24 
25                 //NO.2  串行处理http请求
26             }
27             catch
28             {
29 
30             }
31         }
View Code

注意以上代码中的NO.1和NO.2处,socket.BeginAccept()方法放在NO.1处时,服务器端会并行处理请求,而放在NO.2处时,服务器会串行处理请求。读者可以每种方式都试一下,在串行处理请求时,请求处理过程会阻塞后续请求的处理(比如登录耗时10秒钟,其它人无法访问网站)。

以下是demo效果图:

图7:Web服务器运行后,浏览器访问首页:

图7

图8:浏览器中首页显示(包含登录框):

图8

图9:用户点击“登录”按钮,以Post方式提交数据,Web服务器解析、处理,返回新页面:

图9

文章有点长,部分截图还失真了(部分图以前整理的,没有找到大图,所以就凑合看:))

源码下载:http://files.cnblogs.com/xiaozhi_5638/socket_webServer.rar

© 著作权归作者所有

共有 人打赏支持
IT周见智

IT周见智

粉丝 10
博文 61
码字总数 185891
作品 0
西青
Socket到底是个什么东西

Socket在计算机专业术语上的翻译是“通信节点”。计算机网络中阐述,计算机之间的通信通常指的是应用程序之间的通信。而应用程序之间使用Socket来通信,可以简单的认为,Socket封装了TCP/I...

crazymus
2015/10/14
128
0
web socket 心跳包的实现方案

现在网络环境错综复杂,socket心跳包是获得健康强壮的连接的有效解决方案,今天,我们就在web socket中实现心跳包方案,是的,尽管我们只是做一个简单的聊天室,但我们让他稳定可靠一些一点也...

红薯
2010/06/02
6.3K
5
50.使用Tornado进行网络异步编程

Tornado Tornado是一款非阻塞可扩展的使用Python编写的web服务器和Python Web框架, 可以使用Tornado编写Web程序并不依赖任何web服务器直接提供高效的web服务.所以Tornado不仅仅是一个web框架...

quanpower
2013/08/09
0
0
Socket与线程——建立socket服务器

思路很简单就是在 web 服务器开启一个死循环的 socket 线程监听客户端的数据,实现一对多的监听。思路很简单但实现起来并不容易,线程阻塞,线程间通信,主函数向线程传值,实现有控制的向 ...

什么都不懂的小石
05/06
0
0
Golang Web学习(13)—— 搭建简单的Web服务器

本文为转载,原文:Golang Web学习(13)—— 搭建简单的Web服务器 Golang 1、Web工作方式 我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要 浏览的内容。...

ChainZhang
01/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python3.6 取余运算

python中取余运算逻辑如下: 如果a 与d 是整数,d 非零,那么余数 r 满足这样的关系: a = qd + r , q 为整数,且0 ≤ |r| < |d|。 经过测试可发现,python3.6中取余运算得到的 r 是正整数;...

colinux
18分钟前
1
0
[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
3
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
3
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
1
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部