C#线程系列讲座(3):线程池和文件下载服务器
如果设计一个服务器程序,每当处理用户请求时,都开始一个线程,将会在一定程序上消耗服务器的资源。为此,一个最好的解决方法就是在服务器启动之前,事先创建一些线程对象,然后,当处理客户端请求时,就从这些建好的线程中获得线程对象,并处理请求。保存这些线程对象的结构就叫做线程池。
在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,因为,文件名要为英文名(不能有空格等特殊字符)。
C#线程系列讲座(3):线程池和文件下载服务器的更多相关文章
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...
- 转:C#线程系列讲座(1) BeginInvoke和EndInvoke方法
转载自:http://www.cnblogs.com/levin9/articles/2319248.html 开发语言:C#3.0IDE:Visual Studio 2008本系列教程主要包括如下内 ...
- 【java线程系列】java线程系列之java线程池详解
一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...
- C#线程系列讲座(2):Thread类的应用
一.Thread类的基本用法 通过System.Threading.Thread类可以开始新的线程,并在线程堆栈中运行静态或实例方法.可以通过Thread类的的构造方法传递一个无参数,并且不返回值(返 ...
- C#线程系列讲座(1):BeginInvoke和EndInvoke方法
一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行.这就需要在同一个进程中开启多个 ...
- 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型
关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...
- java线程系列之三(线程协作)
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7433673,转载请注明. 上一篇讲述了线程的互斥(同步),但是在很多情况 ...
- C#线程系列讲座(4):同步与死锁
虽然线程可以在一定程度上提高程序运行的效率,但也会产生一些副作用.让我们先看看如下的代码: class Increment { private int n = 0; ...
- C#线程系列讲座(5):同步技术之Monitor
在上一讲介绍了使用lock来实现线程之间的同步.实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类.先看看下面的C#源代码: public sta ...
随机推荐
- 从个人的角度谈谈本次GNTC大会的收获
GNTC资料:from sdnlab 从个人的角度谈谈本次大会的收获 从本次大会的主题演讲来看,目前SDN.NFV的最前沿已经不再像五年前持观望态度以及探讨,各大运营商.各大厂商已经将SDN.NFV具 ...
- Web 在线文件管理器学习笔记与总结(4)查看文件内容
② 查看文件内容 a.通过 file_get_contents($filename) 得到文件内容 b.通过 highlight_string($string) 或者 highlight_file($ ...
- 随机(Random)
随机(Random)随机是智能的基础,人工智能的很多技术都需要用到随机,因此有必要把这个提到前面谈谈一考虑基于C/C++,般我们都是使用的rand ()等函数实现随机,当然我们也有吊炸天的boost库 ...
- js获取各种宽高方法
屏幕的有效宽高: window.screen.availHeightwindow.screen.availWidth 网页可见区域宽:document.body.clientWidth 网页可见区域高 ...
- 浅谈XML
什么是 XML? · XML 指可扩展标记语言(EXtensible Markup Language) · XML 是一种标记语言,很类似 HTML · XML 的设计宗旨是传输数据,而非显示数据 · ...
- Sign-Magnitude Representation
COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION There are several alt ...
- 浏览器指纹 - HTTP cookie
http://www.iefans.net/ruhe-fangfan-xielu-shangwang-yinsi/ http://www.iefans.net/cookie-yinsi-guanxi/ ...
- Flink - Juggling with Bits and Bytes
http://www.36dsj.com/archives/33650 http://flink.apache.org/news/2015/05/11/Juggling-with-Bits-and-B ...
- autowire异常的三个情况
2010-3-11 16:06:00 net.sf.ehcache.config.ConfigurationFactory parseConfiguration 警告: No configuratio ...
- 注册、启动、停止windows服务
找到本机InstallUtil.exe命令 命令行下注册服务InstallUtil.exe D:\XXXXService.exe 启动服务 net start XXXXService 停止服务net ...