您的位置:首页 > 编程语言 > C#

C#线程系列讲座(3):线程池和文件下载服务器

2012-04-14 15:43 393 查看
转自:/article/4740814.html

如果设计一个服务器程序,每当处理用户请求时,都开始一个线程,将会在一定程序上消耗服务器的资源。为此,一个最好的解决方法就是在服务器启动之前,事先创建一些线程对象,然后,当处理客户端请求时,就从这些建好的线程中获得线程对象,并处理请求。保存这些线程对象的结构就叫做线程池。

在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,因为,文件名要为英文名(不能有空格等特殊字符)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: