早就很想看这本书了,现在终于下载了一个pdf版的,以后每天要看一些,然后做做笔记。
1,通用资源标识符(Uniform Resource Identifier, 简称"URI"),这是百度百科上的写法,书上把u写成了universal.
2,url是uri的一种,主要是指web中的统一资源定位符。
3,学习一下Uri类,下面是相关的代码:
System.Uri ms = new Uri("http://www.cnblogs.com/wang7/admin/EditPosts.aspx?opt=1"); Console.WriteLine("协议名:{0}", ms.Scheme); Console.WriteLine("主机名:{0},", ms.Host); Console.WriteLine("据对路径:{0}", ms.AbsolutePath); Console.WriteLine("端口号:{0}", ms.Port); Console.WriteLine("参数{0}", ms.Query); Console.Read();
运行结果是:
绝对路径上传到服务器后被成为虚拟路径。
4,http协议是无状态协议
(1)无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
客户端与服务器进行动态交互的Web应用程序出现之后,HTTP无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,而另一个则是Session。
(2)cookie是通过客户端保存一些值,每次请求是都将这些值发送给服务器,这样保持状态。
(3)session是通过服务器端保存一些值,每次当请求过来的时候比对一下这些值来保持状态。
5,传输层从下向上是第4层,有两个重要的协议,tcp和udp,网络编程中要用到。http是第7层应用层.网络层是第3层,有个ip协议。
socket仅仅负责传输层编程。
6,一个简单的socket服务器
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Noesis.Javascript; using System.Net; using System.Net.Sockets; namespace ConsoleTest { class Program { static void Main(string[] args) { IPAddress ip = IPAddress.Loopback;//得到本地巡回地址127.0.0.1 IPEndPoint point = new IPEndPoint(ip, 49155);//得到本地一个端点(ip地址:端口) //新建一个基于tcp和ipv4的socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(point);//将sockey绑定到端点 socket.Listen(10);//监听10个请求 Console.WriteLine("开始监听端口:{0}", point.Port); while (true) { //开始监听,直到接收一个请求,这是一个阻塞方法 Socket client = socket.Accept(); Console.WriteLine(client.RemoteEndPoint);//输出客户端的地址 byte[] buffer = new byte[2048]; int length = client.Receive(buffer, 2048, SocketFlags.None);//接收数据 System.Text.Encoding utf8 = Encoding.UTF8;//得到utf-8编码 string requestString = utf8.GetString(buffer, 0, length);//将字节转为字符串 Console.WriteLine("请求消息是:\n{0}", requestString); string statusLine = "HTTP/1.1 200 OK\r\n";// 状态行 byte[] statusLineBytes = utf8.GetBytes(statusLine);//字符串转为字节数组 string responseBody = "<html><head><title>From Socket Server</title></head><body>Hello JinHe!</body></html>";//响应体 byte[] responseBodyBytes = utf8.GetBytes(responseBody);//字符串转为字节数组 string responseHeader = string.Format( //响应头信息 "Content-Type: text/html; charset=UTF-8;\r\n Content-Length:{0}\r\n", responseBody.Length); byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);//*******就在这个地方写成了responseBody,结果抓包发现响应头内容是响应体的内容 client.Send(statusLineBytes);//向客户端发送状态行 client.Send(responseHeaderBytes);//向客户端发送响应头信息 client.Send(new byte[] { 13, 10 });//响应头和响应内容之间的分隔行,13和10就是回车换行字节 client.Send(responseBodyBytes);//响应内容 client.Close();//关闭连接 if (Console.KeyAvailable)//如果按键可以使用 { break; } } socket.Close();//关闭套接字 } } }
在浏览器中输入http://localhost:49155/ 则浏览器可以看到的结果。
参见:http://www.cnblogs.com/zhili/archive/2012/08/23/WebServer.html
分析:刚开始怎么都不显示响应的网页内容,在网上看到一篇相同的文档,他的显示,我一点一点的对比,调试,还是不显示,本来打算放弃了,后来看到网上说抓包看看,然后我就使用抓包工具抓包,发现响应头的内容居然是响应体,后来发现果然是在获取响应头字节时写成了获取响应体的代码。 越来越发现,抓包工具的重要行。
7,一个基于TcpListener的web服务器:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Noesis.Javascript; using System.Net; using System.Net.Sockets; namespace ConsoleTest { class Program { static void Main(string[] args) { IPAddress ip = IPAddress.Loopback;//得到本地巡回地址127.0.0.1 IPEndPoint endPoint = new IPEndPoint(ip, 49155);//得到本地一个端点(ip地址:端口) TcpListener newServer = new TcpListener(endPoint);//新建一个监听器 newServer.Start();//开始侦听连接请求 while (true) { TcpClient newClient = newServer.AcceptTcpClient();//接收一个客户端请求 Console.WriteLine("已经建立连接"); NetworkStream ns = newClient.GetStream();//返回连接网络流 Encoding utf8 = Encoding.UTF8; byte[] buffer = new byte[4096]; int length = ns.Read(buffer, 0, 4096);//读取数据 string requestString = utf8.GetString(buffer, 0, length);//得到请求的字符串 Console.WriteLine("请求消息是:\n{0}", requestString); string statusLine = "HTTP/1.1 200 OK\r\n";// 状态行 byte[] statusLineBytes = utf8.GetBytes(statusLine);//字符串转为字节数组 string responseBody = "<html><head><title>From Socket Server</title></head><body>Hello JinHe!</body></html>";//响应体 byte[] responseBodyBytes = utf8.GetBytes(responseBody);//字符串转为字节数组 string responseHeader = string.Format( //响应头信息 "Content-Type: text/html; charset=UTF-8;\r\n Content-Length:{0}\r\n", responseBody.Length); byte[] responseHeaderBytes = utf8.GetBytes(responseHeader);//*******就在这个地方写成了responseBody,结果抓包发现响应头内容是响应体的内容 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); ns.Close(); if (Console.KeyAvailable) { break; } } newServer.Stop();//关闭 } } }
这个例子要记住:响应头和响应体之间一定要加一个换行,否则响应体不会显示。
8,基于HttpListener的web服务器:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Noesis.Javascript; using System.Net; using System.Net.Sockets; namespace ConsoleTest { class Program { static void Main(string[] args) { if (!HttpListener.IsSupported) { throw new InvalidOperationException("只用windos sp2或server 2003以上版本可以使用HttpListener"); } //一定在末尾加斜杠 string[] prefixes = new string[] { "http://localhost:49115/"}; HttpListener listener = new HttpListener(); foreach (string s in prefixes) { listener.Prefixes.Add(s);//设施uri前缀 } listener.Start();//开始监听 while (true) { HttpListenerContext context = listener.GetContext();//得到传入的请求 HttpListenerRequest request = context.Request;//得到http请求 Console.WriteLine("Method:{0};RawUrl:{1}", request.HttpMethod, request.RawUrl); Console.WriteLine("Accept:{0}",string.Join(",",request.AcceptTypes)); Console.WriteLine("Accept-Language:{0}", string.Join(",", request.UserLanguages)); Console.WriteLine("User-Agent:{0}", request.UserAgent); Console.WriteLine("Accept-Encoding:{0}", request.Headers["Accept-Encoding"]); Console.WriteLine("Connection:{0}", request.KeepAlive ? "Keep-Alive" : "Close"); Console.WriteLine("Host:{0}", request.UserHostName); Console.WriteLine("Pragram:{0}", request.Headers["Pragram"]); HttpListenerResponse response = context.Response;//得到响应对象 string responseBody = "<html><head><title>From Socket Server</title></head><body>Hello JinHe!</body></html>";//响应体 response.ContentLength64 = Encoding.UTF8.GetByteCount(responseBody);//响应内容长度 response.ContentType = "text/html;charset=utf-8";//响应内容 System.IO.Stream stream = response.OutputStream;//响应输出流 System.IO.StreamWriter writer = new System.IO.StreamWriter(stream);//写入流 writer.Write(responseBody); writer.Close(); if (Console.KeyAvailable) { break; } } listener.Stop(); } } }
9,应用程序域:这是一个比进程小的单元,让一个程序运行的逻辑空间。
一个进程有多个应用程序域,每一个应用程序域中承载一个.NET可执行程序,应用程序域为承载的应用程序提供了深度隔离。如果进程中一个应用程序域失败了,其他的应用程序域也能保持正常。
asp.net将网站应用程序寄宿在一个独立的应用程序域中,以便于管理。
10
GAC:global assembly cache
他的作用是可以存放一些有很多程序都要用到的公共Assembly,例如System.Data、System.Windows.Forms等等。这样,很多程序就可以从GAC里面取得Assembly,而不需要再把所有要用到的Assembly都拷贝到应用程序的执行目录下面。举例而言,如果没有GAC,那么势必每个WinForm程序的目录下就都要从C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705下面拷贝一份System.Windows.Forms.dll,这样显然不如都从GAC里面取用方便,也有利于Assembly的升级和版本控制。
11,System.Web.HttpRuntime类是整个asp.net服务器处理的入口。
每一个应用程序域中都存在这样一个类。它的静态方法ProcessRequest帮助我们开始请求的
处理。只要将HttpWorkerRequest对象传递给这个方法,就可以开始服务器的请求处理了。
(1)请求参数的对象类型HttpRequest,这个类提供了有关请求的属性和方法。
(2)响应参数的对象类型HttpResponse,这个类提供有关响应的属性和方法。
12(1)对于最后一个例子,asp.net服务器,如果要使用AplicationHost.CreateApplicationHost
创建应用程序域,则需要将第一个参数hostType的程序集拷贝到网站的bin目录下,否则报告错误
找不到文件。
(2)CreateApplicationHost的第三个参数需要改为网站目录;
运行之后要在浏览器地址栏中输入:http://localhost:49152/ 然后才可以输出请求信息。
对于类WebServer,它是一个应用程序域,对于他真正的作用我还是不明白,在那个方法里加断点就是不会执行这个类的方法。迷惑????
结束语: