上一篇博客中介绍了怎样使用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服务器中最终的请求处理泵代码如下:

         static Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  //侦听socket
static void Main(string[] args)
{
_socket.Bind(new IPEndPoint(IPAddress.Any, ));
_socket.Listen();
_socket.BeginAccept(new AsyncCallback(OnAccept), _socket); //开始接收来自浏览器的http请求(其实是socket连接请求)
Console.Read();
}
static void OnAccept(IAsyncResult ar)
{
try
{
Socket socket = ar.AsyncState as Socket;
Socket new_client = socket.EndAccept(ar); //接收到来自浏览器的代理socket
//NO.1 并行处理http请求
socket.BeginAccept(new AsyncCallback(OnAccept), socket); //开始下一次http请求接收 (此行代码放在NO.2处时,就是串行处理http请求,前一次处理过程会阻塞下一次请求处理) byte[] recv_buffer = new byte[ * ];
int real_recv = new_client.Receive(recv_buffer); //接收浏览器的请求数据
string recv_request = Encoding.UTF8.GetString(recv_buffer, , real_recv);
Console.WriteLine(recv_request); //将请求显示到界面 Resolve(recv_request,new_client); //解析、路由、处理 //NO.2 串行处理http请求
}
catch
{ }
}

注意以上代码中的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

C#中使用Socket实现简单Web服务器的更多相关文章

  1. 使用Socket的简单Web服务器

    Socket类在System.Net.Sockets命名空间 常用的操作 Bind:绑定一个本地的终结点 Listen:进入监听状态,并设置等待队列 Accept:等待一个新连接,当连接到达时,返回一 ...

  2. Python Socket实现简单web服务器

    #!/usr/bin/python env # coding:utf-8 import socket ip_port = ('127.0.0.1', 80) back_log = 10 buffer_ ...

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

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

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

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

  5. tomcat解析之简单web服务器(图)

    链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...

  6. Java中常见的5种WEB服务器介绍

    这篇文章主要介绍了Java中常见的5种WEB服务器介绍,它们分别是Tomcat.Resin.JBoss.WebSphere.WebLogic,需要的朋友可以参考下 Web服务器是运行及发布Web应用的 ...

  7. Java 18 新特性:简单Web服务器 jwebserver

    在今年3月下旬的时候,Java版本已经更新到了18.接下来DD计划持续做一个系列,主要更新从Java 9开始的各种更新内容,但我不全部都介绍,主要挑一些有意思的内容,以文章和视频的方式来给大家介绍和学 ...

  8. 运用socket实现简单的服务器客户端交互

    Socket解释: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意 ...

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

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

随机推荐

  1. 杨氏矩阵:查找x是否在矩阵中,第K大数

    参考:http://xudacheng06.blog.163.com/blog/static/4894143320127891610158/ 杨氏矩阵(Young Tableau)是一个很奇妙的数据结 ...

  2. CozyRSS开发记录12-MVVM,绑定RSS源和数据

    CozyRSS开发记录12-MVVM,绑定RSS源和数据 1.引入MvvmLight MVVM最近貌似在前端那块也挺火的.据说,WPF的程序如果不用MVVM,那跟MFC和winform的,也没啥区别. ...

  3. Axure RP = Axure Rapid Prototyping

    不要一味追求高保真,特别是交互后产生动态数据.并且将动态数据交互传递出去,违背了做原型的初衷了. 自己做着玩追求高保真可以,有成就感. 但作为工作的话,效率优先.能简单直观地展示必要的交互效果即可.

  4. (转)论python工厂函数与内建函数

    所谓工厂函数就是指这些内建函数都是类对象, 当你调用它们时,实际上是创建了一个类实例.   工厂函数: int(),long(),float(),complex(),bool() str(),unic ...

  5. WebGL入门教程(二)-webgl绘制三角形

    前面已经介绍过了webgl,WebGL入门教程(一)-初识webgl(http://www.cnblogs.com/bsman/p/6128447.html),也知道了如何绘制一个点,接下来就用web ...

  6. display:inline-block的间隙问题和解决办法

    1.display:inline-block在水平方向的间隙: 代码如下: <style type="text/css"> *{margin:0; padding:0; ...

  7. win下安装jdk7后,修改环境变量无法改为jdk6的问题

    jdk的安装包,现在的策略改变了,不再帮你设置环境变量,而是直接把java.exe,javaw.exe,javaws.exe直接拷贝到了system32下. 删掉这3个,path就生效了!

  8. openfl使用64位的ndk时,编译报错的问题!

    当使用64位的ndk时,如果使用openfl test android运行android测试,应该会出现 arm-linux-androideabi-g++:找不到这个命令的错误. 原因是,haxel ...

  9. POJ No.2386【B007】

    [B007]Lake Counting[难度B]—————————————————————————————————————————— [Description] Due to recent rains ...

  10. 打包如何打包额外文件,比如Sqlite数据库的db文件

    http://aigo.iteye.com/blog/2278224 Project Settings -> packaging -> Packaging选项中,有多个设置项来设置打包时要 ...