自己写的Web服务器

  自己写一个使用Http协议的服务器。在谷歌搜了一下,发现其实.NET Framework里面本身提供了HttpListener类,看别人的博文介绍是它是对Socket的简单封装,也有一些人没有用这个类,还是直接用Socekt写了服务器。说是Socket的扩展性反而比较好。HttpListener毕竟是微软封装好的,安全性应该一般会比用Socket写的要高,如果大牛写的就不同了,像我这等水货,其实还是用HttpListener要好一些。但也是个尝试,也是学习,我尝试用Socket写。虽然说是基于Socket,但实际上用的Socket的连接池。连接池的实现细节在上一篇博文《Socket连接池》有介绍。

  写之前肯定看过别人的博文,看了这篇《C#开发自己的Web服务器》,是翻译老外的博文的。既然是用到Http协议,那肯定要对它有一定的了解,至少懂得看他它的请求头和响应头吧。本人了解的不多,但知道的都能在写这个程序里用得上。

  用谷歌浏览器随便获取了请求和响应的消息结构,列出来简单看一下

1 GET /page/130970/ HTTP/1.1

2 Host: kb.cnblogs.com

3 Connection: keep-alive

4 Cache-Control: max-age=0

5 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

6 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31

7 Accept-Encoding: gzip,deflate,sdch

8 Accept-Language: zh-CN,zh;q=0.8

9 Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

  这个有些部分被我删了,因为篇幅太长了。这个是GET的请求结构,写这个服务器要用到的信息只是第一行请求行而已。由于是GET请求,请求的方法是GET,请求要获取的资源就是“/page/130970”这段。暂时用到的信息就之后这两个而已。

  下面这个则是POST的请求消息结构

 1 POST /ws/SideRightList.asmx/GetList HTTP/1.1

 2 Host: kb.cnblogs.com

 3 Connection: keep-alive

 4 Content-Length: 35

 5 Accept: application/json, text/javascript, */*; q=0.01

 6 Origin: http://kb.cnblogs.com

 7 X-Requested-With: XMLHttpRequest

 8 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31

 9 Content-Type: application/json; charset=UTF-8

10 Referer: http://kb.cnblogs.com/page/130970/

11 Accept-Encoding: gzip,deflate,sdch

12 Accept-Language: zh-CN,zh;q=0.8

13 Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

  同样以POST这个请求方法作为开头,请求的资源就同样的跟在后面,但是请求的参数就跟在请求头的下两行,可是这里的没有带参数,参数的长度可以在请求头的Content-Length中获得,如这里的参数长度就是35。

 1 HTTP/1.1 200 OK

 2 Server: Tengine

 3 Date: Fri, 26 Apr 2013 05:50:11 GMT

 4 Content-Type: text/html; charset=utf-8

 5 Transfer-Encoding: chunked

 6 Connection: keep-alive

 7 Vary: Accept-Encoding

 8 Cache-Control: public, max-age=300

 9 Expires: Fri, 26 Apr 2013 05:54:43 GMT

10 Last-Modified: Fri, 26 Apr 2013 05:49:43 GMT

11 X-AspNet-Version: 4.0.30319

12 X-Powered-By: ASP.NET

13 X-UA-Compatible: IE=edge

14 Content-Encoding: gzip

当服务器接收到浏览器发送的请求处理完之后,要对浏览器进行响应,响应的消息结构如上所示,这里要提供的参数不是很多,首先是响应的状态码,下面则是状态码的类别

  • 1XX  提示信息 - 表示请求已被成功接收,继续处理
  • 2XX  成功 - 表示请求已被成功接收,理解,接受
  • 3XX  重定向 - 要完成请求必须进行更进一步的处理
  • 4XX  客户端错误 -  请求有语法错误或请求无法实现
  • 5XX  服务器端错误 -   服务器未能实现合法的请求

这里用到的状态码有三个 200 OK,404 Not Found,501 Not Implemented。

Server则是服务器的名称,Content-Length则是响应内容的长度,Content-Type是服务器定它们的响应中的内容的类型,也称为MIME,我在以往常见的是这几个

  • text/html
  • text/xml
  • text/plain
  • text/css
  • text/javascript

  HTTP的内容不讲太多了,知道这些足以写这个服务器了。在博客园的知识库了发现一篇文章讲HTTP协议的挺不错的,叫《HTTP 协议详解》。

  吹完Http协议的,说回程序了,既然请求头都是一堆字符串,那现在可以把服务器的职能一份为二,一部分是面向网络的,是Socket那部分,刚好不久前完成了Socket的连接池,在这里可以用得上了;另一部分则是对接收到的请求进行处理,字符串处理为主,充其量就加上文件的IO处理。Socket那部分完成了,只要对连接池配置,使用就行了,剩下是对请求的处理和作出响应。

  这里我也是习惯性的定义了一些实体类,好让信息存取方便些。

  第一个则是服务器的配置信息类,配置过IIS的都知道配置服务器需要IP,端口,虚拟目录,有时候需要控制并发量,起始页。这里就简单地存放了这些信息。

 

1     public class ServerConfigEntity

2     {

3         public string IP { get; set; }//IP地址

4         public int Port { get; set; }//端口号

5         public int MaxConnect { get; set; }//最大并发量

6         public string VirtualPath { get; set; }//虚拟目录

7         public string DefaultPage { get; set; }//起始页

8     }

 

  接着便是请求消息和响应消息了

 1     class RequestHeader

 2     {

 3         public string ActionName { get; set; }

 4         public string URL { get; set; }

 5         public string Host { get; set; }

 6         public string Accept { get; set; }

 7         public string Connection { get; set; }

 8         public string Accept_Language { get; set; }

 9         public string User_Agent { get; set; }

10         public string Accept_Encoding { get; set; }

11 

12         public string Form { get; set; }

13         public int Content_Length { get; set; }

14         public string Referer { get; set; }

15         public string Content_Type { get; set; }

16 

17         public static RequestHeader ConvertRequestHander(string headerStr)

18         {

19             string regActionName = "GET|POST";

20             string regURL = "(?<=GET|POST).*?(?=HTTP/1.1)";

21             string regHost = @"(?<=Host\:\s).*(?=\r\n)";

22             string regAccept = @"(?<=Accept\:\s).*(?=\r\n)";

23             string regConnection = @"(?<=Connection\:\s).*(?=\r\n)";

24             string regAcceptLanguage = @"(?<=Accept-Language\:\s).*(?=\r\n)";

25             string regUserAgent = @"(?<=User-Agent\:\s).*(?=\r\n)";

26             string regAcceptEncoding = @"(?<=Accept-Encoding\:\s).*(?=\r\n)";

27 

28             string regForm = @"(?<=\r\n\r\n).*";

29             string regConntenLength = @"(?<=Connten-Length\:\s).*(?=\r\n)";

30             string regRefere = @"(?<=Refere\:\s).*(?=\r\n)";

31             string regContentType = @"(?<=Content-Type\:\s).*(?=\r\n)";

32 

33             RequestHeader hander = new RequestHeader();

34             hander.ActionName = Regex.Match(headerStr, regActionName).Value;

35             hander.URL = Regex.Match(headerStr, regURL).Value;

36             hander.Host = Regex.Match(headerStr, regHost).Value;

37             hander.Accept = Regex.Match(headerStr, regAccept).Value;

38             hander.Connection = Regex.Match(headerStr, regConnection).Value;

39             hander.Accept_Language = Regex.Match(headerStr, regAcceptLanguage).Value;

40             hander.Accept_Encoding = Regex.Match(headerStr, regAcceptEncoding).Value;

41             hander.User_Agent = Regex.Match(headerStr, regUserAgent).Value;

42             string tempStr = Regex.Match(headerStr, regConntenLength).Value;

43             hander.Content_Length = Convert.ToInt32(tempStr == "" ? "0" : tempStr);

44             hander.Referer = Regex.Match(headerStr, regRefere).Value;

45             hander.Content_Type = Regex.Match(headerStr, regContentType).Value;

46             hander.Form = Regex.Match(headerStr, regForm).Value;

47             return hander;

48         }

49     }

  这里用到了正则去提取请求消息的相应内容,虽然前面介绍时只是提到用到一点点信息,但是以后扩展开来说不能用到其他信息的,于是一概提取了。

 1     class ResponseHeader

 2     {

 3         public string ResponseCode { get; set; }

 4         public string Server { get; set; }

 5         public int Content_Length { get; set; }

 6         public string Connection { get; set; }

 7         public string Content_Type { get; set; }

 8 

 9         public override string ToString()

10         {

11             string result = string.Empty;

12             result += "HTTP/1.1 " + this.ResponseCode + "\r\n";

13             result += "Server: "+this.Server+"\r\n";

14             result += "Content-Length: " + this.Content_Length + "\r\n";

15             result += "Connection: "+this.Connection+"\r\n";

16             result += "Content-Type: " + this.Content_Type + "\r\n\r\n";

17             return result;

18         }

19 

20         public string CreateErrorHtml()

21         {

22             string html = @"<html><head><meta http-equiv=""Content-Type"" content=""text/html;charset=utf-8""></head><body>{0}</body></html>";

23             html = html.Replace("{0}", "<h2>My Web Server</h2><div>{0}</div>");

24             html = string.Format(html, this.ResponseCode);

25             return html;

26         }

27     }

  响应消息这里重写了基类的ToString()方法,能比较方便的根据当前响应的信息转成字符串。还提供了一个生成错误页面内容的方法CreateErrorHtml()。

       接着到服务器的类了,类里面有以下的私有字段

1         private SocketPoolController _pool;//Socket连接池

2         private Dictionary<string, string> _supportExtension;//支持的资源后缀

3         private ServerConfigEntity config;//服务器的配置信息

4         private bool _runFlag;//服务器启动标识

  类的构造函数,构造一个连接池,给支持的附上支持的后缀以及相对应的MIME。

 1         public HttpProtocolServer(ServerConfigEntity config)

 2         {

 3             this.config = config;

 4             _pool = new SocketPoolController(32768, config.MaxConnect);

 5             _supportExtension = new Dictionary<string, string>() 

 6             {

 7                 { "htm", "text/html" },

 8                 { "html", "text/html" },

 9                 { "xml", "text/xml" },

10                 { "txt", "text/plain" },

11                 { "css", "text/css" },

12                 { "png", "image/png" },

13                 { "gif", "image/gif" },

14                 { "jpg", "image/jpg" },

15                 { "jpeg", "image/jpeg" },

16                 { "zip", "application/zip"},

17                 {"js","text/javascript"},

18                 { "dll", "text/plain" }

19                 //{"aspx","text/html"}

20             };

21             _runFlag = false;

22         }

外放的方法有两个,分别是启动服务器RunServer()和停止服务器StopServer()

  启动服务器要把连接池运行起来,同时给注册一个接收事件,以便在接收到浏览器的请求时做出响应。

1         public void RunServer()

2         {

3             if (_runFlag) return;

4             _pool.OnReceive += new SocketPoolController.RecevieHandler(HandleRequest);

5             _pool.RunPool(config.IP, config.Port);

6             _runFlag = true;

7         }

       关闭服务器只需要把连接池关闭了就行了

1         public void StopServer()

2         {

3             _pool.StopPool();

4             _pool = null;

5             _runFlag = false;

6         }

接收到浏览器请求后处理的方法(也就是跟连接池注册的方法)如下

 1         private void HandleRequest(string uid, string header)

 2         {

 3             RequestHeader request = RequestHeader.ConvertRequestHander(header);

 4             ResponseHeader response = new ResponseHeader();

 5             response.Server = "My Test WebSite";

 6             response.Connection = "close";

 7 

 8             //暂时只支持POST和GET的请求,其他的请求就视为未实现,发501响应

 9             if (request.ActionName != "GET" && request.ActionName != "POST")

10             {

11                 response.ResponseCode = "501 Not Implemented";

12                 response.Content_Type = "text/html";

13                 SendErrorResponse(uid, response);

14                 return;

15             }

16 

17             //对请求资源名称经行处理。主要是去除GET时带的参数,还有把斜杠换过来

18             string fullURL = config.VirtualPath + request.URL;

19             string fileName =(fullURL.Contains('?')? Regex.Match(fullURL, @".*(?=\?)").Value:fullURL).Replace('/','\\');

20 

21             //如果请求的只是一个斜杠的,那证明请求的是默认页面

22             if (fileName == fullURL + "\\")

23             {

24                 //如果配置中有默认页的,发200的响应

25                 string defaultFile = Path.Combine(config.VirtualPath, config.DefaultPage);

26                 if (File.Exists(defaultFile))

27                 {

28                     response.Content_Type = "text/html";

29                     response.ResponseCode = "200 OK";

30                     SendResponse(uid, File.ReadAllText(defaultFile), response);

31                     return;

32                 }

33                 //如果不存在的,当404处理了

34                 else

35                 {

36                     response.ResponseCode = "404 Not Found";

37                     response.Content_Type = "text/html";

38                     SendErrorResponse(uid, response);

39                     return;

40                 }

41             }

42 

43             //如果请求的资源不存在的,那就发送404

44             FileInfo fileInfo = new FileInfo(fileName);

45             if (!fileInfo.Exists)

46             {

47                 response.ResponseCode = "404 Not Found";

48                 response.Content_Type = "text/html";

49                 SendErrorResponse(uid, response);

50                 return;

51             }

52 

53             //如果请求的资源不在支持的范围内,也当作404了,感觉不是404的,貌似是403的

54             string extension = fileInfo.Extension.TrimStart('.');

55             if (string.IsNullOrEmpty(extension) || !_supportExtension.ContainsKey(extension))

56             {

57                 response.ResponseCode = "404 Not Found";

58                 response.Content_Type = "text/html";

59                 SendErrorResponse(uid, response);

60                 return;

61             }

62 

63             //既然也不是请求起始页的,也没发生上面列的错误的,就正常响应

64             response.Content_Type = _supportExtension[extension];

65             response.ResponseCode = "200 OK";

66             FileStream fs =null;

67             try

68             {

69                 fs = File.OpenRead(fileInfo.FullName);

70                 byte[] datas = new byte[fileInfo.Length];

71                 fs.Read(datas, 0, datas.Length);

72                 SendResponse(uid, datas, response);

73             }

74             finally

75             {

76                 fs.Close();

77                 fs.Dispose();

78                 fs = null;

79             }

80             return;

81         }

发送消息的方法有三个,都是内部方法

  • SendResponse(string uid,string content,ResponseHeader header)是原始版的,发送普通的响应。
  • SendResponse(string uid, byte[] content, ResponseHeader header)是重载过的,专门发送内容已经是byte[]的响应。
  • SendErrorResponse(string uid,ResponseHeader header)用于专门发送错误响应的,其实内部也是调用了SendResponse(string uid,string content,ResponseHeader header)方法。从发送消息的情况来看,总共利用Socket发了两次数据,第一次是发响应消息,第二次才是发响应内容。
 1         private void SendErrorResponse(string uid,ResponseHeader header)

 2         {

 3             string errorPageContent = header.CreateErrorHtml();

 4             header.Content_Length = errorPageContent.Length;

 5             SendResponse(uid, errorPageContent, header);

 6         }

 7 

 8         private void SendResponse(string uid,string content,ResponseHeader header)

 9         {

10             header.Content_Length = content.Length;

11             _pool.SendMessage(uid, header.ToString());

12             _pool.SendMessage(uid, content);

13         }

14 

15         private void SendResponse(string uid, byte[] content, ResponseHeader header)

16         {

17             header.Content_Length = content.Length;

18             _pool.SendMessage(uid, header.ToString());

19             _pool.SendMessage(uid, content);

20         }

 

  这个简单的Web服务器就完成了,测试了一下,发现效率比不上IIS,普通浏览一个页面察觉不出来,当下载几个文件时就有差别了,IIS的用了接近2秒的时间,而这个服务器去用了接近四秒的时间。不知是哪里慢了,可能是连接池处理得不好。下面提供了源码,要用到连接池的,连接池的代码这里不提供了,需的话可以在上一篇博文《Socket连接池》里获取好了,做这个Web服务器是为了抛砖引玉,不足的,错的,遗漏的东西还很多,希望各位园友多多指点,谢谢!

整份源码
  1    class RequestHeader

  2     {

  3         public string ActionName { get; set; }

  4         public string URL { get; set; }

  5         public string Host { get; set; }

  6         public string Accept { get; set; }

  7         public string Connection { get; set; }

  8         public string Accept_Language { get; set; }

  9         public string User_Agent { get; set; }

 10         public string Accept_Encoding { get; set; }

 11 

 12         public string Form { get; set; }

 13         public int Content_Length { get; set; }

 14         public string Referer { get; set; }

 15         public string Content_Type { get; set; }

 16 

 17         public static RequestHeader ConvertRequestHander(string headerStr)

 18         {

 19             string regActionName = "GET|POST";

 20             string regURL = "(?<=GET|POST).*?(?=HTTP/1.1)";

 21             string regHost = @"(?<=Host\:\s).*(?=\r\n)";

 22             string regAccept = @"(?<=Accept\:\s).*(?=\r\n)";

 23             string regConnection = @"(?<=Connection\:\s).*(?=\r\n)";

 24             string regAcceptLanguage = @"(?<=Accept-Language\:\s).*(?=\r\n)";

 25             string regUserAgent = @"(?<=User-Agent\:\s).*(?=\r\n)";

 26             string regAcceptEncoding = @"(?<=Accept-Encoding\:\s).*(?=\r\n)";

 27 

 28             string regForm = @"(?<=\r\n\r\n).*";

 29             string regConntenLength = @"(?<=Connten-Length\:\s).*(?=\r\n)";

 30             string regRefere = @"(?<=Refere\:\s).*(?=\r\n)";

 31             string regContentType = @"(?<=Content-Type\:\s).*(?=\r\n)";

 32 

 33             RequestHeader hander = new RequestHeader();

 34             hander.ActionName = Regex.Match(headerStr, regActionName).Value;

 35             hander.URL = Regex.Match(headerStr, regURL).Value;

 36             hander.Host = Regex.Match(headerStr, regHost).Value;

 37             hander.Accept = Regex.Match(headerStr, regAccept).Value;

 38             hander.Connection = Regex.Match(headerStr, regConnection).Value;

 39             hander.Accept_Language = Regex.Match(headerStr, regAcceptLanguage).Value;

 40             hander.Accept_Encoding = Regex.Match(headerStr, regAcceptEncoding).Value;

 41             hander.User_Agent = Regex.Match(headerStr, regUserAgent).Value;

 42             string tempStr = Regex.Match(headerStr, regConntenLength).Value;

 43             hander.Content_Length = Convert.ToInt32(tempStr == "" ? "0" : tempStr);

 44             hander.Referer = Regex.Match(headerStr, regRefere).Value;

 45             hander.Content_Type = Regex.Match(headerStr, regContentType).Value;

 46             hander.Form = Regex.Match(headerStr, regForm).Value;

 47             return hander;

 48         }

 49     }

 50 

 51     class ResponseHeader

 52     {

 53         public string ResponseCode { get; set; }

 54         public string Server { get; set; }

 55         public int Content_Length { get; set; }

 56         public string Connection { get; set; }

 57         public string Content_Type { get; set; }

 58 

 59         public override string ToString()

 60         {

 61             string result = string.Empty;

 62             result += "HTTP/1.1 " + this.ResponseCode + "\r\n";

 63             result += "Server: "+this.Server+"\r\n";

 64             result += "Content-Length: " + this.Content_Length + "\r\n";

 65             result += "Connection: "+this.Connection+"\r\n";

 66             result += "Content-Type: " + this.Content_Type + "\r\n\r\n";

 67             return result;

 68         }

 69 

 70         public string CreateErrorHtml()

 71         {

 72             string html = @"<html><head><meta http-equiv=""Content-Type"" content=""text/html;charset=utf-8""></head><body>{0}</body></html>";

 73             html = html.Replace("{0}", "<h2>My Web Server</h2><div>{0}</div>");

 74             html = string.Format(html, this.ResponseCode);

 75             return html;

 76         }

 77     }

 78 

 79     public class ServerConfigEntity

 80     {

 81         public string IP { get; set; }

 82         public int Port { get; set; }

 83         public int MaxConnect { get; set; }

 84         public string VirtualPath { get; set; }

 85         public string DefaultPage { get; set; }

 86     }

 87 

 88     public class HttpProtocolServer

 89     {

 90         private SocketPoolController _pool;

 91         private Dictionary<string, string> _supportExtension;

 92         private ServerConfigEntity config;

 93         private bool _runFlag;

 94 

 95         public HttpProtocolServer(ServerConfigEntity config)

 96         {

 97             this.config = config;

 98             _pool = new SocketPoolController(32768, config.MaxConnect);

 99             _supportExtension = new Dictionary<string, string>() 

100             {

101                 { "htm", "text/html" },

102                 { "html", "text/html" },

103                 { "xml", "text/xml" },

104                 { "txt", "text/plain" },

105                 { "css", "text/css" },

106                 { "png", "image/png" },

107                 { "gif", "image/gif" },

108                 { "jpg", "image/jpg" },

109                 { "jpeg", "image/jpeg" },

110                 { "zip", "application/zip"},

111                 {"js","text/javascript"},

112                 { "dll", "text/plain" },

113                 {"aspx","text/html"}

114             };

115             _runFlag = false;

116         }

117 

118         public void RunServer()

119         {

120             if (_runFlag) return;

121             _pool.OnReceive += new SocketPoolController.RecevieHandler(HandleRequest);

122             _pool.RunPool(config.IP, config.Port);

123             _runFlag = true;

124         }

125 

126         public void StopServer()

127         {

128             _pool.StopPool();

129             _pool = null;

130             _runFlag = false;

131         }

132 

133         private void HandleRequest(string uid, string header)

134         {

135             RequestHeader request = RequestHeader.ConvertRequestHander(header);

136             ResponseHeader response = new ResponseHeader();

137             response.Server = "My Test WebSite";

138             response.Connection = "close";

139 

140             //暂时只支持POST和GET的请求,其他的请求就视为未实现,发501响应

141             if (request.ActionName != "GET" && request.ActionName != "POST")

142             {

143                 response.ResponseCode = "501 Not Implemented";

144                 response.Content_Type = "text/html";

145                 SendErrorResponse(uid, response);

146                 return;

147             }

148 

149             //对请求资源名称经行处理。主要是去除GET时带的参数,还有把斜杠换过来

150             string fullURL = config.VirtualPath + request.URL;

151             string fileName =(fullURL.Contains('?')? Regex.Match(fullURL, @".*(?=\?)").Value:fullURL).Replace('/','\\');

152 

153             //如果请求的只是一个斜杠的,那证明请求的是默认页面

154             if (fileName == fullURL + "\\")

155             {

156                 //如果配置中有默认页的,发200的响应

157                 string defaultFile = Path.Combine(config.VirtualPath, config.DefaultPage);

158                 if (File.Exists(defaultFile))

159                 {

160                     response.Content_Type = "text/html";

161                     response.ResponseCode = "200 OK";

162                     SendResponse(uid, File.ReadAllText(defaultFile), response);

163                     return;

164                 }

165                 //如果不存在的,当404处理了

166                 else

167                 {

168                     response.ResponseCode = "404 Not Found";

169                     response.Content_Type = "text/html";

170                     SendErrorResponse(uid, response);

171                     return;

172                 }

173             }

174 

175             //如果请求的资源不存在的,那就发送404

176             FileInfo fileInfo = new FileInfo(fileName);

177             if (!fileInfo.Exists)

178             {

179                 response.ResponseCode = "404 Not Found";

180                 response.Content_Type = "text/html";

181                 SendErrorResponse(uid, response);

182                 return;

183             }

184 

185             //如果请求的资源不在支持的范围内,也当作404了,感觉不是404的,貌似是403的

186             string extension = fileInfo.Extension.TrimStart('.');

187             if (string.IsNullOrEmpty(extension) || !_supportExtension.ContainsKey(extension))

188             {

189                 response.ResponseCode = "404 Not Found";

190                 response.Content_Type = "text/html";

191                 SendErrorResponse(uid, response);

192                 return;

193             }

194 

195             //既然也不是请求起始页的,也没发生上面列的错误的,就正常响应

196             response.Content_Type = _supportExtension[extension];

197             response.ResponseCode = "200 OK";

198             FileStream fs =null;

199             try

200             {

201                 fs = File.OpenRead(fileInfo.FullName);

202                 byte[] datas = new byte[fileInfo.Length];

203                 fs.Read(datas, 0, datas.Length);

204                 SendResponse(uid, datas, response);

205             }

206             finally

207             {

208                 fs.Close();

209                 fs.Dispose();

210                 fs = null;

211             }

212             return;

213         }

214 

215         private void SendErrorResponse(string uid,ResponseHeader header)

216         {

217             string errorPageContent = header.CreateErrorHtml();

218             header.Content_Length = errorPageContent.Length;

219             SendResponse(uid, errorPageContent, header);

220         }

221 

222         private void SendResponse(string uid,string content,ResponseHeader header)

223         {

224             header.Content_Length = content.Length;

225             _pool.SendMessage(uid, header.ToString());

226             _pool.SendMessage(uid, content);

227         }

228 

229         private void SendResponse(string uid, byte[] content, ResponseHeader header)

230         {

231             header.Content_Length = content.Length;

232             _pool.SendMessage(uid, header.ToString());

233             _pool.SendMessage(uid, content);

234         }

235     }

 对本服务器的更改情况,将在下一篇博文《自己写Web服务器(续)》列出

你可能感兴趣的:(web服务器)