---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
HTTP协议
HTTP协议是一种Web通信协议,通过特定的规则来实现服务器跟客户端的通信。HTTP协议有这样几个特点:
(1)面向无连接的,一次只能处理一个请求,HTTP1.0服务器解析完客户端请求并作出应答后,会关闭连接;对于HTTP1.1应答后会等待一个非常短的时间,如果这段时间没有新请求,就会关闭连接。
(2)HTTP协议是无状态的,即对处理过的事务没有记忆能力,它认为每一次请求都是陌生的独立的,为了解决这个问题,Web服务程序引进了cookie机制来维持请求状态。
(3)HTTP协议允许传输任意类型的数据,对于正在传输的数据类型用Content-Type标记。
URL
url需要提供几种信息,一是采用的协议,二是连接的套接字,三是请求文件的路径,后面还可以跟上请求参数
在浏览器中输入www.csdn.net,浏览器会自动帮我们转化为http://www.csdn.net/。
采用的协议,这里已HTTP为例;连接套接字包括ip地址跟端口号,端口号一般都是默认的,不需要我们输入,ip地址我们一般输入域名,然后通过域名服务器解析;请求的路径,一般web程序会提供一个默认路径,如果不输,就是默认的;路径后面还可以跟上GET请求的参数,在请求路径后加上"?"参数之间用“&”连接。一般来说简单的无安全要求的数据,我们直接通过GET方法传递给服务器,而大量的隐私的数据我们通过Post方法传递给服务器。
HTTP请求报文
请求报文分为三个部分,请求行、请求头、请求体,格式都是固定的。如图1.1所示:
请求的方法如下:
(1)GET 请求获取url标识的资源
(2)POST 请求获取url标识的资源并像浏览器传递数据
(3)HEAD 请求服务器对url的响应报头
(4)PUT 请求服务器存储资源,并以url作为其标识
(5)DELETE 请求服务器删除url标识的资源
(6)TRACE 请求服务器返回发送过去的请求,主要用于诊断和测试
HTTP响应报文
响应报文也分为三个部分,响应行、响应头、响应体,如图1.2所示:
响应行包含了协议版本,状态码,和状态码的描述。
状态码是一个百位数,100段表示请求已接受,继续处理;200段表示请求成功;300段表示请求需要做进一步处理,比如说跳转;400段表示请求错误,并且是客户端的原因;500段表示服务器的原因导致了请求错误。
常见的响应码如下:
200 : OK
302 : Found 重定向
400 : Bad Request 错误请求,发出错误的不符合Http协议的请求
401 : Unauthorized 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 : Forbidden 禁止
404 : Not Found 未找到
500 : Internal Server Error 服务器内部错误
503 : Service Unavailable 一般是访问人数过多
常用的类型名:
Server 提供web服务器版本信息;Content-Type 响应的内容的类型 ;Content-Length 响应体的字节长度 ;Connetion 连接的方式信息 ;Accept-Ranges 接收数据的方式,通常是字节数组。
MyWebServer
复习,模拟一个自己的简单服务器程序,步骤如下:
1、接收浏览器发送的请求(socket)
2、分析请求报文(http),请求的路径
3、生成响应报文,响应体
4、发送响应内容
//用的winform,首先搭建一个窗体,点击开始后开始监听。
namespace MyWebServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
void ShowMsg(string str)
{
txtLog.AppendText(str+"\r\n");
}
private void btnStart_Click(object sender, EventArgs e)
{
//点击开始运行,创建一个socket对象并进行监听
IPAddress ip;int p;
if (!IPAddress.TryParse(txtIp.Text, out ip))
{
MessageBox.Show("请输入一个正确的ip地址");
return;
}
if(!int.TryParse(txtPort.Text,out p))
{
MessageBox.Show("请输入一个正确的端口号");
return ;
}
IPEndPoint point = new IPEndPoint(ip, p);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Bind(point);//绑定地址
socket.Listen(10);//开始监听
ShowMsg("开始运行。。。");
//创建一个后台线程接受客户端的连接
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socket);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Listen(object o)
{
Socket socket = o as Socket;
while (true)
{
Socket connSocket = socket.Accept();//通信用的socket
ShowMsg(connSocket.RemoteEndPoint + "连接成功");
//创建一个DataConnection类专门接收请求和发送响应
DataConnection dc = new DataConnection(connSocket, ShowMsg);
}
}
}
}
其中接收和发送请求交给DataConnection
namespace MyWebServer
{
delegate void DelHandler(string str);//用于传递方法ShowMsg
class DataConnection
{
Socket connsocket; DelHandler del; string request;
public DataConnection(Socket socket,DelHandler del)
{
connsocket=socket;
this.del = del;
request = RecRequest();
del(request);//通过委托调用窗体的ShowMsg方法,显示请求报文
//分析请求报文,放在Request类中进行
Request req = new Request(request);
staticPage(req.Url);
}
//处理静态页面,根据请求的路径来判断
void staticPage(string url)
{
string extension = Path.GetExtension(url).TrimStart('.');//获取后缀名
switch (extension)
{
case "html":
case "htm":
case "css":
case "js":
case "jpg":
case "png":
case "gif":
//处理静态页面,生产响应有Response类负责
ProcessStaticPage(url);
break;
case"she":
//处理动态页面
break;
default:
break;
}
}
//处理静态页面
void ProcessStaticPage(string url)
{
//求出绝对路径
string path = AppDomain.CurrentDomain.BaseDirectory + url;
//判断文件是否存在
if (File.Exists(path))
{
using (FileStream fs=new FileStream(path,FileMode.Open))
{
//读取文件
byte[]buffer=new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
//生成响应头,交给Response类
Response response = new Response(200, buffer.Length, url);
connsocket.Send(response.GetResponseHeads());
connsocket.Send(buffer);
connsocket.Close();
del("关闭了连接");
}
}
else
{
//文件不存在,404页面
}
}
void ProcessDTPage(string url)
{
string fileName = Path.GetFileNameWithoutExtension(url);//一般把文件名定义成类名
//获取当前方法所在的命名空间
string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
//类的全名称
string fullName = nameSpace + "." + fileName;
IHttpHandler handler = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;
if (handler != null)
{
//响应体
byte[] buffer = handler.ProcessRequest();
//响应头
Response res = new Response(200, buffer.Length, url);
//发送
connsocket.Send(res.GetResponseHeads());
connsocket.Send(buffer);
connsocket.Close();
del("关闭连接");
}
}
//接收请求报文
string RecRequest()
{
byte[] buffer = new byte[1024 * 1024];
int num=connsocket.Receive(buffer);
return Encoding.UTF8.GetString(buffer,0,num);
}
}
}
分割请求信息得到路径和准备响应头都交给对应的类做了:
class Request
{
string request; public string Url;
public Request(string request)
{
try
{
string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
string first = strs[0];
string[] requstHeads = first.Split( ' ');
Url = requstHeads[1];//请求行中的路径
}
catch (Exception ex)
{
Url = "";
}
}
}
class Response
{
Dictionary<int, string> dic = new Dictionary<int, string>();//存状态码根描述
int stateCode = 200;
int contentLength;
string contentType;
public Response(int stateCode,int contentLength,string url)
{
Fill();
this.stateCode = stateCode;
this.contentLength = contentLength;
GetContentType(url);
}
//生成响应头
public byte[] GetResponseHeads()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("HTTP/1.1 "+stateCode+" "+dic[stateCode]);
sb.AppendLine("Content-Length: " + contentLength);
sb.AppendLine("Content-Type: "+ contentType +";charset=utf-8\r\n");
return Encoding.UTF8.GetBytes(sb.ToString());
}
//根据后缀给contenttype赋值
void GetContentType(string url)
{
//.htm
string ext = Path.GetExtension(url);
switch (ext)
{
case ".htm":
case ".html":
contentType = "text/html";
break;
case ".css":
contentType = "text/css";
break;
case ".js":
contentType = "text/javascript";
break;
case ".jpg":
contentType = "image/jpeg";
break;
default:
contentType = "text/html";
break;
}
}
void Fill()
{
dic.Add(200, "OK");
dic.Add(400, "Not Found");
}
}
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------