通過HttpListener實現簡單的Http服務
基本概念
HttpListener提供一個簡單的、可通過編程方式控制的 HTTP 協議偵聽器。通過它可以很容易的提供一些Http服務,而無需啟動IIS這類大型服務程序。
注意:該類僅在運行 Windows XP SP2 或 Windows Server 2003 操作系統的計算機上可用。
使用Http服務一般步驟如下:
1 創建一個HTTP偵聽器對象並初始化
2 添加需要監聽的URI 前綴
3 開始偵聽來自客戶端的請求
4 處理客戶端的Http請求
5 關閉HTTP偵聽器
其中3,4兩步可以循環處理,以提供多客戶多次請求的服務。
創建一個HTTP偵聽器對象
創建HTTP偵聽器對象只需要新建一個HttpListener對象即可。
HttpListener listener = new HttpListener();
初始化需要經過如下兩步
添加需要監聽的URL范圍至listener.Prefixes中,可以通過如下函數實現:
listener.Prefixes.Add(prefix) //prefix必須以'/'結尾
調用listener.Start()實現端口的綁定,並開始監聽客戶端的需求。
接受HTTP請求
在.net2.0中,通過HttpListenerContext對象提供對HttpListener類使用的請求和響應對象的訪問。
獲取HttpListenerContext的最簡單方式如下:
HttpListenerContext context = listener.GetContext();
該方法將阻塞調用函數至接收到一個客戶端請求為止,如果要提高響應速度,可使用異步方法listener.BeginGetContext()來實現HttpListenerContext對象的獲取。
處理HTTP請求
獲取HttpListenerContext后,可通過Request屬性獲取表示客戶端請求的對象,通過Response屬性取表示 HttpListener 將要發送到客戶端的響應的對象。
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
這里的HttpListenerRequest對象和HttpListenerResponse對象和Asp中的Request和Response的使用方式類似,這里就不多說了,具體的使用可以參看下面的例子。
關閉HTTP偵聽器
通過調用listener.Stop()函數即可關閉偵聽器,並釋放相關資源
異步方法listener
====== 異步方法listener ======
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Net;
- using System.Net.Sockets;
- using DevSDK.Net.Sockets;
- using System.IO;
- namespace ConsoleApplication1
- {
- class Program
- {
- static HttpListener sSocket = null;
- static void Main(string[] args)
- {
- sSocket = new HttpListener();
- sSocket.Prefixes.Add("http://127.0.0.1:8080/");
- sSocket.Start();
- sSocket.BeginGetContext(new AsyncCallback(GetContextCallBack), sSocket);
- Console.Read();
- }
- static void GetContextCallBack(IAsyncResult ar)
- {
- try
- {
- sSocket = ar.AsyncState as HttpListener;
- HttpListenerContext context = sSocket.EndGetContext(ar);
- sSocket.BeginGetContext(new AsyncCallback(GetContextCallBack), sSocket);
- Console.WriteLine(context.Request.Url.PathAndQuery);
- //其它處理code
- }
- catch { }
- }
- }
- }
非異步方法listener
====== C# 利用HttpListener監聽處理Http請求 ======
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Net;
- using System.Net.Sockets;
- using System.IO;
- using System.Xml.Serialization;
- using System.Threading;
- using System.Web;
- namespace Test
- {
- class Program
- {
- static void Main(string[] args)
- {
- try
- {
- HttpListener listerner = new HttpListener();
- {
- for (; true; )
- {
- try
- {
- listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份驗證 Anonymous匿名訪問
- listerner.Prefixes.Add("http://192.168.1.10:1500/ApiService/");
- listerner.Start();
- }
- catch (Exception e)
- {
- Console.WriteLine("未能成功連接服務器.....");
- listerner = new HttpListener();
- continue;
- }
- break;
- }
- Console.WriteLine("服務器啟動成功.......");
- int maxThreadNum, portThreadNum;
- //線程池
- int minThreadNum;
- ThreadPool.GetMaxThreads(out maxThreadNum, out portThreadNum);
- ThreadPool.GetMinThreads(out minThreadNum, out portThreadNum);
- Console.WriteLine("最大線程數:{0}", maxThreadNum);
- Console.WriteLine("最小空閑線程數:{0}", minThreadNum);
- Console.WriteLine("\n\n等待客戶連接中。。。。");
- while (true)
- {
- //等待請求連接
- //沒有請求則GetContext處於阻塞狀態
- HttpListenerContext ctx = listerner.GetContext();
- ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc), ctx);
- }
- con.Close();
- listerner.Stop();
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- Console.Write("Press any key to continue . . . ");
- Console.ReadKey( );
- }
- }
- static void TaskProc(object o)
- {
- HttpListenerContext ctx = (HttpListenerContext)o;
- ctx.Response.StatusCode = 200;//設置返回給客服端http狀態代碼
- string type = ctx.Request.QueryString["type"];
- string userId = ctx.Request.QueryString["userId"];
- string password = ctx.Request.QueryString["password"];
- string filename = Path.GetFileName(ctx.Request.RawUrl);
- string userName = HttpUtility.ParseQueryString(filename).Get("userName");//避免中文亂碼
- //進行處理
- //使用Writer輸出http響應代碼
- using (StreamWriter writer = new StreamWriter(ctx.Response.OutputStream))
- {
- writer.Write(“處理結果”);
- writer.Close();
- ctx.Response.Close();
- }
- }
- }
- }
Android客戶端:
- public static void Register(final Handler handler, final Context context,
- final String userId, final String userName,final int groupId, final String password){
- new Thread(new Runnable(){
- public void run() {
- if(!CommonTools.checkNetwork(context)){
- Message msg = new Message();
- msg.what = Signal.NETWORK_ERR;
- handler.sendMessage(msg);
- return;
- }
- try {
- String content = "";
- String tmp = java.net.URLEncoder.encode(userName, "utf-8"); //防止中文亂碼
- URL url = new URL(URL+"?type=Register&userId="+userId+"&password="+password+"&groupId="+groupId+"&userName="+tmp);
- // HttpURLConnection
- HttpURLConnection httpconn = (HttpURLConnection) url.openConnection();
- if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
- InputStreamReader isr = new InputStreamReader(httpconn.getInputStream(), "utf-8");
- int i;
- // read
- while ((i = isr.read()) != -1) {
- content = content + (char) i;
- }
- isr.close();
- }
- //disconnect
- httpconn.disconnect();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }//run
- }).start();//thread
- }
注意:
1.中文亂碼問題
在客戶端采用如下形式
String tmp = java.net.URLEncoder.encode(userName, "utf-8"); //防止中文亂碼
服務器端
string filename = Path.GetFileName(ctx.Request.RawUrl);
string userName = HttpUtility.ParseQueryString(filename).Get("userName");//避免中文亂碼
服務器端需要引入: using System.Web;
此時可能提示找不到庫,則在項目右鍵添加引用 找到 System.Web.dll勾選即可
2.[System.Net.HttpListenerException] = {"拒絕訪問。"}問題
如果是win7或者win8,在cmd.exe上右鍵,以管理員身份運行,然后執行下面的命令
netsh http add urlacl url=http://本機IP:1500/ user=用戶名(如Administrator)
3.記得關閉防火牆,或者只開放指定端口,步驟如下:
step1、點擊控制面板
step2、選擇windows防火牆,點擊高級設置
step3、在彈出的“高級安全windows防火牆”點擊“入站規則”,在右側“操作”欄點擊“入站規則”下的“新建規則…”,此時會彈出一個窗口讓你設置。剩下的就非常傻瓜化了。
step4、彈出“新建入站規則向導”-規則類型-選中“端口”,點擊下一步。選擇規則應用的協議“TCP/UDP”如果是TCP你就選擇TCP,UDP就選擇UDP。再勾選“特定本地端口”在文本框輸入您想開放的端口號(例如1521)。
step5、點擊下一步,到“連接符合指定條件時應該進行什么操作?”選擇“允許連接”。點擊下一步到“配置文件”何時應用該規則,勾選“域”、“專用”、“公用”點擊下一步。
step6、配置規則名稱,隨便輸入你自己認為好記的規則名稱即可。
非異步方法listener 自開線程處理請求
====== 非異步方法listener 自開線程處理請求 ======
- using System;
- using System.IO;
- using System.Net;
- using System.Text;
- using System.Threading;
- namespace HttpHelper
- {
- /// <summary>
- /// HTTP請求監聽
- /// </summary>
- public class HttpListeners
- {
- private static HttpListener _httpListener;
- static readonly int Port = 1005;
- static HttpListeners()
- {
- ListenerStart();
- }
- private static bool ListenerStop()
- {
- try
- {
- if (_httpListener != null)
- {
- //LogInfo("停止監聽端口:" + Port);
- _httpListener.Stop();
- }
- return true;
- }
- catch (Exception e)
- {
- //LogError(e.Message + e.StackTrace);
- return false;
- }
- }
- /// <summary>
- /// 監聽端口
- /// </summary>
- private static void ListenerStart()
- {
- try
- {
- _httpListener = new HttpListener { AuthenticationSchemes = AuthenticationSchemes.Anonymous };
- _httpListener.Prefixes.Add(string.Format("http://+:{0}/",Port));
- _httpListener.Start();
- //LogInfo("開始監聽端口:" + Port);
- while (true)
- {
- try
- {
- //監聽客戶端的連接,線程阻塞,直到有客戶端連接為止
- var client = _httpListener.GetContext();
- new Thread(HandleRequest).StartAsync(client);
- }
- catch (Exception ex)
- {
- //LogError(ex.Message + ex.StackTrace);
- }
- }
- }
- catch (Exception e)
- {
- //LogError(e.Message + e.StackTrace);
- Environment.Exit(0);
- }
- }
- private static void HandleRequest(object obj)
- {
- var client = obj as HttpListenerContext;
- if (client == null) return;
- try
- {
- var coding = Encoding.UTF8;
- var request = client.Request;
- // 取得回應對象
- var response = client.Response;
- response.StatusCode = 200;
- response.ContentEncoding = coding;
- Console.WriteLine("{0} {1} HTTP/1.1", request.HttpMethod, request.RawUrl);
- Console.WriteLine("Accept: {0}", string.Join(",", request.AcceptTypes));
- Console.WriteLine("Accept-Language: {0}",
- string.Join(",", request.UserLanguages));
- Console.WriteLine("User-Agent: {0}", request.UserAgent);
- Console.WriteLine("Accept-Encoding: {0}", request.Headers["Accept-Encoding"]);
- Console.WriteLine("Connection: {0}",
- request.KeepAlive ? "Keep-Alive" : "close");
- Console.WriteLine("Host: {0}", request.UserHostName);
- Console.WriteLine("Pragma: {0}", request.Headers["Pragma"]);
- // 構造回應內容
- string responseString = @"<html><head><title>HttpListener Test</title></head><body><div>Hello, world.</div></body></html>";
- byte[] buffer = Encoding.UTF8.GetBytes(responseString);
- //對客戶端輸出相應信息.
- response.ContentLength64 = buffer.Length;
- Stream output = response.OutputStream;
- output.Write(buffer, 0, buffer.Length);
- //關閉輸出流,釋放相應資源
- output.Close();
- }
- catch (Exception e)
- {
- //LogError(e.Message + e.StackTrace);
- }
- finally
- {
- try
- {
- client.Response.Close();
- }
- catch (Exception e)
- {
- //LogError(e.Message);
- }
- }
- }
- }
- }
=== ThreadHelper ===
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace HttpHelper
- {
- public static class ThreadHelper
- {
- /// <summary>
- /// 開啟同步多線程
- /// </summary>
- public static void StartSync(this IEnumerable<Thread> threads, object startPara = null, Func<object, object> callback = null)
- {
- var ts = threads.ToArray();
- //啟動線程
- foreach (var thread in ts)
- {
- if (!thread.IsBackground)
- {
- thread.IsBackground = true;
- }
- var times = 0;
- while (thread.ThreadState == (ThreadState.Background | ThreadState.Unstarted) && times < 10)
- {
- try
- {
- if (startPara == null)
- {
- thread.Start();
- }
- else
- {
- thread.Start(startPara);
- }
- }
- catch (Exception e)
- {
- times++;
- }
- Thread.Sleep(100);
- }
- }
- Thread.Sleep(2000);
- //等待全部結束
- foreach (var thread in ts)
- {
- try
- {
- thread.Join();
- }
- catch (Exception e)
- {
- }
- }
- if (callback != null)
- {
- callback(startPara);
- }
- }
- /// <summary>
- /// 開啟多線程
- /// </summary>
- public static void StartAsync(this IEnumerable<Thread> threads, object startPara = null, Func<object, object> callback = null)
- {
- var ts = threads.ToArray();
- //啟動線程
- foreach (var thread in ts)
- {
- if (!thread.IsBackground)
- {
- thread.IsBackground = true;
- }
- var times = 0;
- while (thread.ThreadState == (ThreadState.Background | ThreadState.Unstarted) && times < 10)
- {
- try
- {
- if (startPara == null)
- {
- thread.Start();
- }
- else
- {
- thread.Start(startPara);
- }
- }
- catch (Exception e)
- {
- times++;
- }
- Thread.Sleep(100);
- }
- }
- if (callback != null)
- {
- callback(startPara);
- }
- }
- /// <summary>
- /// 開啟同步線程
- /// </summary>
- public static void StartSync(this Thread thread, object parameter = null)
- {
- try
- {
- if (!thread.IsBackground)
- {
- thread.IsBackground = true;
- }
- if (parameter == null)
- {
- thread.Start();
- }
- else
- {
- thread.Start(parameter);
- }
- }
- catch (Exception e)
- {
- }
- Thread.Sleep(1000);
- try
- {
- thread.Join();
- }
- catch (Exception e)
- {
- }
- }
- /// <summary>
- /// 開啟帶超時的同步線程
- /// </summary>
- public static void StartSyncTimeout(this Thread thread, int timeoutSeconds, object parameter = null)
- {
- try
- {
- if (!thread.IsBackground)
- {
- thread.IsBackground = true;
- }
- if (parameter == null)
- {
- thread.Start();
- }
- else
- {
- thread.Start(parameter);
- }
- thread.Join(timeoutSeconds * 1000);
- }
- catch (Exception e)
- {
- }
- }
- /// <summary>
- /// 開啟異步線程
- /// </summary>
- public static void StartAsync(this Thread thread, object parameter = null)
- {
- try
- {
- if (!thread.IsBackground)
- {
- thread.IsBackground = true;
- }
- if (parameter == null)
- {
- thread.Start();
- }
- else
- {
- thread.Start(parameter);
- }
- }
- catch (Exception e)
- {
- }
- }
- }
- }
=== end ===