毕设中有一个文件传输的功能模块,所以用Httplistener类写了一个HttpServer类作为一个简单的web服务器,这样客户端下载文件就很简单了。
using System;
using System.Net;
using System.Text;
using System.Threading;
using System.IO;
using System.Security.Principal;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace Test
{
class HttpServer
{
string port;
string homeDir;
HttpListener listener;
Thread listenThread;
public HttpServer(string port, string homeDir)
{
this.port = port;
this.homeDir = homeDir;
}
/// <summary>
/// 设置监听端口,重启服务生效
/// </summary>
//public string Port
//{
// get { return this.port; }
// set
// {
// int p;
// if (string.IsNullOrEmpty(value) || !int.TryParse(value, out p))
// {
// throw new Exception("给http监听器赋值的端口号无效!");
// }
// this.port = value;
// }
//}
/// <summary>
/// http服务根目录
/// </summary>
public string HomeDir
{
get { return this.homeDir; }
set
{
if (!File.Exists(value))
throw new Exception("http服务器设置的根目录不存在!");
this.homeDir = value;
}
}
/// <summary>
/// 服务器是否在运行
/// </summary>
public bool IsRunning
{
get { return (listener == null) ? false : listener.IsListening; }
}
/// <summary>
/// 启动服务
/// </summary>
public void Start()
{
if (listener != null)
return;
listener = new HttpListener();
listener.Prefixes.Add("http://+:" + this.port + "/");
listener.Start();
listenThread = new Thread(AcceptClient);
listenThread.Name = "httpserver";
listenThread.Start();
}
/// <summary>
/// 停止服务
/// </summary>
public void Stop()
{
if (listener != null)
{
listener.Stop();
}
}
/// <summary>
/// /接受客户端请求
/// </summary>
void AcceptClient()
{
while (listener.IsListening)
{
try
{
HttpListenerContext context = listener.GetContext();
new Thread(HandleRequest).Start(context);
}
catch
{
}
}
}
//处理客户端请求
void HandleRequest(object ctx)
{
HttpListenerContext context = ctx as HttpListenerContext;
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
if (request.HttpMethod.ToUpper() != "GET") //只允许get请求方式
{
response.ContentLength64 = 0;
response.StatusCode = 404;
response.Abort();
return;
}
string uri = System.Web.HttpUtility.UrlDecode(request.RawUrl);
uri = uri.Substring(uri.IndexOf("/") + 1);
uri = uri.Replace("/", Path.DirectorySeparatorChar.ToString());
uri = Path.Combine(homeDir, uri);
if (!File.Exists(uri)) //请求的文件不存在
{
response.StatusCode = 404;
response.Close();
return;
}
//向客户端传输请求的文件
FileStream stream = new FileStream(uri, FileMode.Open, FileAccess.Read, FileShare.Read);
try
{
response.ContentLength64 = stream.Length;
response.ContentType = GetContentType(Path.GetExtension(uri));
byte[] buff = new byte[4096];
int count = 0;
while ((count = stream.Read(buff, 0, 4096)) != 0)
{
context.Response.OutputStream.Write(buff, 0, count);
}
response.Close();
stream.Close();
}
catch
{
stream.Close();
}
//finally
//{
// //response.OutputStream.Flush();
// Thread.Sleep(100);
// response.Close();
// stream.Close();
//}
/*
* 存在问题:在cach或finally分支中调用response.Close();或response.OutputStram.Close()时有时会报异常“在写入所有字节之前不能关闭流”。
* 可能原因:由于在try中出现异常时文件未传输完成,当传输的文件大小未达到response.ContentLength64 = stream.Length;中指定的大小而关闭response时就会报此异常,
* 实现中当客户端断开连接时就会出现此异常。
* 调试中发现try中发生的异常为:“指定的网络名不再可用”, 暂未找到解决此异常的办法。
*/
}
/// <summary>
/// 获取文件对应MIME类型
/// </summary>
/// <param name="fileExtention">文件扩展名,如.jpg</param>
/// <returns></returns>
string GetContentType(string fileExtention)
{
switch (fileExtention)
{
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".html":
return "text/html";
default:
return "application/octet-stream";
}
}
}
}