再看.net本质(二)
3.【HTTP协议】 当浏览器寻找到Web服务器的地址之后,浏览器将帮助我们把对服务器的请求转换为一系列参数发送给Web服务器。服务器收到浏览器的请求对数之后,将会分析这些数据并进行处理,然后向浏览器回应处理的结果,也就是一些新的数据:这些数据通常是HTML网页或者图片。浏览器收到之后,解析这些数据,将它们呈现在浏览器的窗口中,就是我们现在看到的网页。 在浏览器与Web服务器的对话中,需要使用双方都能够理解的语法规范进行通信,这种程序之间进行通信的语法规范,我们称之为协议。协议有许许多多种,根据国际标准化组织ISO的网络参考模型,程序与程序之间的通信可以分为7层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。每层都有自己所对应的协议。比如,应用层之间的通信协议,我们称为应用层协议。不同的应用程序可能有着不同的应用层协议。同一层的协议也有许许多多种。 浏览器与Web服务喊叫之间的协议是应用层协议,当前,我们主要遵循的协议为HTTP/1.1。HTTP协议是Web开发的基础,这是一个无状态的协议,客户机与服务器之间通过请求和响应完成一次会话(Session)。每次会话中,通信双方发送的数据称为消息,消息分为两种:请求消息和回应消息。
4【最简单的Web服务器】 在遥远的Unix时代,为了解决传输层的编程问题,从4.2BSD Unix 开始,Unix提供了类似于文件操作的网络操作方式--Socket.通过Socket,程序员可以像操作文件一样通过打开写入读取,关闭等操作完成网络编程。这使得网络编程可以统一到文件操作之下。通过Socket 帮助程序员解决网络传输层的问题,而系统中的网络系统负责处理网络内部的复杂操作,这样程序员就可以比较容易地编写网络应用程序。需要注意的是,应用层的协议需要针对网络程序专门处理,Socket不负责应用层的协议,仅仅负责传输层的协议。 当然,网络毕竟不是简单的文件,所以,在使用Socket的时候,程序员还是需要设置一些网络相关的细节问题参数。 通过Socket开发网络应用程序的时候,首先需要考虑所使用的网络类型,主要包括以下三个方面: 1)Socket类型,使用网络协议的类别,IPv4的类型为PF_INET. 2)数据通信的类型,常见的数据报(sock_dgram),数据流(sock_stream). 3)使用的网络协议,比如:TCP协议。 在同一个网络地址上,为了区分使用相同协议的不同应用程序, 可以为不同的应用程序分配一个数字编号,这个编号称为网络端口号(port)。端口号是一个两字节的整数,取值范围从0到65535.==又分为三类:a:0gc 1023称为众所周知的端口,由特定的网络程序使用,b :第二类范围:1024到49151称为登记端口,这些商品不由IANA控制,c:49152到65535,称为动态或者天愁私有端口,这些端口可以由普通用户程序使用。
对于一个网络应用程序来说,通过地址,协议和端口号可以唯一地确定网络上的一个应用程序。其中地址和端口的组合称为端点(EndPoint).每个Socket 需要绑定到一个端点上与其他端点进行通信。
在.net中,System.Net命名空间提供了网络编程的大多数数据类型以及常用操作,其中常用的类型如下:
1:IPAddress类用来表示一个IP地址。
2:IPEndPoint类用来表示一个IP地址和一个端口号的组合,称为网络的端点。
3:System.Net.Sockets命名空间中提供了基于Socket编程的数据类型。
4:Socket类封装了Socket的操作。
4.1:Listen:设置基于连接通信的Socket进入监听状态,并设置等待队列的长度。
4.2:Accept:等待一个新的连接,当新连接到达的时候,返回一个针对新连接的Socket对象。通过这个新的Socket对象,可以与 新连接通信
4.3:Receive:通过Socket接受字节数据,保存到一个字节数组中,返回实际接收的字节数。
4.4:Send:通过Socket发送预先保存的字节数组中的数据。
下面是用Socket编程一个简单的Web服务器:
// 取得本机的 loopback 网络地址,即 127.0.0.1
IPAddress address = IPAddress.Loopback;
// 创建可以访问的端点,49152 表示端口号 I
PEndPoint endPoint = new IPEndPoint(address, 8008);
// 创建一个 socket,使用 IPv4 地址,传输控制协议 TCP,双向、可靠、基于连接的字节流
System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 将 socket 绑定到一个端点上
socket.Bind(endPoint);
// 设置连接队列的长度
socket.Listen(10);
Console.WriteLine("开始监听, 端口号:{0}.", endPoint.Port);
while (true)
{
// 开始监听,这个方法会阻塞线程的执行,直到接受到一个客户端的连接请求
System.Net.Sockets.Socket client = socket.Accept();
// 输出客户端的地址
Console.WriteLine(client.RemoteEndPoint);
// 准备读取客户端请求的数据,读取的数据将保存在一个数组中
byte[] buffer = new byte[4096];
// 接受数据
int length = client.Receive(buffer, 4096, SocketFlags.None);
// 将请求的数据翻译为 UTF-8
System.Text.Encoding utf8 = System.Text.Encoding.UTF8;
string requestString = utf8.GetString(buffer, 0, length);
// 显示请求的内容
Console.WriteLine(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><h1>Hello, 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();
基于TcpListener的Web服务器 为了简化基于TCP协议的监听程序,.net在System.Net.Sockets命名空间中提供了TcpListener类,使用它,在构造函数中传递一组网络端点信息就可以准备好监听参数,而不再需要设置使用的网络协议等细节,调用start方法之后,监听工作就开始了。AcceptTcpClient方法将阻塞进行,直到一个客户端的连接到达监听器,这个方法将返回一个代表客户端连接的代理对象,它的类型为TcpClient,我们可以通过它与客户端进行通信。
//取得本机的loopback网络地址,即127.0.0.1
IPAddress address=IPAddress.Loopback;
//创建可以访问的端点,49152 表示端口号
IPEndPoint endPoint=new IPEndPoint(address,49152);
//创建TCP监听器
TcpListener newserver=new TcpListener(endPoint);
//启动监听器
newserver.Start();
Console.WritenLine("开始监听 。。。");
while(true)
{
//等待客户端连接
TcpClient newclient=newserver.AcceptTcpClient();
Console.WriteLine("已经建立连接!");
//得到一个网络流
NetworkStream ns=newclient.GetStream();
//处理过程中使用UTF-8编码
System.Text.Encoding utf8=System.Text.Encoding.UTF8;
byte[]request=new byte[]4096; int length=ns.Read(request,0,4096);
string requestString=utf8.GetString(request,0,length);
Console.WriteLine(requestString);
//状态行
string statusLine="HTTP/1.1 200 OK\r\n"; byte[]statusLineBytes=uft8.GetBytes(statusLine); //装备发送到客户端的网页 string responseBody="<html><head><title>From Socket Server</title></head><body><h1> 这些内容是从自定义网页服务器返回过来的</h1></body></html>" //回应的头部 string responseHeader=string.Format("Content_Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n",responseBody.Lenght); 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();
基于HttpListener的Web服务器 为了进一步简化HTTP协议的监听器,.NET在命名空间Systtem.Net中提供了HttpListener类。伴随这个对象,.NET提供了一系列相关对象封装了HTTP的处理工作。注意,这个类使用Http.sys系统组件完成工作,所以,只有在Windows XP SP2或者Server 2003 以上的操作系统中才能使用。 HttpListener类进一步简化了监听操作,公需要通过字符串的方法提供监听的地址,端口号以及虚拟路径,就可以开始监听工作。开始监听后,GetContext方法将阻塞线程,当客户端的请求到达之后,HttpListener返回一个HttpListenerContext对象作为处理客户端请求的总代理,通过代理对象的Request属性,我们可以得到一个类型为HttpListenerRequest的代表请求参数的对象,这个对象将大多数请求参数进行了对象化,所以,我们可以通过它提供的一系列属性来猎取请求参数。例如HttpListenerRequest的HttpMethod属性就提供了请求的方法类型。通过代理的Response属性,可以得到一个类似为HttpListenerResponse的回应处理对象,这个对象将回应的数据和操作进行了封装,使得我们大幅度简化了回应的编程工作量,工作过程如下:
//检查系统是否支持 if(!HttpListener.IsSupported) { throw new System.InvalidOperationException("使用HttpListener 必须为 Windows XP SP2 或 Server 2003 以上系统! "); }
//注意前缀必须以 /正斜杠结尾 string[] prefixes=new string[]{"http://localhost:8008"}; //创建监听器 HttpListener listener=new HttpListener(); //增加监听的前缀 foreach (string s in prefixes) { listener.Prefixes.Add(s); } //开始监听 listener.Start(); Console.WriteLine("监听中。。。"); while(true) { //注意:GetContext方法将阻塞线程,直到请求到达 HttpListenerContext context=listener.GetContext(); //取得请求对象 HttpListenerRequest request=context.Request; Console.WriteLine("{0} {1} HTTP/1.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}",requst.Headers["Accept-Encoding"]); Console.WriteLine("Connection:{0}",request.KeepAlive?"keep-Alive":"close"); Console.WriteLine("Host: {0}",request.UserHostName); Console.WriteLine("Pragmaa:{0}",request.Headers{"Pragma"]); //取得回应对象 HttpListenerResponse response=cotext.Response; //构造回应内容 string responseString=@"<html> <head><title>From HttpListener Server</title></head> <body><h1>Hello,World.</h1></body> </html>"; //设置回应头部内容,长度编码 response.ContentLength64=System.Text.Encoding.UTF8.GetByteCount(responseString); response.ContentType="text/html;charset=UTF-8"; //输出回应内容 System.IO.Stream output=response.OutputStream; System.IO.StreamWriter writer=new System.IO.StreamWriter(output); writer.Write(responseString); //必须关闭输出流 writer.Close(); if(Console.KeyAvailable); break; } //关闭服务器 listener.Stop();
再看.net本质(二)的更多相关文章
- 再看.net本质
1.[资源的地址-通用资源标识符] 我们在地址栏中输入的内容称为通用资源标识符(Universal Resource Identifier,URI),它有很多种形式,在Web中我们通常使用称为统一资源 ...
- python基础----再看property、描述符(__get__,__set__,__delete__)
一.再看property 一个静态属性property ...
- iOS Block的本质(二)
iOS Block的本质(二) 1. 介绍引入block本质 通过上一篇文章Block的本质(一)已经基本对block的底层结构有了基本的认识,block的底层就是__main_block_impl_ ...
- 再看Ajax
再回顾Ajax相关的内容,再次梳理学习还是很有必要的,尤其是实际的开发中,ajax更是必不可少,仔细学习以便避免不必要的错误. 文章导读: --1.使用XMLHttpRequest---------- ...
- 2014年武汉的IT行情好像不太好(续):20个月过后,再看当时面试过的几个公司--武汉财富基石-崩盘,辣妈萌宝-创业失败,朋友公司转交他人管理
2014年9月的时候,写过一篇面试的总结性质的文章,"2014年武汉的IT行情好像不太好". 原文地址:blog.csdn.net/fansunion/article/detai ...
- mysql索引设计的注意事项(大量示例,收藏再看)
mysql索引设计的注意事项(大量示例,收藏再看) 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过ke ...
- 再看ftp上传文件
前言 去年在项目中用到ftp上传文件,用FtpWebRequest和FtpWebResponse封装一个帮助类,这个在网上能找到很多,前台使用Uploadify控件,然后在服务器上搭建Ftp服务器,在 ...
- 再看 AspriseOCR - OCR应用开发 -20151124
再看 AspriseOCR - OCR应用开发 我写这个博文时间为 2015/11/24日,注意时间因为,网上很多文章时间上很久远,有的已经不能参考了 很多人面对从图片中识别文字或者数字0~9 A~ ...
- Android菜鸟的成长笔记(17)—— 再看Android中的Unbounded Service
原文:Android菜鸟的成长笔记(17)-- 再看Android中的Unbounded Service 前面已经写过关于startService(Unbounded Service)的一篇文章:&l ...
随机推荐
- 【转】SQL SERVER标量表达式的隐式转换
在SQL Server中的数据类型中,存在着优先级的问题.标量表达示的返回结果类型也会根据操作数的类型而定,如1 +'1'=2.而不是'11',因些Int型的优先级比VARCHAR型的优先级要高.所以 ...
- [Vue]学习中遇到的疑点
computed:计算属性,官方api上说计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算.但是经过测试并没有缓存.案例: computed: { now: function () { c ...
- PLSQL_性能优化系列08_Oracle Insert / Direct Insert性能优化
2014-09-25 Created By BaoXinjian
- 牢骚 - 你代码写得丑,又不肯用好一点的IDE,这让我很为难啊。
又有人问我代码错误,发过来就是一篇巨丑无比的代码,先不说左大括号转行还和代码写在同一行的谭浩强风格,你这狗啃的一样的缩进是闹哪样!粘进VS2015里面,自动格式化,瞬间赏心悦目,编译错误出了5行,我直 ...
- 使用thinkphp连接sqlserver数据库时提示“系统不支持:sqlsrv”
习惯了使用php跟mysql组合,现在接到项目需要调用客户线下的系统软件的数据,具了解,这个软件的数据库是用sqlserver数据库也就是常说的mssql数据库了. 那么我现在需要用PHP连接sqls ...
- CSS如何实现数字分页效果
代码实例如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- html table单双行颜色间隔(转载)
直接上代码: <html> <head> <meta http-equiv="Content-Type" content="text/htm ...
- C++ 多继承和虚继承的内存布局(转)
转自:http://www.oschina.net/translate/cpp-virtual-inheritance 警告. 本文有点技术难度,需要读者了解C++和一些汇编语言知识. 在本文中,我们 ...
- 解决脱离rails使用activerecord报错 NameError: uninitialized constant ActiveRecord::Migrator::Zlib
上下文说明 原本系统是15.10,无奈只支持1年,所以今天升级16.04,环境答好后运行rake migratte报错 task :default => :migrate desc 'Run m ...
- [Java] 使用转换流来处理标准输入
package test.stream; import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...