js跨域总结与解决办法

原文链接
什么是跨域
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。这里把涉及到跨域的一些问题简单地整理一下:

首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:

特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。
接下来简单地总结一下在“前台”一般处理跨域的办法,后台proxy这种方案牵涉到后台配置,这里就不阐述了,有兴趣的可以看看yahoo的这篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls》

1、document.domain+iframe的设置
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。当然这种办法只能解决主域相同而二级域名不同的情况,如果你异想天开的把script.a.com的domian设为alibaba.com那显然是会报错地!代码如下:

www.a.com上的a.html

document.domain = ‘a.com’;
var ifr = document.createElement(‘iframe’);
ifr.src = ‘http://script.a.com/b.html‘;
ifr.style.display = ‘none’;
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
alert(doc.getElementsByTagName(“h1”)[0].childNodes[0].nodeValue);
};
script.a.com上的b.html

document.domain = ‘a.com’;
这种方式适用于{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何页面相互通信。

备注:某一页面的domain默认等于window.location.hostname。主域名是不带www的域名,例如a.com,主域名前面带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。 domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。

问题:
1、安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。
2、如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。
2、动态创建script
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。具体的做法可以参考YUI的Get Utility

这里判断script节点加载完毕还是蛮有意思的:ie只能通过script的readystatechange属性,其它浏览器是script的load事件。以下是部分判断script加载完毕的方法。

js.onload = js.onreadystatechange = function() {
if (!this.readyState || this.readyState === ‘loaded’ || this.readyState === ‘complete’) {
// callback在此处执行
js.onload = js.onreadystatechange = null;
}
};
3、利用iframe和location.hash
这个办法比较绕,但是可以解决完全跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改变hash并不会导致页面刷新,所以可以利用hash值来进行数据传递,当然数据容量是有限的。假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息,cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面,这时的hash值可以做参数传递用。cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;Firefox可以修改)。同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。代码如下:

先是a.com下的文件cs1.html文件:

function startRequest(){
var ifr = document.createElement(‘iframe’);
ifr.style.display = ‘none’;
ifr.src = ‘http://www.cnblogs.com/lab/cscript/cs2.html#paramdo‘;
document.body.appendChild(ifr);
}

function checkHash() {
try {
var data = location.hash ? location.hash.substring(1) : ‘’;
if (console.log) {
console.log(‘Now the data is ‘+data);
}
} catch(e) {};
}
setInterval(checkHash, 2000);
cnblogs.com域名下的cs2.html:

//模拟一个简单的参数处理操作
switch(location.hash){
case ‘#paramdo’:
callBack();
break;
case ‘#paramset’:
//do something……
break;
}

function callBack(){
try {
parent.location.hash = ‘somedata’;
} catch (e) {
// ie、chrome的安全机制无法修改parent.location.hash,
// 所以要利用一个中间的cnblogs域下的代理iframe
var ifrproxy = document.createElement(‘iframe’);
ifrproxy.style.display = ‘none’;
ifrproxy.src = ‘http://a.com/test/cscript/cs3.html#somedata‘; // 注意该文件在”a.com”域下
document.body.appendChild(ifrproxy);
}
}
a.com下的域名cs3.html

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等……

4、window.name实现的跨域数据传输
文章较长列在此处不便于阅读,详细请看 window.name实现的跨域数据传输。

5、使用HTML5 postMessage
HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
a.com/index.html中的代码:


b.com/index.html中的代码:


参考文章:《精通HTML5编程》第五章——跨文档消息机制、https://developer.mozilla.org/en/dom/window.postmessage

6、利用flash
这是从YUI3的IO组件中看到的办法,具体可见http://developer.yahoo.com/yui/3/io/。
可以看在Adobe Developer Connection看到更多的跨域代理文件规范:ross-Domain Policy File Specifications、HTTP Headers Blacklist。

js跨域请求

js跨域请求,原文地址

  1. 同源策略

    所有的浏览器都遵守同源策略,这个策略能够保证一个源的动态脚本不能读取或操作其他源的http响应和cookie,这就使浏览器隔离了来自不同源的内容,防止它们互相操作。所谓同源是指协议、域名和端口都一致的情况。举例来说,首先在Nginx上配置两个虚拟主机,一个监听80端口,另一个监听81端口:
    

    [plain] view plain copy print?
    server {

    listen 80;  
    server_name localhost;  
    
    location / {  
        root   D:/dev/workspace;  
                index  index.html index.htm;  
    }  
    
    location ~ \.php$ {  
        # 委托给后端的php  
        }  
    

    }

    81端口的server配置是类似的,只是端口不同而已,所以通过80和81端口会访问到相同的东西。写两个php,一个是用于页面展示的show_person.php,另一个是用于生成json数据的person.php。
    

    [php] view plain copy print?
    // show_person.php








[php] view plain copy print?
// person.php

<?php
$person = array(‘name’ => ‘kobe’, ‘age’ => 34);
echo json_encode($person);
?>
注意show_person.php中通过jQuery的getJSON请求http://localhost:80/MongoTest/person.php,这里是80端口。
然后先访问80端口试试,键入url:http://localhost/cross_domain/show_person.php。会弹出对话框,显示:kobe, your age is 34。
然后再访问81端口,http://localhost:81/cross_domain/show_person.php,结果出错:
XMLHttpRequest cannot loadhttp://localhost/MongoTest/person.php. Origin http://localhost:81 is not allowed by Access-Control-Allow-Origin.

这就是同源策略作用的效果。因为浏览器中访问的是81端口的内容,而show_person.php中请求的是80端口,所以请求的是不同源的内容,浏览器直接阻止这次请求。
  1. 打破同源策略的限制
    浏览器会阻止ajax请求非同源的内容,但没有限制<script>标签来访问非同源的内容,也没有限制使用动态添加<script>标签,所以可以采用这种方式打破这种限制。先测试下<script>访问非同源的内容,修改show_person.php,如下:
    
    [php] view plain copy print?
    // show_person.php




    <script type="text/javascript" src="http://localhost:80/MongoTest/person.php" ></script>  
</head>  
<body>  
</body>  


还需要对person.php略微修改,以实现函数调用:
[php] view plain copy print?
// person.php

<?php
$person = array(‘name’ => ‘kobe’, ‘age’ => 34);
echo ‘sayHello(‘.json_encode($person).’)’;
?>
实际上,通过之间。访问80和81端口,都会得到希望得到的结果:kobe, your age is 34。
下面就看一下,动态添加





person.php再做修改:
[php] view plain copy print?
// person.php

<?php
$person = array(‘name’ => ‘kobe’, ‘age’ => 34);
echo $_REQUEST[‘callback’].’(‘.json_encode($person).’)’;
?>
通过81端口访问,发现也会打印出结果。这就实现了跨域请求,可以通过firefox的firebug或者chrome的js控制台查看html元素发现,在head元素上多了一个

  1. JSONP
    实际上,上面的例子就是一个JSONP的简单实现。JSONP(JSON with Padding)就是服务器端和客户端互相协作以完成跨域请求的一种协议,客户端向服务器端发送请求并附带callback函数,服务器端返回相应的js代码,这个代码就是执行回调函数,参数就是服务器端返回的JSON数据。上面例子中的person.php就是服务端的简单实现,返回的响应内容是sayHello({"name":"kobe","age":34}),这段内容会被客户端插入到动态生成的script标签内部。
    客户端在发起跨域请求时,需要制定具体的回调函数,比如这个请求http://localhost:80/MongoTest/person.php?callback=sayHello,callback就是回调函数,服务器端也要通过callback要提取回调函数名,所以具体的这个参数需要客户端和服务器端达成一致,否则不能实现跨域。
    在jQuery中拥有对JSONP的支持,只要在使用jQuery.getJSON方法时传入的url的格式是url?callback=?即可,jQuery会自动的将?替换成具体的回调函数名。上面例子的功能,可以采用jQuery改写成:
    
    [javascript] view plain copy print?
    $.getJSON(‘http://localhost:80/MongoTest/person.php?callback=?‘, function(data){
    sayHello(data);
    });
    访问81端口,可以得到正确的响应。观察一下,发现person.php的响应内容是:
            jQuery17103600438670255244_1331202380099({"name":"kobe","age":34})
    前面的jQuery17103600438670255244_1331202380099就是jQuery动态生成的回调函数名,然后在这个回调函数内容调用后面定义的匿名函数,并将得到的JSON数据传进去。jQuery可以优化JSONP请求,如果向同一个源发出请求,jQuery 就将其转化为普通 Ajax 请求。
    

浏览器拦截跨域请求处理方法

浏览器拦截跨域请求处理方法(同源策略不允许读取XXX上的远程资源)

解决此类问题,最直接的方法就是,就是给被请求的服务器,添加HTTP头响应头,这里提供两种添加HTTP头的方法:

  • 第一种,就是在程序中添加HTTP头:

如: Response.Headers.Add(“Access-Control-Allow-Origin”, ““);
添加此段代码的目的很简单,也就是告诉浏览器,这个资源是运行远程所有域名访问的。当然,此处的
也可以替换为指定的域名,出于安全考虑,建议将*替换成指定的域名。

  • 第二种,就是在服务器上,添加HTTP响应头。在这里,我们就以IIS6.0为例:

    在被请求的网站上,设置HTTP头,添加“

Access-Control-Allow-Origin
值为:*或指定的域名。

一般完成以上工作,就可以了。网上还有说在被请求服务器根目录下创建:”crossdomain.xml”的文件。内容格式如下:

1
2
3
4
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

套接字

源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务。
套接字

  套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程。应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。

区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。Socket原意是 “插座”。通过将这3个参数结合起来,与一个“插座”Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

 每一个基于TCP/IP网络通讯的程序(进程)都被赋予了唯一的端口和端口号,端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的端口号保留给标准应用程序,比如pop3的端口号就是110,每一个套接字都组合进了IP地址、端口、端口号,这样形成的整体就可以区别每一个套接字。关于WinSock中的套接字接发缓冲区的大小,可以通过WSA:getsockopt/setsockopt 来读取并设置。

Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另外一个Socket中,使这段信息能传送到其他程序中。一般一个server服务器对应很多客户端client连接,则服务器必须维护一张客户连接列表,每增加一个客户端连接服务器端都要新建一个套接字负责与新增客户端进行对话通信。

套接字主要有两类:流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。流类型的套接字是为需要可靠连接的应用程序设计的。这些程序通常使用连续的数据流。用于这种类型套接字的协议是TCP,适合FTP这类实现。流套接字是最常用的,一些众所周知的协议如HTTP、TCP、SMTP、POP3等都是用它。

 数据报套接字使用UDP做为下层协议,是无连接的,有一个最大缓冲区大小(数据包大小的最大值)。它是为那些需要发送小数据包,并且对可靠性要求不高的应用程序设计的。与流式套接字不同,数据报套接字并不保证数据会到达终端,也不保证它是以正确的顺序到来的。数据报套接字的传输效率相当高,它经常用于音频或视频应用程序。对这些程序来说,速度比可靠性更加重要。

以下为基于Socket的C/S通信模式图:

(1)同步和异步问题

同步方式指发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式,它是一种阻塞模式;而异步指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式,它是非阻塞模式。

关于同步和异步,参考以下实例:

举例1:手机的通讯

手机打电话时同步,发短信是异步。

举例2:请你吃饭

同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。

异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。

举例3:Windows消息处理

SendMessage同步:把一条消息投放到创建hWnd窗口的线程的消息队列中,直到消息被处理完毕才返回。

PostMessage异步:把一条消息投放到创建hWnd窗口的线程的消息队列中,不等消息被处理就立即返回。

举例4:B/S交互

普通B/S模式同步:提交请求->等待服务器处理(这期间客户浏览器不能干任何其他事情)->处理完毕返回。

AJAX技术异步: 请求通过事件触发->服务器处理(这期间浏览器仍然可以作其他事情)->处理完毕。

(2)基于socket的C/S结构程序设计

套接字的本质是通信过程中所要使用的一些缓冲区及一些相关的数据结构。

1).服务器创建监听套接字,并为它关联一个本地地址(IP和端口Port),然后进入监听状态准备接受客户的连接请求。为了接受客户的连接请求,服务器必须调用accept函数。服务器端每接收到一个客户端连接就新建一个套接字负责与该客户会话。

2).客户端创建套接字后即可调用connect函数去试图连接服务器监听套接字。当服务器端的accept函数返回后,connect函数也返回。此时客户方使用socket函数创建的套接字clientSocket,服务器方使用accept返回的套接字serverSocket,双方就可以通信了。

(3)关于服务器端监听套接字和accept返回的新的套接字的区别

一个连接由server_ip, server_port, client_ip, server_port唯一确定。你可用getsockname和getpeername由某个socket取得。

关于监听套接字和accept返回的新的套接字的区别,借用以下情景说明。好比你去吃饭,饭馆门迎小姐(监听SOCKET)看到你来后和你打招呼,然后(ACCEPT)找来一个服务员小姐(NEW SOCKET)伺候你,然后守在门口继续欢迎(监听)下一个。当然门迎小姐会记录是哪一位服务员小姐招待了你;如再有新客人来,门迎小姐(同一监听SOCKET)又会安排另一位服务员小姐(NEW SOCKET)伺候。门迎小姐走了,伺候每一位客人的服务员小姐不受影响。从以上情景可知连接建立后,客户端用发出连接的那个SOCKET向服务器发数据,是发给服务器新创建的SOCKET,而不是服务器的监听SOCKET。服务器的监听SOCKET永远只是用来接受连接请求。

TCP协议与UDP协议的区别

TCP协议与UDP协议的区别转载地址

首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信!

TCP/IP协议是一个协议簇。里面包括很多协议的。UDP只是其中的一个。之所以命名为TCP/IP协议,因为TCP,IP协议是两个很重要的协议,就用他两命名了。

  • TCP/IP协议集包括应用层,传输层,网络层,网络访问层。

  • 其中应用层包括:

    超文本传输协议(HTTP):万维网的基本协议.
    文件传输(TFTP简单文件传输协议):
    远程登录(Telnet),提供远程访问其它主机功能,它允许用户登录
    internet主机,并在这台主机上执行命令.
    网络管理(SNMP简单网络管理协议),该协议提供了监控网络设备的方法,以及配置管理,统计信息收集,性能管理及安全管理等.
    域名系统(DNS),该系统用于在internet中将域名及其公共广播的网络节点转换成IP地址.

  • 其次网络层包括:

    Internet协议(IP)
    Internet控制信息协议(ICMP)
    地址解析协议(ARP)
    反向地址解析协议(RARP)
    最后说网络访问层:网络访问层又称作主机到网络层(host-to-network).网络访问层的功能包括IP地址与物理地址硬件的映射,以及将IP封装成帧.基于不同硬件类型的网络接口,网络访问层定义了和物理介质的连接.

当然我这里说得不够完善,TCP/IP协议本来就是一门学问,每一个分支都是一个很复杂的流程,但我相信每位学习软件开发的同学都有必要去仔细了解一番。

  • 下面我着重讲解一下TCP协议和UDP协议的区别。

TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。

一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,只简单的描述下这三次对话的简单过程:主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;主机B向主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。
详细点说就是:(文章部分转载http://zhangjiangxing-gmail-com.iteye.com,主要是这个人讲解得很到位,的确很容易使人理解!)

  • TCP三次握手过程

    1 主机A通过向主机B 发送一个含有同步序列号的标志位的数据段给主机B ,向主机B 请求建立连接,通过这个数据段,
    主机A告诉主机B 两件事:我想要和你通信;你可以用哪个序列号作为起始数据段来回应我.
    2 主机B 收到主机A的请求后,用一个带有确认应答(ACK)和同步序列号(SYN)标志位的数据段响应主机A,也告诉主机A两件事:
    我已经收到你的请求了,你可以传输数据了;你要用哪佧序列号作为起始数据段来回应我
    3 主机A收到这个数据段后,再发送一个确认应答,确认已收到主机B 的数据段:”我已收到回复,我现在要开始传输实际数据了
    这样3次握手就完成了,主机A和主机B 就可以传输数据了.

  • 3次握手的特点

    没有应用层的数据
    SYN这个标志位只有在TCP建产连接时才会被置1
    握手完成后SYN标志位被置0

  • TCP建立连接要进行3次握手,而断开连接要进行4次

1 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求
2 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1
3 由B 端再提出反方向的关闭请求,将FIN置1
4 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束.
由TCP的三次握手和四次断开可以看出,TCP使用面向连接的通信方式,大大提高了数据通信的可靠性,使发送数据端
和接收端在数据正式传输前就有了交互,为数据正式传输打下了可靠的基础

  • 名词解释
  1. ACK TCP报头的控制位之一,对数据进行确认.确认由目的端发出,用它来告诉发送端这个序列号之前的数据段都收到了.比如,确认号为X,则表示前X-1个数据段都收到了,只有当ACK=1时,确认号才有效,当ACK=0时,确认号无效,这时会要求重传数据,保证数据的完整性.

  2. SYN 同步序列号,TCP建立连接时将这个位置1

  3. FIN 发送端完成发送任务位,当TCP完成数据传输需要断开时,提出断开连接的一方将这位置1

  • TCP的包头结构:

    源端口 16位
    目标端口 16位
    序列号 32位
    回应序号 32位
    TCP头长度 4位
    reserved 6位
    控制代码 6位
    窗口大小 16位
    偏移量 16位
    校验和 16位
    选项 32位(可选)

这样我们得出了TCP包头的最小长度,为20字节。

UDP(User Data Protocol,用户数据报协议)

(1) UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。


(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。


(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。


(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。


(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。


(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。

我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。

  • UDP的包头结构:

    源端口 16位
    目的端口 16位
    长度 16位
    校验和 16位

小结TCP与UDP的区别:

  1. 基于连接与无连接;

  2. 对系统资源的要求(TCP较多,UDP少);

  3. UDP程序结构较简单;

  4. 流模式与数据报模式 ;

  5. TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

用sublime text 编辑markdown

用sublime text 2 编辑markdown文件,只需要安装两个插件

Markdown to Clipboard
MarkdownBuild

安装之后不需要任何配置,编写好md文件之后,

ctrl+b 就可以在默认浏览器中查看效果
右键菜单中,有copy Markdown as Html,输出也方便
Markdown简明语法

http信息含义

转载地址

HTTP头标

头标由主键/值对组成。它们描述客户端或者服务器的属性、被传输的资源以及应该实现连接。

  • 四种不同类型的头标:

    1.通用头标:即可用于请求,也可用于响应,是作为一个整体而不是特定资源与事务相关联。
    2.请求头标:允许客户端传递关于自身的信息和希望的响应形式。
    3.响应头标:服务器和于传递自身信息的响应。
    4.实体头标:定义被传送资源的信息。即可用于请求,也可用于响应。

头标格式::

  • 下面描述在HTTP/1.1中用到的头标

Accept 定义客户端可以处理的媒体类型,按优先级排序;
在一个以逗号为分隔的列表中,可以定义多种类型和使用通配符。例如:Accept: image/jpeg,image/png,/
Accept-Charset
定义客户端可以处理的字符集,按优先级排序;
在一个以逗号为分隔的列表中,可以定义多种类型和使用通配符。例如:Accept-Charset: iso-8859-1,*,utf-8

Accept-Encoding 定义客户端可以理解的编码机制。例如:Accept-Encoding:gzip,compress
Accept-Language 定义客户端乐于接受的自然语言列表。例如:Accept-Language: en,de

Accept-Ranges
一个响应头标,它允许服务器指明:将在给定的偏移和长度处,为资源组成部分的接受请求。
该头标的值被理解为请求范围的度量单位。例如Accept-Ranges: bytes或Accept-Ranges: nonea

Age 允许服务器规定自服务器生成该响应以来所经过的时间长度,以秒为单位。
该头标主要用于缓存响应。例如:Age: 30

Allow 一个响应头标,它定义一个由位于请求URI中的次源所支持的HTTP方法列表。例如:Allow: GET,PUT

aUTHORIZATION
一个响应头标,用于定义访问一种资源所必需的授权(域和被编码的用户ID与口令)。
例如:Authorization: Basic YXV0aG9yOnBoaWw=

Cache-Control 一个用于定义缓存指令的通用头标。例如:Cache-Control: max-age=30
Connection 一个用于表明是否保存socket连接为开放的通用头标。例如:Connection: close或Connection: keep-alive

Content-Base
一种定义基本URI的实体头标,为了在实体范围内解析相对URLs。
如果没有定义Content-Base头标解析相对URLs,使用Content-Location URI(存在且绝对)或使用URI请求。
例如:Content-Base: Http://www.myweb.com

Content-Encoding 一种介质类型修饰符,标明一个实体是如何编码的。例如:Content-Encoding: zip
Content-Language 用于指定在输入流中数据的自然语言类型。例如:Content-Language: en
Content-Length 指定包含于请求或响应中数据的字节长度。例如:Content-Length:382

Content-Location
指定包含于请求或响应中的资源定位(URI)。
如果是一绝。对URL它也作为被解析实体的相对URL的出发点。
例如:Content-Location: http://www.myweb.com/news

Content-MD5
实体的一种MD5摘要,用作校验和。
发送方和接受方都计算MD5摘要,接受方将其计算的值与此头标中传递的值进行比较。
例如:Content-MD5:

Content-Range
随部分实体一同发送;标明被插入字节的低位与高位字节偏移,也标明此实体的总长度。
例如:Content-Range: 1001-2000/5000

Contern-Type 标明发送或者接收的实体的MIME类型。例如:Content-Type: text/html
Date 发送HTTP消息的日期。例如:Date: Mon,10PR 18:42:51 GMT

ETag 一种实体头标,它向被发送的资源分派一个唯一的标识符。
对于可以使用多种URL请求的资源,ETag可以用于确定实际被发送的资源是否为同一资源。
例如:ETag: “208f-419e-30f8dc99”

Expires 指定实体的有效期。例如:Expires: Mon,05 Dec 2008 12:00:00 GMT
Form 一种请求头标,给定控制用户代理的人工用户的电子邮件地址。例如:From: webmaster@myweb.com
Host 被请求资源的主机名。对于使用HTTP/1.1的请求而言,此域是强制性的。例如:Host: www.myweb.com

If-Modified-Since
如果包含了GET请求,导致该请求条件性地依赖于资源上次修改日期。
如果出现了此头标,并且自指定日期以来,此资源已被修改,应该反回一个304响应代码。
例如:If-Modified-Since: Mon,10PR 18:42:51 GMT

If-Match 如果包含于一个请求,指定一个或者多个实体标记。只发送其ETag与列表中标记区配的资源。
例如:If-Match: “208f-419e-308dc99”

If-None-Match
如果包含一个请求,指定一个或者多个实体标记。资源的ETag不与列表中的任何一个条件匹配,操作才执行。
例如:If-None-Match: “208f-419e-308dc99”

If-Range
指定资源的一个实体标记,客户端已经拥有此资源的一个拷贝。必须与Range头标一同使用。
如果此实体自上次被客户端检索以来,还不曾修改过,那么服务器只发送指定的范围,否则它将发送整个资源。
例如:Range: byte=0-499If-Range:”208f-419e-30f8dc99”

If-Unmodified-Since
只有自指定的日期以来,被请求的实体还不曾被修改过,才会返回此实体。
例如:If-Unmodified-Since:Mon,10PR 18:42:51 GMT

Last-Modified 指定被请求资源上次被修改的日期和时间。例如:Last-Modified: Mon,10PR 18:42:51 GMT
Location
对于一个已经移动的资源,用于重定向请求者至另一个位置。
与状态编码302(暂时移动)或者301(永久性移动)配合使用。
例如:Location: http://www2.myweb.com/index.jsp

Max-Forwards
一个用于TRACE方法的请求头标,以指定代理或网关的最大数目,该请求通过网关才得以路由。
在通过请求传递之前,代理或网关应该减少此数目。例如:Max-Forwards: 3

Pragma 一个通用头标,它发送实现相关的信息。例如:Pragma: no-cache
Proxy-Authenticate
类似于WWW-Authenticate,便是有意请求只来自请求链(代理)的下一个服务器的认证。
例如:Proxy-Authenticate: Basic realm-admin

Proxy-Proxy-Authorization
类似于授权,但并非有意传递任何比在即时服务器链中更进一步的内容。
例如:Proxy-Proxy-Authorization: Basic YXV0aG9yOnBoaWw=

Public 列表显示服务器所支持的方法集。例如:Public: OPTIONS,MGET,MHEAD,GET,HEAD
Range 指定一种度量单位和一个部分被请求资源的偏移范围。例如:Range: bytes=206-5513

Refener
一种请求头标域,标明产生请求的初始资源。对于HTML表单,它包含此表单的Web页面的地址。
例如:Refener: http://www.myweb.com/news/search.html

Retry-After
一种响应头标域,由服务器与状态编码503(无法提供服务)配合发送,以标明再次请求之前应该等待多长时间。
此时间即可以是一种日期,也可以是一种秒单位。例如:Retry-After: 18

Server 一种标明Web服务器软件及其版本号的头标。例如:Server: Apache/2.0.46(Win32)
Transfer-Encoding 一种通用头标,标明对应被接受方反向的消息体实施变换的类型。例如:Transfer-Encoding: chunked

Upgrade
允许服务器指定一种新的协议或者新的协议版本,与响应编码101(切换协议)配合使用。
例如:Upgrade: HTTP/2.0

User-Agent
定义用于产生请求的软件类型(典型的如Web浏览器)。
例如:User-Agent: Mozilla/4.0(compatible; MSIE 5.5; Windows NT; DigExt)

Vary 一个响应头标,用于表示使用服务器驱动的协商从可用的响应表示中选择响应实体。例如:Vary: *
Via 一个包含所有中间主机和协议的通用头标,用于满足请求。例如:Via: 1.0 fred.com, 1.1 wilma.com
Warning 用于提供关于响应状态补充信息的响应头标。例如:Warning: 99 www.myweb.com Piano needs tuning

www-Authenticate
一个提示用户代理提供用户名和口令的响应头标,与状态编码401(未授权)配合使用。响应一个授权头标。
例如:www-Authenticate: Basic realm=zxm.mgmt

http请求状态码

转载地址

http状态返回代码 1xx(临时响应)

  • 表示临时响应并需要请求者继续执行操作的状态代码。

http状态返回代码 代码 说明

  • 100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
  • 101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。

http状态返回代码 2xx (成功)

表示成功处理了请求的状态代码。

http状态返回代码 代码 说明

  • 200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
  • 201 (已创建) 请求成功并且服务器创建了新的资源。
  • 202 (已接受) 服务器已接受请求,但尚未处理。
  • 203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
  • 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
  • 205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
  • 206 (部分内容) 服务器成功处理了部分 GET 请求。

http状态返回代码 3xx (重定向)

  • 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

http状态返回代码 代码 说明

  • 300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
  • 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
  • 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
  • 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
  • 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
  • 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
  • 307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

http状态返回代码 4xx(请求错误)

  • 这些状态代码表示请求可能出错,妨碍了服务器的处理。

http状态返回代码 代码 说明

  • 400 (错误请求) 服务器不理解请求的语法。
  • 401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
  • 403 (禁止) 服务器拒绝请求。
  • 404 (未找到) 服务器找不到请求的网页。
  • 405 (方法禁用) 禁用请求中指定的方法。
  • 406 (不接受) 无法使用请求的内容特性响应请求的网页。
  • 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
  • 408 (请求超时) 服务器等候请求时发生超时。
  • 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
  • 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
  • 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
  • 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
  • 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
  • 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
  • 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
  • 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
  • 417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。

http状态返回代码 5xx(服务器错误)

  • 这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

http状态返回代码 代码 说明

  • 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
  • 501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
  • 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
  • 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
  • 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
  • 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

一些常见的http状态返回代码为:

  • 200 - 服务器成功返回网页
  • 404 - 请求的网页不存在
  • 503 - 服务不可用

从输入URL到页面加载完成的过程-数据包组装过程

从输入URL到页面加载完成的过程-数据包组装过程

网络各层数据包的组装过程是比较复杂的,由于每一层都有各自的职责,所以在各层组装时的首部都会携带一些特定的标识。下面先给出一个组装图,再一一到来:

数据包组装过程

1、组装TCP报文段,TCP的全部功能都体现在它首部中各自段的作用:

解释其中几个比较重要的部分:

  • 源端口、目标端口:计算机上的进程要和其他进程通信是要通过计算机端口的,而一个计算机端口某个时刻只能被一个进程占用,所以通过指定源端口和目标端口,就可以知道是哪两个进程需要通信。源端口、目标端口是用16位表示的,可推算计算机的端口个数为2^16个。
  • 序列号:表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置

  • 确认号:表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是告诉发送发:我希望你(指发送方)下次发送的数据的第一个字节数据的编号是这个确认号。

  • 窗口大小:窗口指的是发送本报文段的一方的接收窗口,而不是自己的发送窗口。窗口值作为接收方让发送方设置其发送窗口的依据。

  • 校验和:提供额外的可靠性,检验报文段是否正确。具体如何校验,参考其他资料。

2、IP数据报组装需要首部和数据部分,数据部分即是TCP报文段。

IP 数据报的格式示意图:

IP数据报首部

解释其中几个比较重要的部分:

  • 版本:占 4 位,指 IP 协议的版本,目前的 IP 协议版本号为 4 (即 IPv4)

  • 总长度:占 16 位,指首部和数据之和的长度,单位为字节,因此数据报的最大长度为 65535 字节。总长度必须不超过最大传送单元 MTU

  • 首部校验和:只检验数据报的首部,但不包括数据部分。

  • 源地址、目的地址:表示此报文段发送方的IP地址和接收方的IP地址,此时假如电脑使用wifi上网(即组成局域网),那么发送方的ip为内网IP(如192.168.1.10),可想而知,在接收方发送数据回来时,是找不到这个IP地址的,因此在出口的NAT设备上,会把此IP数据报的源IP地址换为出口IP(也就是公网IP,如119.147.215.58),那么NAT设备是如何转换的呢?
    NAT路由器的工作原理

NAT地址转换表举例

  • 在客户端的局域网内,数据包的发送是以MAC帧首部的源MAC地址和目的MAC地址来寻找机器的,而到了NAT路由器,它会解开数据包,根据转换表,把IP数据报的首部中的源IP地址替换为新的IP地址(公网IP)

3、MAC帧格式,数据链路层需要解决的问题:

  • 封装成帧(如下图)、透明传输(数据部分加入转义符,头尾加入标识符)、差错检测(CRC)

用帧首部和帧尾部进行封装成帧

以太网帧格式

  • 其中比较重要的是目的地址和源地址,这个地址就是硬件地址(网卡地址或mac地址),通过arp和rarp协议,可以把ip转换成mac地址,此时就会把源机器的mac地址和目标机器(服务器)的ip地址放于首部中。在网络中的路由器间进行传输时,路由器会不断的把mac帧首部的目的地址和源地址进行更换,以便找到下一个路由器。

mac帧传输使用硬件地址

注意:

1)、虽然在IP数据报的首部有源站IP地址,但路由器只根据目的站的IP地址的网络号进行路由选择。

2)、可以看出,传输过程中,IP数据报中的IP地址是不会变的,而MAC帧首部的源地址和目的地址要发生变化。在局域网的链路层,只能看见MAC帧。

3)、IP层抽象的互联网却屏蔽了下层这些很复杂的细节。

到此,基本完成了网络各层的封装,每层的作用基本可以体现在首部和尾部的字段中,不过我们不必较真,知道其中几个比较重要的字段就可以,因为我们关注的是数据包怎么传输(本文已可以看到解答)?

从输入URL到页面加载完成的过程

从输入URL到页面加载完成的过程

原文地址

当你输入一个网址的时候,实际会发生什么,作为一个开发者,一定会对这整个工作过程感兴趣,下面分多篇文章介绍这整个过程,期间涉及DNS,TCP三次握手,数据包路由过程,服务器大致的响应处理过程,以及长连接的保持和TCP连接的关闭。

-下面简单列出请求过程中比较重要的步骤:

1、在浏览器里输入网址,Enter,浏览器向DNS发送请求,查找域名对应IP

2、浏览器根据返回的请求域名IP,加上请求端口(默认80),和请求资源(资源位置为/或者index.html之类的),组装请求后浏览器发送请求

[从输入URL到页面加载完成的过程-DNS解析域名过程]

3、传输层发现没有和目标IP建立连接,因此发起请求建立连接,发生3次握手建立TCP连接的过程

 从输入URL到页面加载完成的过程-TCP三次握手

4、建立连接后,发送请求资源的数据包,请求类型假设是GET(只请求获取资源内容),系统经过传输层、网络层、数据链路层的层层封装,最终发出数据包

 从输入URL到页面加载完成的过程-数据包组装过程

5、数据包在NAT设备和多个路由器上流转,经过漫长的跳转到达服务器的NAT设备,NAT根据请求端口把请求转发给内网服务器

6、服务器接受请求后,可能直接使用缓存,也可能会把请求发到web server进行解析,最终经过服务器解析后,组装响应内容,向客户端发送响应数据。响应数据包经过网络返回到客户端NAT,并经过NAT转发后到达客户端

7、客户端网络各层把数据包层层解包,并在应用层把数据包(数据包可能有多个,当都到达后,才会把完整的数据包给浏览器)返回给浏览器解析

8、浏览器根据响应的HTTP头和实体内容,解析数据包。并继续请求页面中需要加载的一些其他资源,如果此时请求的资源在CDN(内容分发网络,就是在你家附近的服务器存放有请求的这些静态资源;减少网络延迟的办法一个是使用更好的传输介质-比如光纤,一个是缩短传输距离-CDN就是利用这个),则从CDN获取资源(过程和请求服务器资源一致,需要经过三次握手建立连接);如果是继续获取原来服务器(敲入域名对应的IP),则继续重用原来的TCP连接(前提是使用HTTP1.1,而HTTP1.0有keep-alive头部可以达到保持连接的效果)。

9、请求资源后,空闲一段时间没有和服务器进行交互(空闲时间是设置的,有的应用为了不断开TCP连接,会每隔一段时间发送一次请求到服务器,从而保持连接,这样用户在发起真实的资源请求时,就可以省略TCP连接建立的过程,但是这样的连接过多会消耗服务器的资源),就会发生TCP连接关闭过程,关闭过程会发生四次交互。

10、TCP传输数据过程中的慢启动、拥塞预防和控制

11、从请求交互过程总结的优化方法

 以上这些每一点都会单独写篇文章配图分析,敬请期待。文章内容参考网络资源、《HTTP权威指南》、《WEB性能权威指南》。最后说下最近的看书感受,Know hardware to design better software,了解底层能让自己看的更全面些。
,