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

    在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,因为,文件名要为英文名(不能有空格等特殊字符)。

转载于:https://www.cnblogs.com/kakaliush/archive/2011/12/21/2295337.html

C#线程系列(3):线程池和文件下载服务器相关推荐

  1. java任务流程_死磕 java线程系列之线程池深入解析——普通任务执行流程

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了Java中 ...

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

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

  3. 死磕 java线程系列之线程池深入解析——未来任务执行流程

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了线程池中普 ...

  4. 线程系列3--Java线程同步通信技术

    上一篇文章我们讲解了线程间的互斥技术,使用关键字synchronize来实现线程间的互斥技术.根据不同的业务情况,我们可以选择某一种互斥的方法来实现线程间的互斥调用.例如:自定义对象实现互斥(sync ...

  5. java线程池深入讲解_死磕 java线程系列之线程池深入解析——生命周期

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 上一章我们一起重温了下线程的 ...

  6. C#线程系列讲座(4):同步与死锁

    本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:C#线程系列讲座(3):线程池和文件下载服务器   虽然线程可以在一定程度上提高程序运行的效率,但也会产生一些副作用.让我们先看看如下的代码: ...

  7. java 手编线程池_死磕 java线程系列之自己动手写一个线程池

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...

  8. idea 线程内存_Java线程池系列之-Java线程池底层源码分析系列(一)

    课程简介: 课程目标:通过本课程学习,深入理解Java线程池,提升自身技术能力与价值. 适用人群:具有Java多线程基础的人群,希望深入理解线程池底层原理的人群. 课程概述:多线程的异步执行方式,虽然 ...

  9. idea 线程内存_Java线程池系列之-Java线程池底层源码分析系列(二)

    课程简介: 课程目标:通过本课程学习,深入理解Java线程池,提升自身技术能力与价值. 适用人群:具有Java多线程基础的人群,希望深入理解线程池底层原理的人群. 课程概述:多线程的异步执行方式,虽然 ...

最新文章

  1. php排版word文档试卷,word选择题选项排版
  2. jchdl - GSL Port
  3. [转]配置子报表和钻取报表
  4. 思科防火墙nat-control的作用
  5. 前端js变量踩坑,部分手机浏览器不支持let、const
  6. 微软OTech第二次会议(广州站)
  7. 使用VS2015进行C++开发的6个主要原因
  8. Can't create handler inside thread that has not called Looper.prepare()
  9. android 混淆移除log,关于安卓代码混淆和Release版本中去除Debug信息
  10. Qt:QML:JavaScript 和QML 语法错误表
  11. SG90舵机驱动,有代码
  12. 分享一个小软件fences(桌面管理软件)
  13. 原型工具Axure6.5的使用
  14. Tippy.js - 免费开源且高度可定制的气泡提示独立组件
  15. 深聊性能测试,从入门到放弃之:如何对IO进行性能调优
  16. 【uniapp】解决uni.previewImage图片模糊问题
  17. java毕业设计员工绩效考核系统分析与设计Mybatis+系统+数据库+调试部署
  18. 计算机网络基础教程实训总结,实训总结
  19. 离线地图二次开发(支持所有地图源)
  20. JAVA使用JDBC批量插入SQL

热门文章

  1. eclipse中创建类和包的快捷方式
  2. 集美大学1511,1512软件工程课程作业总结
  3. JCIFS实现单点登录
  4. printf()用法详解(转)
  5. Binder相关面试总结(五):为什么Activity间传递对象需要序列化
  6. ANativeWindow是个什么东西
  7. 看图说OpenGL之二之投影矩阵求法
  8. 解决 Android : Can't convert value at index 4 to dimension: type=0x1
  9. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化-[Android取经之路]
  10. 线程为什么调用start()而不是直接调用run()