C#建立最简单的web服务,无需IIS

原创 2015年07月09日 18:06:41

软件架构师何志丹

本程序只是入门级程序,所以不考虑
1,多线程。
2,安全性。
3,不考虑端点下载文件。
4,Keep-Alive。
5,不考虑head。
6,为了简洁,删掉了catch的内容。

exe的祖父目录必须有wwwroot文件夹,且文件夹有index.htm,内容不限。 
开发环境: WinXP+VS2010C#

一,新建一个项目TestWeb,项目类型:Windows窗口应用程序。
二,新建类RequestProcessor。
 using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace TestWeb
{
    class RequestProcessor
    {
        public bool ParseRequestAndProcess(string[] RequestLines)//解析内容
        {
            for (int i = 0; i < RequestLines.Length; i++)
                System.Diagnostics.Trace.Write(RequestLines[i]);

            char[] sp = new Char[1] { ' ' };
            string[] strs = RequestLines[0].Split(sp);
            if (strs[0] == "GET")
            {
                Send(strs[1], 0, 0);
            }

            return false;
        }

        void Send(string filename, long start, long length)//发送文件(文件头和文件)
        {
            string strFileName = GetPathFileName(filename);
            FileStream fs = null;
            try
            {
                fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

            }
            catch (IOException)// FileNotFoundException)
            {//不能将 e.Message,发给浏览器,否则会有安全隐患的
                SendHeadrAndStr("打开文件" + filename + "失败。");
                return;
            }

            if (length == 0)
                length = fs.Length - start;

            SendHeader("text/html", (fs.Length == length), start, length);
            sendContent(fs, start, length);
        }

        public void SendHeadrAndStr(String str)//直接将str的内容发给html
        {
            byte[] sendchars = Encoding.Default.GetBytes((str).ToCharArray());
            SendHeader("text/html", true, 0, sendchars.Length);
            SendStr(Encoding.Default, str);
        }

        private void SendHeader(string fileType, bool bAll, long start, long length)//发送文件头
        {
            try
            {
                Encoding coding = Encoding.Default;
                string strSend;
                string strState = (bAll) ? "HTTP/1.1 200 OK" : "HTTP/1.1 206 Partial Content";
                SendStr(coding, strState + "\r\n");
                SendStr(coding, "Date: \r\n");
                SendStr(coding, "Server: httpsrv/1.0\r\n");
                SendStr(coding, "MIME-Version: 1.0\r\n");
                SendStr(coding, "Content-Type: " + fileType + "\r\n");


                strSend = "Content-Length: " + length.ToString();
                SendStr(coding, strSend + "\r\n");

                //发送一个空行
                SendStr(coding, "\r\n");
            }
            catch (ArgumentException)//the request is WRONG
            {


            }

        }

        private void sendContent(FileStream fs, long start, long length)//发生文件内容
        {
            try
            {

                //报文头发送完毕,开始发送正文
                const int SOCKETWINDOWSIZE = 8192;
                long r = SOCKETWINDOWSIZE;
                int rd = 0;
                Byte[] senddatas = new Byte[SOCKETWINDOWSIZE];
                fs.Seek(start, SeekOrigin.Begin);
                do
                {
                    r = start + length - fs.Position;
                    //fs.BeginRead(s,s,s,s,d) 以后使用的版本,用以提高读取的效率                
                    if (r >= SOCKETWINDOWSIZE)
                        rd = fs.Read(senddatas, 0, SOCKETWINDOWSIZE);
                    else
                        rd = fs.Read(senddatas, 0, (int)r);
                    mSockSendData.Send(senddatas, 0, rd, SocketFlags.None);
                } while (fs.Position != start + length);

            }
            catch (SocketException e)
            {
                throw e;
            }
            catch (IOException e)
            {
                throw e;
            }
        }



        public Socket mSockSendData;//Notice: get from ClientSocketThread.s





        private string GetPathFileName(string filename)
        {
            const string strDefaultPage = "index.htm";
            const string strWWWRoot = "..\\..\\wwwroot\\";
            string strFileName = String.Copy(filename);
            if ("/" == strFileName)
                strFileName = strDefaultPage;
            return System.AppDomain.CurrentDomain.BaseDirectory + strWWWRoot + strFileName;
        }

        private void SendStr(Encoding coding, string strSend)//发送一个字符串
        {
            Byte[] sendchars = new Byte[512];
            sendchars = coding.GetBytes((strSend).ToCharArray());
            mSockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);
        }
    }
}

三,新建类ClientSocketThread。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace TestWeb
{
    class ClientSocketThread
    {
        public TcpListener tcpl;//Notice: get from SrvMain.tcpl
        private static Encoding ASCII = Encoding.ASCII;

        public void HandleThread()
        {
            Thread currentThread = Thread.CurrentThread;
            try
            {

                Socket s = tcpl.AcceptSocket();


                RequestProcessor aRequestProcessor = new RequestProcessor(); //Notice:
                aRequestProcessor.mSockSendData = s;//Notice: so that the processor can work


                const int BUFFERSIZE = 4096;//that's enough???
                Byte[] readclientchar = new Byte[BUFFERSIZE];
                char[] sps = new Char[2] { '\r', '\n' };
                string[] RequestLines = new string[32];

                do
                {
                    //use BUFFERSIZE contral the receive data size to avoid the BufferOverflow attack
                    int rc = s.Receive(readclientchar, 0, BUFFERSIZE, SocketFlags.None);

                    string strReceive = ASCII.GetString(readclientchar, 0, rc);

                    RequestLines = strReceive.Split(sps);


                } while (aRequestProcessor.ParseRequestAndProcess(RequestLines));

                s.Close();
            }
            catch (SocketException)
            {

            }
        }


    }
}


四,主对话框中增加按钮,按键的相应函数加如下代码。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace TestWeb
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
              try
            {
                //启动监听程序                
                TcpListener tcpl;
                IPAddress LocalIP = Dns.Resolve("localhost").AddressList[0];
                tcpl = new TcpListener(LocalIP, 80); // listen on port 80
                tcpl.Start();
                         

               // int ThreadID = 0;
                while (true)
                {
                    while (!tcpl.Pending())
                    {
                        Thread.Sleep(100);
                    }

                    //启动接受线程
                    ClientSocketThread myThreadHandler = new ClientSocketThread();
                    myThreadHandler.tcpl = tcpl;//Notice: dont forget do this
                    ThreadStart myThreadStart = new ThreadStart(myThreadHandler.HandleThread);
                    Thread myWorkerThread = new Thread(myThreadStart);      
                    myWorkerThread.Start();
                }
            }
            catch (SocketException )
            {
           
            }
            catch (FormatException)
            {
               
            }
            catch (Exception )
            {
               
            }
            //  Console.Read();
       
        }
    }
}

五,启动TestWeb.exe,并单击主对话框上的按钮。在浏览器中输入:http://127.0.0.1/ 或http://127.0.0.1:80。


源码下载:

http://download.csdn.net/detail/he_zhidan/8884733




.net(c#)操作IIS大全

注意使用时要有服务器管理员权限 ,可在Web.config 添加 IISWorker using AppMain.model; using System; using ...
  • idays021
  • idays021
  • 2015年12月09日 16:45
  • 422

Win10下IIS配置图解、MVC项目发布图解、IIS添加网站图解

Win10下IIS配置 1.找到控制面板:【开始】菜单鼠标右击,打开【控制面板】 2.打开控制面板,点击【程序】,点击【启用或关闭Windows功能】 下一步...
  • u010763324
  • u010763324
  • 2016年08月11日 14:58
  • 18334

实测如何使用c#代码判断服务器是否安装iis

做项目时用到判断iis是否安装的问题。查找了相应的资料,并整理实测了一下。亲测可用。 首先项目引用  System.ServiceProcess protected void Page_Load(...
  • mengdong0228
  • mengdong0228
  • 2017年11月30日 19:35
  • 34

C#操作IIS完整解析

原文出处:http://www.cnblogs.com/chenkai/archive/2010/07/26/1785074.html 最近在为公司实施做了一个工具,Silverlight部署早...
  • chelen_jak
  • chelen_jak
  • 2016年08月08日 14:40
  • 963

C#建立最简单的Web服务,无需IIS

  • 2015年07月09日 18:04
  • 18KB
  • 下载

使用C#开发HTTP服务器系列之更简单的实现方式

各位朋友大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com。到目前为止,我已经发布了3篇HTTP服务器开发的系列文章。对我个人而言,我非常享受这个从无到...
  • qinyuanpei
  • qinyuanpei
  • 2016年07月02日 15:56
  • 12688

使用C#开发HTTP服务器系列之Hello World

各位朋友大家好,我是秦元培,欢迎大家关注我的博客。从今天起,我将开始撰写一组关于HTTP服务器开发的系列文章。我为什么会有这样的想法呢?因为人们对Web技术存在误解,认为网站开发是Web技术的全部。其...
  • qinyuanpei
  • qinyuanpei
  • 2016年06月25日 09:12
  • 14814

C# web网站的发布过程

参考:  http://blog.csdn.net/chinahuyong/article/details/47067381 一、选择编译完成的工程,进行如下操作: ...
  • aa2397199142
  • aa2397199142
  • 2016年09月02日 17:32
  • 3269

使用owin不依赖iis 构建自承载的c# web服务器,支持ajax+html+webapi

owin 自承载 html+ajax+webapi 站点
  • xxj_jing
  • xxj_jing
  • 2016年07月22日 11:41
  • 3063

Win10下IIS配置图解、MVC项目发布图解、IIS添加网站图解

Win10下IIS配置 1.找到控制面板:【开始】菜单鼠标右击,打开【控制面板】 2.打开控制面板,点击【程序】,点击【启用或关闭Windows功能】 下一步...
  • u010763324
  • u010763324
  • 2016年08月11日 14:58
  • 18334
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#建立最简单的web服务,无需IIS
举报原因:
原因补充:

(最多只允许输入30个字)