`
devgis
  • 浏览: 133936 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

自定义Web服务器

 
阅读更多

一、Socket编程实现一个简单的Web服务器

Socket这个概念是在Unix系统中提出来的。在Unix的时代,为了解决传输层的编程问题,Unix提供了类似于文件操作的网络操作方式——Socket,通过Socket,我们就可以像操作文件一样通过打开、写入、读取、关闭等操作完成网络编程,这样就使得网络编程可以统一到文件操作方面,这样就使我们更容易地编写网络应用程序。需要注意的是,应用层的协议需要网络程序专门处理,Socket不负责应用层协议,仅仅负责传输层的协议。

现在介绍下网络端口号(port)的概念,在同一个网络地址中,为了区分使用相同协议的不同应用程序,为不同的应用程序分配一个数字编号,我们把这个编号就成为网络端口号(就是区分同一个网络地址中不同的进程)。端口号是由一个两个字节的整数,所以取值范围为0~65535,这些端口号又分为三类:

1.第一类的范围是0~1023,称为众所周知的端口,这些端口号由特定的网络程序使用,例如,TCP协议使用80端口来完成Http协议的传输。

2.第二类的范围是1024~49151,称为登记端口,一般情况下不应该在程序中使用。

3.第三类的范围是49152~65535,称为私有端口, 这些端口可以由普通用户程序使用。

在我们用Socket开发网络应用程序中,还有一个就是端点的概念,在网络中,通过IP地址,协议和端口号可以唯一地确定网络上的一个应用程序,其中把IP地址和端口的组合叫做端点(EndPoint)。每个Socket需要绑定到一个端点上与其他端点进行通信。

介绍完基本的一些概念后,下面演示通过Socket编程实现一个简单的Web服务器,此实例中就是简单向浏览器返回一个固定的静态页面,实现代码如下:

  1. usingSystem;
  2. usingSystem.Net;
  3. usingSystem.Net.Sockets;
  4. usingSystem.Text;
  5. namespaceWebServer
  6. {
  7. ///<summary>
  8. ///实现一个简单的Web服务器
  9. ///该服务器向请求的浏览器返回一个静态的HTML页面
  10. ///</summary>
  11. classProgram
  12. {
  13. staticvoidMain(string[]args)
  14. {
  15. //获得本机的Ip地址,即127.0.0.1
  16. IPAddresslocaladdress=IPAddress.Loopback;
  17. //创建可以访问的断点,49155表示端口号,如果这里设置为0,表示使用一个由系统分配的空闲的端口号
  18. IPEndPointendpoint=newIPEndPoint(localaddress,49155);
  19. //创建Socket对象,使用IPv4地址,数据通信类型为数据流,传输控制协议TCP协议.
  20. Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
  21. //将Socket绑定到断点上
  22. socket.Bind(endpoint);
  23. //设置连接队列的长度
  24. socket.Listen(10);
  25. while(true)
  26. {
  27. Console.WriteLine("WaitanconnectRequest...");
  28. //开始监听,这个方法会堵塞线程的执行,直到接受到一个客户端的连接请求
  29. Socketclientsocket=socket.Accept();
  30. //输出客户端的地址
  31. Console.WriteLine("ClientAddressis:{0}",clientsocket.RemoteEndPoint);
  32. //把客户端的请求数据读入保存到一个数组中
  33. byte[]buffer=newbyte[2048];
  34. intreceivelength=clientsocket.Receive(buffer,2048,SocketFlags.None);
  35. stringrequeststring=Encoding.UTF8.GetString(buffer,0,receivelength);
  36. //在服务器端输出请求的消息
  37. Console.WriteLine(requeststring);
  38. //服务器端做出相应内容
  39. //响应的状态行
  40. stringstatusLine="HTTP/1.1200OK\r\n";
  41. byte[]responseStatusLineBytes=Encoding.UTF8.GetBytes(statusLine);
  42. stringresponseBody="<html><head><title>DefaultPage</title></head><body><pstyle='font:bold;font-size:24pt'>Welcomeyou</p></body></html>";
  43. stringresponseHeader=
  44. string.Format(
  45. "Content-Type:text/html;charset=UTf-8\r\nContent-Length:{0}\r\n",responseBody.Length);
  46. byte[]responseHeaderBytes=Encoding.UTF8.GetBytes(responseHeader);
  47. byte[]responseBodyBytes=Encoding.UTF8.GetBytes(responseBody);
  48. //向客户端发送状态行
  49. clientsocket.Send(responseStatusLineBytes);
  50. //向客户端发送回应头信息
  51. clientsocket.Send(responseHeaderBytes);
  52. //发送头部和内容的空行
  53. clientsocket.Send(newbyte[]{13,10});
  54. //想客户端发送主体部分
  55. clientsocket.Send(responseBodyBytes);
  56. //断开连接
  57. clientsocket.Close();
  58. Console.ReadKey();break;
  59. }
  60. //关闭服务器
  61. socket.Close();
  62. }
  63. }
  64. }

运行结果:

首先运行服务端后的界面:

在浏览器中输入http://localhost:49155/则浏览器可以看到如下的所示的结果:

此时在服务器端显示的输出为:

这里只是简单实现了一个web服务器的功能,当然实际的Web服务器通过用户的发来的Http请求中获得请求文件类型,请求文件名以及请求目录等信息,然后Web服务器根据这些请求信息从服务器的物理目录中寻找请求的文件,如果在服务器中找到请求的文件,然后服务器把响应内容发送给客户端。这里只是通过这个简单的Web服务器让大家理解请求/响应模型以及Web服务器的工作原理,一些复杂的Web服务器也是在此基础进行一些其他功能的扩展。

二、基于TcpListener的Web服务器

在.net平台下, 为了简化网络编程,.net对套接字又进行了一次封装,封装后的类是在System.Net.Sockets命名空间下的TcpListener类和TcpClient类,使用TcpListener类用来监听和接收传入的连接请求,在该类的构造函数中只需要传递一组网络端点信息就可以准备好监听参数,而不需要设置使用的网络协议等细节,调用Start方法后,监听工作就开始(间接调用了Socket.Listen方法),AcceptTcpClient方法将阻塞进程,直到一个客户端发来连接请求为止,这个方法返回一个

封装了Socket的TcpClient对象,同时从传入的连接队列中删除该客户端的连接请求。此时通过这个TcpClient对象与客户端进行通信。

下面是基于TcpListener和TcpClient的一个简单的Web服务器的代码:

  1. usingSystem;
  2. usingSystem.Net;
  3. usingSystem.Net.Sockets;
  4. usingSystem.Text;
  5. namespaceTcpWebserver
  6. {
  7. classProgram
  8. {
  9. staticvoidMain(string[]args)
  10. {
  11. //获得本机的Ip地址,即127.0.0.1
  12. IPAddresslocaladdress=IPAddress.Loopback;
  13. //创建可以访问的断点,49155表示端口号,如果这里设置为0,表示使用一个由系统分配的空闲的端口号
  14. IPEndPointendpoint=newIPEndPoint(localaddress,49155);
  15. //创建Tcp监听器
  16. TcpListenertcpListener=newTcpListener(endpoint);
  17. //启动监听
  18. tcpListener.Start();
  19. Console.WriteLine("WaitanconnectRequest...");
  20. while(true)
  21. {
  22. //等待客户连接
  23. TcpClientclient=tcpListener.AcceptTcpClient();
  24. if(client.Connected==true)
  25. {
  26. //输出已经建立连接
  27. Console.WriteLine("Createdconnection");
  28. }
  29. //获得一个网络流对象
  30. //该网络流对象封装了Socket的输入和输出操作
  31. //此时通过对网络流对象进行写入来返回响应消息
  32. //通过对网络流对象进行读取来获得请求消息
  33. NetworkStreamnetstream=client.GetStream();
  34. //把客户端的请求数据读入保存到一个数组中
  35. byte[]buffer=newbyte[2048];
  36. intreceivelength=netstream.Read(buffer,0,2048);
  37. stringrequeststring=Encoding.UTF8.GetString(buffer,0,receivelength);
  38. //在服务器端输出请求的消息
  39. Console.WriteLine(requeststring);
  40. //服务器端做出相应内容
  41. //响应的状态行
  42. stringstatusLine="HTTP/1.1200OK\r\n";
  43. byte[]responseStatusLineBytes=Encoding.UTF8.GetBytes(statusLine);
  44. stringresponseBody="<html><head><title>DefaultPage</title></head><body><pstyle='font:bold;font-size:24pt'>Welcomeyou</p></body></html>";
  45. stringresponseHeader=
  46. string.Format(
  47. "Content-Type:text/html;charset=UTf-8\r\nContent-Length:{0}\r\n",responseBody.Length);
  48. byte[]responseHeaderBytes=Encoding.UTF8.GetBytes(responseHeader);
  49. byte[]responseBodyBytes=Encoding.UTF8.GetBytes(responseBody);
  50. //写入状态行信息
  51. netstream.Write(responseStatusLineBytes,0,responseStatusLineBytes.Length);
  52. //写入回应的头部
  53. netstream.Write(responseHeaderBytes,0,responseHeaderBytes.Length);
  54. //写入回应头部和内容之间的空行
  55. netstream.Write(newbyte[]{13,10},0,2);
  56. //写入回应的内容
  57. netstream.Write(responseBodyBytes,0,responseBodyBytes.Length);
  58. //关闭与客户端的连接
  59. client.Close();
  60. Console.ReadKey();
  61. break;
  62. }
  63. //关闭服务器
  64. tcpListener.Stop();
  65. }
  66. }
  67. }

程序的输出结果和前面的用Socket实现的效果相同,这里就不再贴图了,这里实现的Web服务器都是建立控制台的应用程序来实现的,感兴趣的朋友也可以用Windows窗体进行实现,同时这里也只是简单列出了采用同步的方式进行实现的,同时TcpListener类和TcpClient类同时支持异步操作的方法,下面列出这个两个类中异步操作的方法如下表:

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics