如果設計一個服務器程序,每當處理用戶請求時,都開始一個線程,將會在一 定程序上消耗服務器的資源。為此,一個最好的解決方法就是在服務器啟動之前 ,事先創建一些線程對象,然後,當處理客戶端請求時,就從這些建好的線程中 獲得線程對象,並處理請求。保存這些線程對象的結構就叫做線程池。
在C#中可以通過System.Threading.ThreadPool類來實現,在默認情況下, ThreadPool最大可建立500個工作線程和1000個I/O線程(根據機器CPU個數和.net framework版本的不同,這些數據可能會有變化)。下面是一個用C#從線程池獲得 線程的例子:
private static void execute(object state)
{
Console.WriteLine(state);
}
static void Main(string[] args)
{
int workerThreads;
int completionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
Console.WriteLine(workerThreads);
Console.WriteLine(completionPortThreads);
ThreadPool.QueueUserWorkItem(execute,"線程1"); // 從線程池中得到一個線程,並運行execute
ThreadPool.QueueUserWorkItem(execute, "線程2");
ThreadPool.QueueUserWorkItem(execute, "線程3");
Console.ReadLine();
}
下圖為上面代 碼的運行結果。
要注意的是,使用ThreadPool獲得的線程都是後台線程。
下面的程序是我 設計的一個下載文件服務器的例子。這個例子從ThreadPool獲得線程,並處理相 應的客戶端請求。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.IO;
namespace MyThread
{
class FileServer
{
private String root;
private Thread listenerThread;
private void worker(object state)
{
TcpClient client = state as TcpClient;
try
{
client.ReceiveTimeout = 2000;
Stream stream = client.GetStream();
System.IO.StreamReader sr = new StreamReader(stream);
String line = sr.ReadLine();
String[] array = line.Split(' ');
String path = array[1].Replace('/', '\\');
String filename = root + path;
if (File.Exists(filename)) // 如果下載文件存在,開始下載這個文件
{
FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read,
FileShare.Read);
byte[] buffer = new byte[8192]; // 每次下載8K
int count = 0;
String responseHeader = "HTTP/1.1 200 OK\r\n" +
"Content-Type:application/octet-stream\r\n" +
"Content-Disposition:attachment;filename=" +
filename.Substring(filename.LastIndexOf("\\") + 1) + "\r\n\r\n";
byte[] header = ASCIIEncoding.ASCII.GetBytes(responseHeader);
stream.Write(header, 0, header.Length);
while ((count = fileStream.Read(buffer, 0, buffer.Count())) > 0)
{
stream.Write(buffer, 0, count);
}
Console.WriteLine(filename + "下載完成");
}
else // 文件不存在,輸出提示信息
{
String response = "HTTP/1.1 200 OK\r\nContent-Type:text/plain;charset=utf-8\r\n\r\n文件不存在";
byte[] buffer = ASCIIEncoding.UTF8.GetBytes(response);
stream.Write(buffer, 0, buffer.Length);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
if (client != null)
{
client.Close();
}
}
}
private void listener()
{
TcpListener listener = new TcpListener(1234);
listener.Start(); // 開始監聽客戶端請求
TcpClient client = null;
while (true)
{
client = listener.AcceptTcpClient();
client.ReceiveTimeout =2000;
ThreadPool.QueueUserWorkItem(worker, client); // 從線程池中獲得一個線程來處理客戶端請求
}
}
public FileServer(String root)
{
this.root= root;
}
public void start()
{
listenerThread = new Thread(listener);
listenerThread.Start(); // 開始運行監聽線程
}
}
}
FileServer類的使用方法:
FileServer fs = new FileServer (“d:\\download”);
fs.start();// 端口為 1234
如果d:"download目錄中有一個叫aa.exe的文件,在浏 覽器中輸入如下的地址可下載:
http://localhost:1234/aa.exe
下圖為下載對話框:
要注意的是,本程序並沒有處理含有中文和其他特殊字符(如空格)的 url,因為,文件名要為英文名(不能有空格等特殊字符)。
文章來 源:http://www.cnblogs.com/nokiaguy/archive/2008/07/18/1246299.html