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

简介:
本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:C#线程系列讲座(2):Thread类的应用

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

    C#中可以通过System.Threading.ThreadPool类来实现,在默认情况下,ThreadPool最大可建立500个工作线程和1000I/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#线程系列讲座(4):同步与死锁

本文转自银河使者博客园博客,原文链接http://www.cnblogs.com/nokiaguy/archive/2008/07/18/1246299.html如需转载请自行联系原作者


银河使者

相关文章
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
171 2
|
11月前
|
弹性计算 运维 对象存储
如何把阿里云ECS里的文件下载到本地(免登录免配置)
阿里云推出新功能,无需安装额外工具、不需ECS开通公网或登录ECS,仅通过控制台即可将ECS中的文件轻松下载至本地。只需开通OSS对象存储服务,按步骤创建任务,获取临时下载链接,即可在浏览器中直接下载文件。操作简便快捷,适合频繁需要从ECS下载文件的用户。
|
API Windows
揭秘网络通信的魔法:Win32多线程技术如何让服务器化身超级英雄,同时与成千上万客户端对话!
【8月更文挑战第16天】在网络编程中,客户/服务器模型让客户端向服务器发送请求并接收响应。Win32 API支持在Windows上构建此类应用。首先要初始化网络环境并通过`socket`函数创建套接字。服务器需绑定地址和端口,使用`bind`和`listen`函数准备接收连接。对每个客户端调用`accept`函数并在新线程中处理。客户端则通过`connect`建立连接,双方可通过`send`和`recv`交换数据。多线程提升服务器处理能力,确保高效响应。
157 6
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
194 1
如何在Java中实现多线程的Socket服务器?
在Java中,多线程Socket服务器能同时处理多个客户端连接以提升并发性能。示例代码展示了如何创建此类服务器:监听指定端口,并为每个新连接启动一个`ClientHandler`线程进行通信处理。使用线程池管理这些线程,提高了效率。`ClientHandler`读取客户端消息并响应,支持简单的文本交互,如发送欢迎信息及处理退出命令。
343 2
|
网络协议 安全 Python
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
|
2月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
168 19
|
3月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
500 0
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
243 3
|
11月前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
803 12

热门文章

最新文章