using System;
02
using System.IO;
03
using System.Net;
04
using System.Text;
05
using System.Threading;
06
07
class MainClass {
08
private static int maxRequestHandlers = 5;
09
private static int requestHandlerID = 0;
10
private static HttpListener listener;
11
private static void RequestHandler(IAsyncResult result) {
12
try {
13
HttpListenerContext context = listener.EndGetContext(result);
14
StreamWriter sw = new StreamWriter(context.Response.OutputStream, Encoding.UTF8);
15
sw.WriteLine("<html><head><title>C# </title>");
16
sw.WriteLine("</head><body>" + result.AsyncState);
17
sw.WriteLine("</body></html>");
18
sw.Flush();
19
20
context.Response.ContentType = "text/html";
21
context.Response.ContentEncoding = Encoding.UTF8;
22
23
context.Response.Close();
24
} catch (ObjectDisposedException) {
25
Console.WriteLine(result.AsyncState);
26
} finally {
27
if (listener.IsListening) {
28
listener.BeginGetContext(RequestHandler,
29
"RequestHandler_" + Interlocked.Increment(ref requestHandlerID));
30
}
31
}
32
}
33
34
public static void Main(string[] args) {
35
using (listener = new HttpListener()) {
36
listener.Prefixes.Add("http://localhost:8080/");
37
listener.Start();
38
for (int count = 0; count < maxRequestHandlers; count++) {
39
listener.BeginGetContext(RequestHandler, "RequestHandler_" +
40
Interlocked.Increment(ref requestHandlerID));
41
}
42
Console.WriteLine("Press Enter to stop the HTTP Server");
43
Console.ReadLine();
44
listener.Stop();
45
46
listener.Abort();
47
}
48
}
49
}
HttpListener:使用HttpListener可创建响应 HTTP 请求的简单 HTTP 协议侦听器。实际上HttpListener只是实现了服务器端Socket上面的一个简单封装类。通过设置Prefixes属性来进行侦听,如,侦听器绑定到http或https端点的URL(如下代码).侦听器默认是绑定到运行在http的80端口和https的443的端口,并允许匿名和无身份验证的客户端访问。可以使用HttpListener类的属性Prefixes来制定自定义url和端口,并通过设置属性AuthenticationSchemes属性来配置身份验证。
建立HttpListener后,执行Start(执行是Start实际上是引发底层的Bind和Listener),就开始处理客服端输入请求。HttpListener中GetContext和套接字的Accept类似,它在没有请求准备好处理的时候处于被阻塞状态。GetContext返回一个对象HttpListenerContext。HttpListenerContext对象的属性Request属性提供了许多关于客户机的一些请求信息.Response则返回一个HttpListerResponse对象,该对象可以用来响应客户机的请求。
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace ConsoleHttpEchoServer
{
class Program
{
static void Main(string[] args)
{
using (HttpListener listerner = new HttpListener())
{
listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
listerner.Prefixes.Add("http://localhost:8080/web/");
// listerner.Prefixes.Add("http://localhost/web/");
listerner.Start();
Console.WriteLine("WebServer Start Successed.......");
while (true)
{
//等待请求连接
//没有请求则GetContext处于阻塞状态
HttpListenerContext ctx = listerner.GetContext();
ctx.Response.StatusCode = 200;//设置返回给客服端http状态代码
string name = ctx.Request.QueryString["name"];
if (name != null)
{
Console.WriteLine(name);
}
//使用Writer输出http响应代码
using (StreamWriter writer = new StreamWriter(ctx.Response.OutputStream))
{
Console.WriteLine("hello");
writer.WriteLine("<html><head><title>The WebServer Test</title></head><body>");
writer.WriteLine("<div style=\"height:20px;color:blue;text-align:center;\"><p> hello {0}</p></div>", name);
writer.WriteLine("<ul>");
foreach (string header in ctx.Request.Headers.Keys)
{
writer.WriteLine("<li><b>{0}:</b>{1}</li>", header, ctx.Request.Headers[header]);
}
writer.WriteLine("</ul>");
writer.WriteLine("</body></html>");
writer.Close();
ctx.Response.Close();
}
}
listerner.Stop();
}
}
}
}
在浏览器 中输入 http://localhost:8080/web/?name=test或 http://localhost/web/?name=test,在浏览器就会出现Hello test 和一些Request头部相关信息.
备注:
1.URI 前缀字符串由方案(http 或 https)、主机、可选端口和可选路径组成。完整前缀字符串的示例为“http://www.contoso.com:8080/customerData/”。前缀必须以正斜杠(“/”)结尾。带有与所请求的 URI 最近似匹配的前缀的 HttpListener 对象响应请求。多个 HttpListener 对象不能添加同一前缀;如果 HttpListener 添加已经使用的前缀,将引发Win32Exception 异常。
2.如果指定了端口,主机元素可以被替换为“*”,以指示如果请求的 URI 与任何其他前缀都不匹配,则 HttpListener 接受发送到该端口的请求。例如,当任何 HttpListener 都不处理请求的 URI 时,若要接收发送到端口 8080 的所有请求,前缀应为“http://*:8080/”。同样,若要指定 HttpListener 接受发送到端口的所有请求,请将主机元素替换为“+”字符,即“https://+:8080”。“*”和“+”字符可出现在包含路径的前缀中。
3.AuthenticationSchemes枚举类有以下值
Anonymous:默认值,允许任意的客户机进行连接,不需要身份验证。
Basic:要求提供纯文本(64位编码)用户名和密码来进行验证。
Digest:类似与基本身份验证,但是用户名和密码使用一个简单密码散列进行传输。
Ntlm: 指定 NTLM 身份验证(只有IE支持)。
IntegratedWindowsAuthentication:指定Windows身份验证。
Negotiate: 和客户端协商以确定身份验证方案。如果客户端和服务器均支持 Kerberos,则使用 Kerberos;否则使用 Ntlm
None:不进行身份验证。
HTTP/1.1协议中共定义了八种方法(有时也叫“动作”)来表明Request-URI指定的资源的不同操作方式:
·
返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。
·
向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
·
向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意访问。
·
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
·
向指定资源位置上传其最新内容。
·
请求服务器删除Request-URI所标识的资源。
·
回显服务器收到的请求,主要用于测试或诊断。
·
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed);当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。
HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。
HTTP响应的代码
3、POST与GET的差异
1.3中介绍了8种方法,其中GET与POST最基本和常用了。表单提交中get和post方式的区别归纳如下几点:
·
·
·
·
·
在FORM提交的时候,如果不指定Method,则默认为GET请求(.net默认是POST),Form中提交的数据将会附加在url之后,以?分开与url分开。字母数字字符原样发送,但空格转换为“+”号,其它符号转换为%XX,其中XX为该符号以16进制表示的ASCII(或ISO Latin-1)值。GET请求请提交的数据放置在HTTP请求协议头中,而POST提交的数据则放在实体数据中;GET方式提交的数据最多只能有2048字节,而POST则没有此限制。POST传递的参数在doc里,也就http协议所传递的文本,接受时再解析参数部分。获得参数。一般用POST比较好。POST提交数据是隐式的,GET是通过在url里面传递的,用来传递一些不需要保密的数据,GET是通过在URL里传递参数,POST不是。
说明:关于“POST与GET的差异”查考了网上前辈的资料,由于找不出源头,到处都是转帖,这里就不贴出相关网址了,baidu或Google下就知道了。
4、以一个实例说明C#中如何使用POST、GET等操作
在介绍实例之前,我们要先介绍一下HttpWebRequest和HttpWebResponse,在C#中就是用这两个类实现客户端向服务器端发送HTTP消息、客户端接受服务器端的HTTP响应。