文档章节

ASP.NET那点不为人知的事(三)

 木宛城主
发布于 2015/03/02 19:41
字数 1401
阅读 3
收藏 0
点赞 0
评论 0

有了以下的知识:

ASP.NET那点不为人知的事(一)

ASP.NET那点不为人知的事(二)

想必开发一个小型服务器以不是问题了,功能补复杂,能够响应客户端浏览器的请求,并根据请求文件的类型返回响应的信息,如能处理静态页面、图片、样式、脚本、动态页面等。  

回顾

由于客户端和服务端的通信是通过Socket通信,且它们通信的“语言”是基于Http1.1协议。根据这个线索,我们完全可以自己开发服务器软件,暂且叫他Melodies Server,当然这是一个很简单的样例,和真正的服务器还是有差距的,好,我们进入正题,首先需要了解以下几个知识点:

  • 客户端和服务端是由Socket进行通信,在服务器端需要有监听请求的套接字,他绑定在某个端口号上,如果发现有请求过来,socket.Accept()产生一个套接字和客户端进行通信。
  • 客户端发送的请求(报文)交给服务器软件分析,判断是否为静态页面、图片还是动态aspx文件,若是静态文件能直接返回。
  • 处理动态页面稍稍麻烦,需要反射创建页面类(原因详见ASP.NET那点不为人知的事(二))

 开启服务

public partial class WebServerForm : Form
    {
        public WebServerForm()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        private Socket socketWatch;//负责监听浏览器连接请求的套接字
     
        private Thread threadWatch;//负责循环调用Socket.Accept 监听线程   

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            socketWatch=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            IPAddress address = IPAddress.Parse(txtIPAddress.Text.Trim());
            IPEndPoint endPoint=new IPEndPoint(address,int.Parse(txtPort.Text.Trim()));

            socketWatch.Bind(endPoint);
            socketWatch.Listen(10);

            threadWatch = new Thread(WatchConnect);
            threadWatch.IsBackground = true;
            threadWatch.Start();
        }

        private bool isWatch = true;
        //Dictionary<> 
        void WatchConnect()
        {
            while (isWatch)
            {
                Socket socketConnection=socketWatch.Accept();
                ShowMsg("浏览器:"+socketConnection.RemoteEndPoint.ToString()+",连接成功*********************");
                ConnectionClient connectionClient = new ConnectionClient(socketConnection, ShowMsg);
            }
        }

        void ShowMsg(string msg)
        {
            txtLog.AppendText(msg+"\r\n");
        }
        

    }

分析报文,处理请求 

  • 在异步线程创建的与客户端通信的Socket,它的主要职责就是分析保文:
/// <summary>
    /// 与客户端连接通信类(包含一个与客户端通信的套接字和通信线程)
    /// </summary>
    public class ConnectionClient
    {
        private Socket socketMsg;//与客户端通信套接字
        private Thread threadMsg;//通信线程

        private DGShowMsg dgShowMsg;//负责向主窗体文本框显示消息的委托
        public ConnectionClient(Socket socket,DGShowMsg dgShowMsg)
        {
            this.socketMsg = socket;
            this.dgShowMsg = dgShowMsg;

            //负责启动一个接受客户端浏览器请求报文的线程
            threadMsg = new Thread(ReceiveMsg);
            threadMsg.IsBackground = true;
            threadMsg.Start();
        }

        private bool isRec = true;
        void ReceiveMsg()
        {
            while (isRec)
            {
                byte[] arrMsg=new byte[1024*1024*3];
                //接受对应客户端发送过来的请求报文
                int length = socketMsg.Receive(arrMsg);

                string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, length);
                dgShowMsg(strMsg);
                //处理报文
                string[] arrStr = strMsg.Replace("\r\n", "韘").Split('韘');
                string[] firstRow=arrStr[0].Split(' ');
                string requestFile = firstRow[1];
                ExcuteRequest(requestFile);//todo:长连接多少时间
            }
        }
        private void ExcuteRequest(string requestFile)
        {
            //获得被请求页面的后缀名
            string fileExtension = System.IO.Path.GetExtension(requestFile);
            if (!string.IsNullOrEmpty(fileExtension))
            {
                switch (fileExtension.ToLower())
            {
                    case ".html":
                    case ".htm":
                    case ".css":
                    case ".js":
                   
                    ExcuteStaticPage(requestFile,fileExtension);
                    break;
                    case ".jpg":
                    ExcuteImg(requestFile,fileExtension);
                    break;
                    case ".aspx":
                    ExcuteDymPage(requestFile,fileExtension);
                    break;
            }
            }
        }
  •   针对不同的请求执行不同的操作,其中静态页面、css、js、图片处理操作一样,都是属性静态文件,直接返回字节流:
/// <summary>
        /// 处理静态页面,直接输出
        /// </summary>
        private void ExcuteStaticPage(string requestPath,string fileExtension)
        {
            StringBuilder sb=new StringBuilder();
            //获得请求文件的文件夹的物理路径
            string dataDir = AppDomain.CurrentDomain.BaseDirectory;
            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release\"))
            {
                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
            }
            string phyPath = dataDir + requestPath;
            //读取静态页面内容
            string fileContent = System.IO.File.ReadAllText(phyPath);
            //获得响应体字节数组
            byte[] fileArr = System.Text.Encoding.UTF8.GetBytes(fileContent);

            //获得响应报文头:
            string responseHeader = GetResponseHeader(fileArr.Length, fileExtension);
            byte[] arrHead = System.Text.Encoding.UTF8.GetBytes(responseHeader);
            //发送响应报文头回浏览器
            socketMsg.Send(arrHead);
            //发送响应报文体回浏览器
            //todo:sleep 1分钟会怎样
            socketMsg.Send(fileArr);
        }
        /// <summary>
        /// 处理图片
        /// </summary>
        /// <param name="requestPath"></param>
        /// <param name="extentionName"></param>
        private void ExcuteImg(string requestPath, string extentionName)
        {
            //获得请求文件的文件夹的物理路径
            string dataDir = AppDomain.CurrentDomain.BaseDirectory;
            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release"))
            {
                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
            }
            //获得请求文件的物理路径(绝对路径)
            string phyPath = dataDir + requestPath;
            int imgLength;
            byte[] fileArr;
            //读取图片内容
            using (FileStream fs = new FileStream(phyPath, FileMode.Open))
            {
                fileArr = new byte[fs.Length];
                imgLength = fs.Read(fileArr, 0, fileArr.Length);
                //获得响应报文头
                string responseHeader = GetResponseHeader(imgLength, extentionName);
                byte[] arrHeader = System.Text.Encoding.UTF8.GetBytes(responseHeader);
                socketMsg.Send(arrHeader);
                socketMsg.Send(fileArr, imgLength, SocketFlags.None);
            }
        }
        /// <summary>
        /// 得到响应头信息
        /// </summary>
        /// <param name="contentLength"></param>
        /// <param name="fileExtentionName"></param>
        /// <returns></returns>
        private string GetResponseHeader(int contentLength,string fileExtentionName)
        {
            StringBuilder sbHeader=new StringBuilder();
            sbHeader.Append("HTTP/1.1 200 OK\r\n");
            sbHeader.Append("Content-Length: "+contentLength+"\r\n");
            sbHeader.Append("Content-Type:" + GetResponseHeadContentType(fileExtentionName) + ";charset=utf-8\r\n\r\n");
            return sbHeader.ToString();
        }
        /// <summary>
        /// 根据后缀名获取响应保文中的内容类型
        /// </summary>
        /// <param name="fileExtentionName"></param>
        /// <returns></returns>
        private string GetResponseHeadContentType(string fileExtentionName)
        {
            switch (fileExtentionName.ToLower())
            {
                case ".html":
                case ".htm":
                case ".aspx":
                    return "text/html";
                    break;
                case ".css":
                    return "text/plain";
                    break;
                case ".js":
                    return "text/javascript";
                    break;
                case ".jpg":
                    return "image/JPEG";
                case ".gif":
                    return "image/GIF";
                    break;
                default:
                    return "text/html";
                    break;

            }
        }
  • 同样,针对动态页面反射创建其页面类,注意记得让其实现IHttpHandler接口
  • 创建一个页面类View
public class View:IHttpHandler
    {
        public string ProcessRequest()
        {
            string dataDir = AppDomain.CurrentDomain.BaseDirectory;
            //获得模板物理路径
            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release"))
            {
                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
            }
            string phyPath = dataDir + "/model.htm";
            string modelContent=System.IO.File.ReadAllText(phyPath);
            modelContent = modelContent.Replace("@Title", "动态页面").Replace("@Content", "反射创建页面类");
            return modelContent;
        }
    }
  • 反射View,调用其ProcessRequest方法执行服务端代码
/// <summary>
        /// 反射创建动态页面对象
        /// </summary>
        /// <param name="requestFile"></param>
        /// <param name="extentionName"></param>
        private void ExcuteDymPage(string requestFile, string extentionName)
        {
            string pageClassName = System.IO.Path.GetFileNameWithoutExtension(requestFile);
            string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            //获得页面类全名称
            pageClassName = assemblyName + "." + pageClassName;
            //通过反射创建页面类对象
            object pageObj = Assembly.GetExecutingAssembly().CreateInstance(pageClassName);
            IHttpHandler page = pageObj as IHttpHandler;
            byte[] fileArr=null;
            if (page!=null)
            {
                string strHtml=page.ProcessRequest();
                fileArr= System.Text.Encoding.UTF8.GetBytes(strHtml);
            }
            //获得响应报文头
            string responseHeader = GetResponseHeader(fileArr.Length, extentionName);
            byte[] arrHeader = System.Text.Encoding.UTF8.GetBytes(responseHeader);

            socketMsg.Send(arrHeader);
            socketMsg.Send(fileArr);


        }

  总结

至此,一个小型的服务器软件就构建好了,赶紧测试一下呵呵。

© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 222
码字总数 199010
作品 0
黄浦
[本周] 就来说说Asp.net 身份验证、授权

[本周]如约而至;时间是争取来的,这回的[本周]是把若干零碎的时间利用起来成文的,完成对Asp.net身份验证、访问授权等内容的梳理,可能漏掉的东西会比较多,漏掉的还是希望大家来补充。顺便说...

唐玄奘
2017/12/03
0
0
OSChina 技术周刊第八期 —— 10 大常见的 web 开发错误

每周技术抢先看,总有你想要的! 移动开发 【翻译】实现 iOS 上的井字游戏 前端开发 【软件】Twemoji —— Twitter 开源其完整的 Emoji 表情 【软件】LokiJS —— 高性能的 JavaScript 数据库...

OSC编辑部
2014/11/09
3.5K
5
ASP.NET MVC 随笔汇总

ASP.NET MVC 随笔汇总 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的。 学前篇之: ASP.NET MVC学前篇之扩展方法、链式编程 ASP.NET MVC学前篇之Lambda表达式、...

jinyuan0829
2014/08/03
0
0
session共享那点事

二、如何实现session的共享? 首先我们应该明白,为什么要实现共享,如果你的网站是存放在一个机器上,那么是不存在这个问题的,因为会话数据就在这台机器,但是如果你使用了负载均衡把请求分...

yagujj
2015/09/16
29
0
MVC 框架--ASP.NET MVC

ASP.NET MVC在现有的ASP.NET 3.5运行时的基础上提供了一个新的MVC框架。开发人员可以用MVC设计模式来构建Web应用,做到清晰的概念分离(UI或者视图与业务应用逻辑分离, 应用逻辑和后端数据分...

匿名
2009/04/03
57.8K
1
分享33本关于.net方面的学习书籍(免费下载)

分享33本关于.net方面的学习书籍(免费下载) 1、程序员大本营.Net版(中文文档) 2、NHibernate2.0中文文档 3、C#+WinForm视频播放器(AxWindowsMediaPlayer) 4、C#+简单视频播放器 5、ASP.NET...

邓剑彬
2012/12/02
1K
2
ASP.NET MVC和jQuery系列一:入门篇

我是ASP.NET MVC的新手,看了ASP.NET MVC和jQuery系列的几篇文章感觉不错,分享给大家,如果翻译的有问题请指出,谢谢。 原文连接:http://www.codeproject.com/Articles/74338/ASP-NET-MVC-a...

王二狗子11
01/01
0
0
自学MVC看这里——全网最全ASP.NET MVC 教程汇总

MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC。小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC技术的学习者提供一个整合学习入口。本文从Why,W...

葡萄城控件技术团队
2016/08/18
204
0
How ASP.NET MVC Works?[持续更新中…]

一、ASP.NET + MVC IIS与ASP.NET管道 MVC、MVP以及Model2[上篇] MVC、MVP以及Model2[下篇] ASP.NET MVC是如何运行的[1]: 建立在“伪”MVC框架上的Web应用 ASP.NET MVC是如何运行的[2]: URL路...

长平狐
2012/09/04
49
0
春哥技术博客来谈谈php源码加密那点事

今天春哥技术博客给大家谈谈源码加密的那些事。加密就是阻碍进步的,asp.net就是因为都编译后发布,导致优秀源码少。 php源码比较常用有 Zend公司的ZendGuard 和 ionCube公司的ionCube PHP E...

cyrepair
2017/06/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
今天
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部