自己写的Web服务器
自己写的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测试数据 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测试数据 3 Connection: keep- alive 4 Content-Length: 35 5 Accept: application / json, text / javascript, * /*; q=0.01 6 Origin: http://kb.cnblogs测试数据 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测试数据/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/javascriptHTTP的内容不讲太多了,知道这些足以写这个服务器了。在博客园的知识库了发现一篇文章讲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 }
分类: C# , Socket编程
标签: Socket , Web服务器 , Http
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息