第一章 网络应用程序

来源:互联网 发布:mac是什么意思啊 编辑:程序博客网 时间:2024/06/05 19:36

1.1 网络插座Socket
Socket开发网络应用程序时,首先考虑使用网络类型,主要包括以下三个方面:
1)Socket类型,使用网络协议的类别,IPV4的类型为PF_INET;
2)数据通信的类型,常见的数据报(SOCK_DGRAM)、数据流(SOCK_STREAM);
3)使用的网络协议,比如:TCP协议。
在同一个网络地址上,为了区分使用相同协议的不同应用程序,可以为不同的应用程序分配一个数字编号,这个编号为网络端口号(port)。取值范围0-65525。端口号分为三类,第一类是0-1023,称为总所周知的端口,有IANA进行控制和分配,由特定的网络程序使用,例如,TCP协议使用的80号端口来完成HTTP协议的传输。第二类的范围是1024-49151,称为登记端口,这些端口不由IANA控制,但是IANA维护了一个登记的列表,如果没有在IANA登记的话,也不应该在程序中使用,也可以在没有冲突的情况下自定义使用。第三类是49152-65535,称为动态或私有端口,这些由用户程序使用。

public class FreshManSocket    {        public void SimpleWebSocket()        {            //获得本机的loopback网络地址,即127.0.0.1            IPAddress address = IPAddress.Loopback;            //创建可以访问的端口,49152表示端口号,如果设置为0,表示使用一个空闲的端口号            IPEndPoint endPoint = new IPEndPoint(address, 49152);            //创建socket,使用IPv4地址,传输控制协议TCP,双向,可靠,基于连接的字节流            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            //将socket绑定到一个端点上            socket.Bind(endPoint);            //设置连接队列的长度            socket.Listen(10);            Console.WriteLine("开始监听,端口号:{0}。", endPoint.Port);            while (true)            {                //开始监听,这个地方会阻塞线程的执行,知道接受到一个客户端的连接请求                Socket client = socket.Accept();                //输出客户端的地址                Console.WriteLine(client.RemoteEndPoint);                //准备读取客户端请求的数据,读取的数据将保存在一个数组中                byte[] buffer = new byte[4096];                //接受数据                int length = client.Receive(buffer, 4096, SocketFlags.None);                //将请求的数据翻译为UTF-8                Encoding utf8 = Encoding.UTF8;                string requestString = utf8.GetString(buffer, 0, length);                //显示请求的消息                Console.WriteLine(requestString);                //回应的状态行                const string statusLine = "HTTP/1.1 200 OK \r\n";                byte[] statusLineBytes = utf8.GetBytes(statusLine);                //准备发送到客户端的网页                const string responseBody = "<html><head><title>From Socket Server</title></head><body><h1>FreshMan,Hello,My name is world.</h1></body></html>";                byte[] responseBodyBytes = utf8.GetBytes(responseBody);                //回应的头部                string responseHeader = string.Format("Content-Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", responseBody.Length);                byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);                //向客户端发送状态信息                client.Send(statusLineBytes);                //向客户端发送回应头                client.Send(responseHeaderBytes);                //头部与内容的分隔行                client.Send(new byte[] { 13, 10 });                //向客户端发送内容部分                client.Send(responseBodyBytes);                //断开与客户端的连接                client.Close();                if (Console.KeyAvailable)                {                    break;                }            }            socket.Close();        }    }

1.2 基于TCPListener的web服务器
为了简化基于TCP协议的监听程序,.NET在System.Net.Socket命名空间中提供了TCPListener类,使用他,在构造函数中传递一组网络端点信息就可以准备好监听参数,而不再需要设置使用的网络协议细节,调用Start方法之后,监听工作就开始了。AcceptTCPClient方法将阻塞进程,直到一个客户端的连接到达监听器,这个方法将返回一个代表客户端连接的代理对象,它的类型为TCPClient,可以通过它与客户端进行通信。
在输入输出部分,NetworkStream这个派生自Steam对象的字节流对象,对Socket的输入和输出进行了封装。

/// <summary>        /// 使用Socket通信        /// </summary>        public void SimpleTcpListener()        {            //获得本机的loopback网络地址,即127.0.0.1            IPAddress address = IPAddress.Loopback;            //创建可以访问的端口,49152表示端口号,如果设置为0,表示使用一个空闲的端口号            IPEndPoint endPoint = new IPEndPoint(address, 49152);            //TCP监听器            TcpListener newServer = new TcpListener(endPoint);            //启动监听器            newServer.Start();            Console.WriteLine("开始监听,端口号:{0}。", endPoint.Port);            while (true)            {                //等待客户端连接                TcpClient newClient = newServer.AcceptTcpClient();                Console.WriteLine("已建立连接!");                //得到一个网络流                NetworkStream ns = newClient.GetStream();                //将请求的数据翻译为UTF-8                Encoding utf8 = Encoding.UTF8;                byte[] request = new byte[4096];                int length = ns.Read(request, 0, 4096);                string requestString = utf8.GetString(request, 0, length);                //显示请求的消息                Console.WriteLine(requestString);                //回应的状态行                const string statusLine = "HTTP/1.1 200 OK \r\n";                byte[] statusLineBytes = utf8.GetBytes(statusLine);                //准备发送到客户端的网页                const string responseBody = "<html><head><title>From Socket Server</title></head><body><h1>FreshMan,Hello,My name is world.</h1></body></html>";                byte[] responseBodyBytes = utf8.GetBytes(responseBody);                //回应的头部                string responseHeader = string.Format("Content-Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", responseBody.Length);                byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);                //向客户端发送状态信息                ns.Write(statusLineBytes, 0, statusLineBytes.Length);                //向客户端发送回应头                ns.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);                //头部与内容的分隔行                ns.Write(new byte[] { 13, 10 }, 0, 2);                //向客户端发送内容部分                ns.Write(responseBodyBytes, 0, responseBodyBytes.Length);                //断开与客户端的连接                newClient.Close();                if (Console.KeyAvailable)                {                    break;                }            }            newServer.Stop();        }

1.3 基于HttpListener的Web服务器
为了进一步简化HTTP协议的监听器,.NET在命名空间System.Net中提供了HttpListener类。只有在Windows XP SP2或者Server 2003以上的操作系统中才能使用。
HttpListener类进一步简化了监听操作,仅需通过字符串的方法提供监听的地址,端口号,以及虚拟路径,就可以开始监听工作。开始监听后,GetContext方法将阻塞线程,当客户端的请求到达之后,HttpListener返回一个HttpListenerContext对象作为处理客户端请求的总代理,通过代理对象的Request属性,可以得到一个HttpListenerRequest的代表请求参数的对象,这个对象将大多数请求参数进行了对象化。
1.4 Web应用程序域
程序集管理的最小逻辑单位为应用程序域(AppDomain),对于.Net程序来说,可以动态加载程序集到应用程序域中。但是,加载之后的程序集不能单独卸载,只能以应用程序域为单位来整体卸载,应用程序域提供了四个重要的机智。
1)隔离,不同应用程序域之间不能直接访问。跨应用程序域访问的对象必须派生自System.MarshalByRefObject;管理程序将可以得到一个远程对象的代理对象,通过这个代理对象访问位于Web应用程序域中的对象;
2)卸载,被加载的程序集只能以应用程序域为单位卸载;
3)安全,以应用程序域为边界的安全机制;
4)配置,以应用程序域为边界的程序配置。
ApplicationHost类的静态方法CreateApplicationHost可以帮助我们非常简单的创建Web应用程序所需要的应用程序域,并设置所有需要的参数:
public static object CreateApplicationHost(Type hostType,string virtualDir,string physicalDir)其中:
hostType表示用来跨域访问的通信对象,它必须派生自MarshalByRefObject基类;
virtualDir表示网站应用程序的根所对应的虚拟目录;
physicalDir表示网站应用程序所在的文件系统的文件目录;
特别注意:
需要创建一个新的应用程序域,这个应用程序域将重新加载hostType,方法将按照以下顺序来寻找定义hostType类型的程序集;
1)GAC;
2)网站物理文件目录下的bin文件夹
准备用于处理的请求,必须封装为HttpWorkerRequest类型的对象,这是一个抽象类,定义在System.Web命名空间中,类型定义如下:public abstract class HttpWorkerRequest;通过这个类的对象实例,必须提供关于处理请求所需要的信息,以便于服务器处理请求。

System.Web.HttpRunting类是整个ASP.NET服务器处理的入口。提供了一系列的静态属性,反映了web应用程序域的设置信息。属性表:

HttpRuntime的静态方法ProcessRequest将帮助我们开始HTTP的处理之旅。方法定义如下:
Public static void ProcessRequest(HttpWorkerRequest wr)将HttpWorkerRequest对象传递给ProcessRequest方法,ASP.Net就开始服务器的请求处理任务了。
1.5 请求,响应参数的对象类型HttpRequest,HttpResponse
对于每一个请求参数,HttpRuntime将创建一个类型为HttpRequest的对象实例,这个类型定义在命名空间System.Web中:public sealed class HttpRequest。在HTTP的请求消息中,包好三部分内容:请求行、请求头部、请求主体。
HttpMethod表示请求的方式,这是一个只读的属性,返回字符串形式的请求方式;
RawUrl属性表示在HTTP请求消息中的原始请求地址,这是一个字符串形式的请求地址表示方式。

QueryString表示GET请求的参数集合,这是一个NameValueCollection类型的集合,提供两种索引器,可以通过顺序号或参数名称来获取参数的值。对于请求头都保存在一个集合中,这个集合的类型也是NameValueCollection类型,通过Headers属性可以获取到。定义如下:
Public NameValueCollection Headers{get;}
对于消息中的Cookie来说,由于Cookie可能有多个,所以在HttpRequest中通过HttpCookieCollection集合类型表示,这个集合可以通过Cookies属性得到。定义如下:
Public HttpCookieCollection Cookies{get;}
请求Body部分,Form为NameValueCollection的集合。定义如下:
Public NameValueCollection Form{get;}
有多个文件,处理成HttpFileCollection类型的集合,通过Files属性提供。定义如下:
Public HttpFileCollection File{get;}这个集合中的元素类型为HttpPostedFile,public sealed calss HttpPostedFile,重要成员:

向客户端返回请求的回应内容,同样定义代表回应的类型:HttpResponse类,它也定义在System.Web命名空间下,提供向客户端回应的方法和属性。HttpResponse类中的属性和方法:

回应消息中包含了三个部分的内容:状态行、头部、主体部分。对于没有对应属性的回应头,可以通过AddHeader方法来处理。这个方法接收两个字符串类型的参数,一个回应头的名称,一个就是回应头所对应的值。Public void AppendHeader(string name,string value)。
回应的内容部分是通过流来完成的,HttpResponse对象的OutputStream属性引用了输出到HTTP回应的输出流,这个属性定义如下:public Stream OutputStream(get;)
在HTTP的消息中,头部必须在主体部分的前面,所以,在已经输出主体部分之后,是不能再次输出消息头的。默认情况下,HttpResponse对输出的内容进行了缓冲,所以,通过HttpResponse输出的内容并没有立即输出到HTTP中,还可以修改。这时,是可以在使用输出流之后再次设置回应头的。但是,关闭了HttpResponse的缓冲,那么这样做就会报错。HttpResponse的BufferOutput属性是一个bool类型的属性,用于设置是否缓冲输出的内容。
辅助工具类HttpServerUtility提供一些常用的辅助方法。

MapPath方法是使用最多的一个辅助方法,用来将网站中的虚拟路径隐射到操作系统中的文件路径上。
浏览器特征:
Browser:浏览器的名称;
MajorVersion:主要版本;
MinorVersion:次要版本;
ClrVersion:CLR版本;
ActiveXControls:是否支持ActiveX控件;
Cookie:是否支持Cookie;
EcmaScriptVersion:支持的ECMA脚本的版本号;
W3CDowVersion:支持的W3C DOM的版本号。
常见的浏览器的特征文件保存在%System%\Microsoft.Net\Framework\版本\Config\Browsers文件夹下面,以.browser类型的文件形式提供。

1 0
原创粉丝点击