关于网络编程:VPC网络有什么优势

VPC通过各种网络增值组件大幅晋升了核心 云上的网络灵活性和功能丰富度,让各种类型的业务场景能够享受网络云化带来的高度便捷性。 残缺内容请点击下方链接查看:VPC网络有什么劣势? 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

April 19, 2023 · 1 min · jiezi

关于网络编程:网工必备五款工作学习必备软件免费下载

很多人都在问,学习网络工程师须要什么软件?其实网工业有很多软件,比方 Cad,比方广联达,比方钉钉,比方一些数据,比方一些辅助软件,这些都是为了进步我的项目的效率,让他们更好的了解我的项目的思路,而明天,咱们就来介绍一下这些软件。 一、华为eNSP模拟器 华为 ensp模拟器是华为公司开发的一款功能强大的网络模仿工具,它的次要性能是通过对网络由器、交换机、 WLAN等设施进行模仿,使其能够完满地展现出理论设施的配置,同时还能够通过大规模的网络模仿来进行试验测试,学习网络技术。 同时,在我的项目开始前,能够模拟出一个我的项目的网络结构,让这个我的项目在执行的时候,可能心里有数,这是一个很有用的软件,简直所有的网络工程师都会用到。 性能阐明: 1、图形页面操作 反对创立,批改,删除,保留等操作。 反对设施拖拽,接口连贯。 通过不同的配色,直观地反映了操作设施和接口的工作情况。 预设了大量的工程实例,能够间接进行模仿学习。 2、实在模仿 能模拟大多数华为 AR路由器,x7系列交换机的实机个性。 能够模仿 PC终端, Hub,云,帧中继交换机等. 模仿设施的配置,疾速理解华为的命令行指令。 能对大型设施的网络组网进行模仿。 二、Secure CRT Secure CRT是一个十分好的工具,它能够用来运行 Windows, UNIX, VMS等近程零碎,它能够利用 VCP指令的运行程序来进行加密的文件传送。 Secure CRT联合了 SSH的安全性、可靠性、可用性和可配置性,以及 Windows终端模仿。 Secure CRT的次要特色是: 反对 SSH、 Telnet、序列和其余协定; Activator tray的利用极大地升高了桌面上的芜杂; Secure Shell对logon和session进行数据加密; 端口爱护保障了TCP/IP数据安全; RSA和密钥辨认; Blowfish, DES, 3DES 和 RC4明码。 这是一个必不可少的近程登录开关。 三、Wireshark工具 wireshark是一个很受欢迎的软件,它具备很强的性能。能拦挡不同的网络封包,并能显示出网络封包的具体情况。wireshark的用户肯定要相熟网络协议,不然是无奈了解 wireshark的。 而且,这是一个十分重要的工具,也是一个十分重要的工具。它的利用范畴很广,速度很快,而且能够提供大量的工具和过滤器来准确地确定网络中的状况。 四、 VISIO软件 微软 Visio是微软办公软件中的一种,在 Windows零碎中运行的流程图和向量绘制软件。 Visio能够帮忙您建设一个带有业余色调的图形,用于了解,记录和剖析信息,数据系统零碎和流程。大部分的绘图软件都是靠美术的。然而,当你应用 Visio时,你能够很容易地看到重要的信息,比方关上一个模板,把一个图形拖入一个图表,或者是一个将要实现的工作。 visio在网工畛域的利用很宽泛,咱们的网工人,在设计的时候,都会用到 visio软件,很有创意。 五、 XMIND思维导图 ...

August 8, 2022 · 1 min · jiezi

关于网络编程:网工必看GVRP协议的详解和配置

又是咱们的网工必备系列啦!快来学习吧! 1.首先咱们来看一下GVRP的报文构造: GARP PDU音讯以列表的模式来承载属性。动态 vlan 手工配置,动静 vlan,gvrp 学习到。然而不能应用。 2.GVRP单向注册 ●在SWA.上创立动态VL AN2,通过VLAN属性的单向注册,SWB和SWC 会学习到动静VLAN2,并将相应端口主动退出到VLAN2中。 ●SWB的G0/0/2端口没有收到Join音讯,不会被退出到VL _AN2中。 同步是单项的,单项的把我的信息发送给你,你收到之后是不能回向给我发送的,你能发送给其余的交换机,注册模式有三种,如下: (1)注册模式—Normal ●交换机端口默认为Normal模式,容许动态和动静VL AN注册,同时会发送动态VLAN和动静VLAN的申明音讯。 默认为 normal 这个是通过这个接口,能够把我本地动态 vlan 、动静 vlan 都给你注册过来。 (2)注册模式—Fixed ●SWA的G0/0/1端口为Fixed模式,不容许动静VLAN在端口.上注册或者登记,且只发送动态VLAN的申明音讯。 Fixed 只能发送动态 vlan 给你,动静不能发送,接收端如果为 fixed 承受端口不会承受任何vlan 信息。 (3)注册模式—Forbidden ●SWA的G0/0/1端口为Forbidden模式,不容许动静VL AN在端口.上进行注册,同时删除端口,上除VL AN1外的所有VL AN。 Forbidden 不容许发送任何 vlan 信息,除了 vlan1 之外 其余都不注册,对于接收端 vlan 间接失落 不会学习。 上面咱们就来做一下简略的GVRP协定的配置,拓扑如下: [SW1]int g0/0/1 [SW1-GigabitEthernet0/0/1]port link-type trunk [SW1-GigabitEthernet0/0/1]port trunk allow-pass vlan all [SW2]int g0/0/1 [SW2-GigabitEthernet0/0/1]port link-type trunk ...

July 13, 2022 · 1 min · jiezi

关于网络编程:网络是怎么样连接的读书笔记-WEB服务端请求和响应五

《网络是怎么样连贯的》读书笔记 - WEB服务端申请和响应(五)本章重点客户端和服务端的区别以及客户端响应的连贯过程。 客户端和服务端的区别服务器的分类和性能品种有很多,然而网络相干的局部, 如网卡、协定栈、Socket 库等性能和客户端却并无二致。 另外咱们能够回顾第一章笔记中介绍了对于互联网的历史局部,网络自诞生开始就是为了军事通信,意味着最好是在数据收发层面不须要辨别客户端和服务器,而是可能以左右对称的形式自在发送数据。所以咱们常说的客户端和服务端仅仅是从发送者和接受者的角度来辨别,如果服务器发送申请到客户端,也能够认为服务器自身是“客户端”。 对于服务端和客户端咱们从Socket库调用上查看两者差异: 客户端的数据收发须要 通过上面 4 个阶段。 (1)创立套接字(创立套接字阶段) (2)用管道连贯服务器端的套接字(连贯阶段) (3)收发数据(收发阶段) (4)断开管道并删除套接字(断开阶段) 服务器是将阶段(2)改成了期待连贯 (1)创立套接字(创立套接字阶段) (2-1)将套接字设置为期待连贯状态(期待连贯阶段) (2-2)承受连贯(承受连贯阶段) (3)收发数据(收发阶段) (4)断开管道并删除套接字(断开阶段) 连贯过程上面和第二章介绍客户端连贯相似,介绍服务端连贯的步骤。 首先调用 bind 将端口号写入套接字中,并且要设置端口,之后协定栈会调用accept连贯,留神这时候包可能是没有到来的,如果包没有到来服务端会阻塞期待客户端的申请,一旦接管到连贯就会开始响应并且进行连贯操作。 接下来协定栈会给期待连贯的套接字复制一个正本, 而后将连贯对象等管制信息写入新的套接字中,为什么这里要创立正本简略解释一下,因为如果间接应用原有的套接字连贯,那么当新的客户端申请过去,就必须要再次创立新的套接字而后再次进行连贯。应用复制套接字的形式,原有的套接字仍然能够实现期待连贯的工作,和新建的套接字正本是没有关联的。 创立套接字除了复制套接字这个特点外,还有一个是端口号的应用,因为一个套接字须要对应一个端口号,然而须要留神新创建的套接字正本必须和原来的期待连贯的套接字具备雷同的端口号,起因是避免相似客户端原本想要连贯 80 端口上的套接字, 后果从另一个端口号返回了包这样的状况。 针对这个问题,服务端的套接字除了确定端口之外,还须要带上IP信息和客户端的端口号信息,最终依附上面四个变量来确定和哪一个套接字交互。 客户端 IP 地址客户端端口号服务器 IP 地址服务器端口号从下面这幅图能够看到,服务端可能会在一个端口上创立正本绑定很多个套接字,然而客户端的端口是齐全不同并且随机的,同时IP地址也不一样,所以能够确定套接字之间是不会存在抵触的。 套接字筹备实现之后,接着是对于网络包进行FCS 的校验,当 FCS 统一确认数据没有谬误时,接下来须要查看 MAC 头部中 的接管方 MAC 地址,看看这个包是不是发给本人的,之后网卡的 MAC 模块将网络包从信号还原为数字信息, 校验 FCS并存入缓冲区。 网卡收到音讯之后,接着是执行中断解决机制告知CPU开始进行网卡的数据处理,对于中断解决的内容能够通过的另一本书《Linux是怎么样工作的》理解CPU的中断解决机制理解整个执行过程,之后网卡驱动会依据 MAC 头部判断协定类型,并将包交给相应的协定栈。 为什么还要应用描述符呢?这里回顾一下描述符的内容,描述符指的是在创立套接字之后,服务端须要返回给客户端一条标识信息,目标是告知客户端本人是谁,协定栈也须要返回描述符用于标识是哪一个套接字在进行传数据。 这里能够简略了解为咱们在网络聊天的时候尽管晓得对方是谁和本人聊天,然而如果对方没有“开摄像头”通知你我是自己,很有可能是他人假装你意识的人在和你聊天。而咱们晓得对方是自己在和咱们聊天也是因为对方的一些“性情”所以理解。 当网络包转交到协定栈时,IP 模块会首先开始工作查看 IP 头部。IP 头部次要是查看标准,查看单方的IP地址,确认包是不是发给本人的,确认包是发给本人的之后,接下来须要查看包有没有被分片,而后查看 IP 头部的协定号字段,并将包转交给相应的模块。 IP模块接管操作小结 协定栈的 IP 模块会查看 IP 头部: ...

June 29, 2022 · 1 min · jiezi

关于网络编程:网络是怎么样连接的读书笔记-认识网络基础概念一

《网络是怎么样连贯的》读书笔记 - 意识网络根底概念(一)讲讲历史1991年8月6日,在瑞士日内瓦的核子钻研核心(CERN)工作的英国物理学家蒂姆·伯纳斯·李(Tim Berners-Lee),正式提出了World Wide Web,也就是现在咱们十分相熟的www。 www是什么?万维网WWW是World Wide Web的简称,也称为Web、3W等。WWW是基于客户机/服务器形式的信息发现技术和超文本的综合技术。 这里集体比拟好奇咱们天天都在说3w,3w,然而互联网是怎么呈现的的书中并没有解释? 这里查了下网上材料依据集体了解解释一波: 实际上网络最开始苗头呈现在美苏热战的期间美国建设的APRA科研部门,被忽然扯出来的科研部门人心涣散不晓得干嘛,凑合苏联的科研工作也没什么停顿,直到一个叫做罗伯特·泰勒的哥们呈现,他的突破口是发现小型的通信网络不能兼容不同型号的计算机,咱们都晓得技术的高峰就是定规定,毫无疑问他抉择构建一套协定让所有的计算机都能恪守这一套规定干活。 于是他找来了几个牛逼的大佬开始捣鼓,两头巴拉巴拉做了很多事绕了很多弯,目标其实就是为了实现下面说的货色,最终在一次失败的“LOGIN”验证中尽管仅仅传输了“LO”两个字母就断开了,然而这次失败是历史性的提高,因为两个不同的设施实实在在的通信了,最终修复之后实现了这五个字母的失常传输。 随后捯饬出的ARPANET(阿帕网) 这个我的项目,也就是正式的互联网雏形。 课外常识到此结束,当初咱们看看第一章次要看点: 如何解析网址?DNS 服务器如何查问域名对应的 IP 地址?DNS服务器如何接力?浏览器如何将音讯委托给操作系统发送给 Web 服务器?外围是了解DNS的角色位置和作用,以及浏览器如何跟DNS交互实现网址(域名)解析为IP这一个操作的,本章最初的委托流程是整个第二章的重点内容,笔记顺其自然的放到了第二章笔记当中,为了不便了解把笔记归纳到第二局部。 如何解析网址咱们从URL开始,什么是URL,URL是Uniform Resource Locator的简称,业余解释叫做对立资源定位符,除开咱们常见的http、https协定之外,浏览器还能够进行ftp文件上传,下载文件,发送电子邮件,浏览新文化等操作。 咱们把这些行为看作是资源交互,尽管不同的资源交互会存在不同的URL组合,然而不论URL的组合模式如何变动,最终是结尾决定所有,结尾局部决定看待资源形式。 解析网址咱们能够看上面的例子: 碰到省略文件名的状况,通常上面几种: http://xxxx/dir/示意 /dir/ 之后的内容被省略,这时候通常状况下会设置对应这个目录的实在拜访门路进行补全。对于web中最为经典的http://localhost:8080/拜访门路,通常状况下Web服务器会拜访到/index.html这个文件,如果没有就会返回404的页面。如果只有域名,比方www.baidu.com,那就会间接拜访web服务器设置的根门路对应的资源和相干文件。含混不清的门路比方http://localhost:8080/wishlist,则会依据先判断是否为文件名,而后判断是否为目录的状况解决,或者看作一个申请映射到另一处资源,或者做一次重定向。下面的内容不用深究,只须要明确浏览器的第一步工作就是对 URL 进行解析。 Http申请http申请简略来说能够简略概括为一句话:对什么做了什么样的操作,所谓对什么指的是URL,示意标识了的指标对象,做什么样的操作就是所谓的办法,办法次要是分为两个POST和GET办法,其余办法根本没啥用途,集体只在偶然几个对接文档中遇到过PUT和HEAD办法。 GET办法:通常用于一些可见资源的拜访,或者凋谢资源的拜访,通常状况下不须要过多的限度就能够间接向具体的目录寻找须要的资源。 POST办法:比拟常见的是应用表单或者 AJAX的形式拜访,并且通常会指向一个WEB的应用程序,获取应用程序的数据须要传递服务器须要的一些无效参数,否则服务端会依据具体情况告诉客户端无权拜访。 AJAX即“Asynchronous JavaScript and XML”(非同步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。Ajax的概念由杰西·詹姆士·贾瑞特所提出[1]。Http申请音讯 晓得了 对什么做了什么样的操作,当初来看看Http 具体是怎么做这件事件的。 Http申请音讯次要分为上面组织构造: 第一行最结尾的局部提取URL的内容,一成不变解析,开端为HTTP版本号次要标记以后HTTP申请版本。例如:GET /cgi/sample.cgi?Field1=ABCDEFG&SendButton=SEND HTTP/1.1第二行为音讯头,这里列举一些简略的内容: Data:申请响应生成日期。Pragma:数据是否容许缓存。Transfer-Encoding:音讯主体编码格局(重要)。Via:通过的代理和网关。音讯头前面存在一行 完满没有内容的空行。第四行为音讯体,然而试验用的是GET办法所以通常内容为空。 咱们以拜访谷歌为例,上面的内容拜访谷歌搜寻页面的一次申请参考,这里的内容间接通过谷歌浏览器的F12拷贝,能够看到根本蕴含了申请行,音讯头和音讯行(GET通常没有所以上面没有体现)三种。 惯例1. 申请网址:https://www.google.com/2. 申请办法:GET3. 状态代码:2004. 近程地址:127.0.0.1:78905. 推荐起源网址政策:origin申请标头1. :authority:www.google.com2. :method:GET3. :path:/4. :scheme:https5. accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.96. accept-encoding:gzip, deflate, br7. accept-language:zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.68. cache-control:no-cache9. cookie:SID=KQi0QVpC_wxTynb6H6HjGmVq-9mYvCuIDOMx9EmEUJ8ii7dJzN_1F-ho69FdK6AN9ekOkA.; __Secure-1PSID=KQi0QVpC_wxTynb6H6HjGmVq-9mYvCuIDOMx9EmEUJ8ii7dJaTdIpqSfRfNb-BvF0haitA.; __Secure-3PSID=KQi0QVpC_wxTynb6H6HjGmVq-9mYvCuIDOMx9EmEUJ8ii7dJ6_WQQeEF09oAZ9MQfe21sA.; HSID=AOdmIhuBCutDeMwVS; APISID=ckyVXTB27QMaC2gQ/AVulr1cMnMbpD0e1x; SSID=AL0-0R0Ofsj3zaqrr; SAPISID=dqpTwJeh7bnii2Ki/AfsaDUfE8uMVR1aqv; __Secure-1PAPISID=dqpTwJeh7bnii2Ki/AfsaDUfE8uMVR1aqv; __Secure-3PAPISID=dqpTwJeh7bnii2Ki/AfsaDUfE8uMVR1aqv; SEARCH_SAMESITE=CgQIvJUB; 1P_JAR=2022-05-24-23; AEC=AakniGOKhznRpAD797X4u508i2XHJjEVYQQHANlqaJC2JSZ1F7mAe-vX_rg; NID=511=K-qt_LW-4ad1IYdJgfPLZjJw772wez2L3_FK9hwrrHAaksdhT8bTqz4icJEnJviOb92zcnyfS4h7P8HB_Is0f_FebYTe_5DR3qFEclHS1R9N1P7r9pv7Z4p12341S72RZRfzIlQ3-CVZUqQKBm1Xy1i9fKwejMGHTPMY2hk02sA--ey8nAEyt1_A7SVMe0RvrEkPnVm88fBnyyyFMMSCeSG1oqYKeC2x7iHJ0GwdbEpeGojpMQyQxAn1jAdxyXbC0oko0rCFjYn7eUREz2A9KA; SIDCC=AJi4QfGQeW0y_3pnzuBs7KI-WabF5XR_-dQchpcoNUN_bRVICBknb39qNQhP4IklnPn6kW4M3d8; __Secure-3PSIDCC=AJi4QfFOaoqiWv0mqmOskkIKVYy_-QNOATkPOyhNt9B8BBTMnRqnv-0zdgVgBNmIJRwlzBS4x6U10. pragma:no-cache11. sec-ch-dpr:212. sec-ch-ua:" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"13. sec-ch-ua-arch:"arm"14. sec-ch-ua-bitness:"64"15. sec-ch-ua-full-version:"101.0.4951.64"16. sec-ch-ua-full-version-list:" Not A;Brand";v="99.0.0.0", "Chromium";v="101.0.4951.64", "Google Chrome";v="101.0.4951.64"17. sec-ch-ua-mobile:?018. sec-ch-ua-model:""19. sec-ch-ua-platform:"macOS"20. sec-ch-ua-platform-version:"12.3.1"21. sec-ch-ua-wow64:?022. sec-ch-viewport-width:144023. sec-fetch-dest:document24. sec-fetch-mode:navigate25. sec-fetch-site:same-origin26. sec-fetch-user:?127. upgrade-insecure-requests:128. user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.3629. x-client-data:CLG1yQEIkrbJAQijtskBCMS2yQEIqZ3KAQjYjMsBCJShywEI2+/LAQjmhMwBCNupzAEI/qrMAQjDrMwBCKSvzAEYqKnKARirqcoB30. 已解码:message ClientVariations { // Active client experiment variation IDs. repeated int32 variation_id = [3300017, 3300114, 3300131, 3300164, 3313321, 3327576, 3330196, 3340251, 3342950, 3347675, 3347838, 3348035, 3348388]; // Active client experiment variation IDs that trigger server-side behavior. repeated int32 trigger_variation_id = [3314856, 3314859]; }响应内容 ...

June 19, 2022 · 3 min · jiezi

关于网络编程:基于QUIC协议的HTTP3正式发布

1、HTTP/3终于标准化2022年6月6日,IETF QUIC和HTTP工作组成员Robin Mark在推特上发表,历时5年,HTTP/3终于被标准化为 RFC 9114,这是HTTP超文本传输协定的第三个次要版本。 同时, HTTP/2也被更新为新的 RFC 9113。 Robin写道,新公布的HTTP/3规范将与RFC 9204(QPACK header压缩) 和 RFC 9218(可扩大的优先级)一起为Web关上重要的新篇章。 2、什么是QUIC协定? QUIC是一种通用、平安、多路复用的传输层新型网络协议。它的目标是代替TCP(目前是互联网上用于数据传输的支流协定)。2012年,QUIC协定由过后还在谷歌任职的Jim Roskind开发。2013年,QUIC正式对外颁布。 2015年,QUIC被提交给IETF进行标准化,然而直到六年当前,也就是2021年5月,IETF才公布了第一版标准化的QUIC,被命名为RFC 9000。同时,IETF还公布应用了QUIC的HTTP/3标准化版本。 QUIC吸纳了很多与TCP相似的属性,还有TLS加密,将它们置于UDP传输之上的应用层中。 无关QUIC协定的文章可具体浏览上面几篇,这里不再赘述: [1] 一泡尿的工夫,疾速读懂QUIC协定:http://www.52im.net/thread-28...[2] 技术扫盲:新一代基于UDP的低延时网络传输层协定——QUIC详解:http://www.52im.net/thread-13...[3] 让互联网更快:新一代QUIC协定在腾讯的技术实际分享:http://www.52im.net/thread-14...[4] 七牛云技术分享:应用QUIC协定实现实时视频直播0卡顿!:http://www.52im.net/thread-14...

June 8, 2022 · 1 min · jiezi

关于网络编程:不为人知的网络编程十一从底层入手深度分析TCP连接耗时的秘密

本文作者张彦飞,原题“聊聊TCP连贯耗时的那些事儿”,有少许改变。 1、引言对于基于互联网的通信利用(比方IM聊天、推送零碎),数据传递时应用TCP协定绝对较多。这是因为在TCP/IP协定簇的传输层协定中,TCP协定具备牢靠的连贯、谬误重传、拥塞管制等长处,所以目前在利用场景上比UDP更宽泛一些。 置信你也肯定听闻过TCP也存在一些毛病,能常都是陈词滥调的开销要略大。然而各路技术博客里都在单单说开销大、或者开销小,而少见不给出具体的量化剖析。不客气的讲,相似阐述都是没什么养分的废话。 通过日常工作的思考之后,我更想弄明确的是,TCP的开销到底有多大,是否进行量化。一条TCP连贯的建设须要耗时提早多少,是多少毫秒,还是多少微秒?能不能有一个哪怕是粗略的量化预计?当然影响TCP耗时的因素有很多,比方网络丢包等等。我明天只分享我在工作实际中遇到的比拟高发的各种状况。 写在后面:得益于Linux内核的开源,本文中所提及的底层以及具体的内核级代码例子,都是以Linux零碎为例。 学习交换: 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(备用地址点此)(本文已同步公布于:http://www.52im.net/thread-32...) 2、系列文章本文是系列文章中的第11篇,本系列文章的纲要如下: 《鲜为人知的网络编程(一):浅析TCP协定中的疑难杂症(上篇)》《鲜为人知的网络编程(二):浅析TCP协定中的疑难杂症(下篇)》《鲜为人知的网络编程(三):敞开TCP连贯时为什么会TIME_WAIT、CLOSE_WAIT》《鲜为人知的网络编程(四):深入研究剖析TCP的异样敞开》《鲜为人知的网络编程(五):UDP的连接性和负载平衡》《鲜为人知的网络编程(六):深刻地了解UDP协定并用好它》《鲜为人知的网络编程(七):如何让不牢靠的UDP变的牢靠?》《鲜为人知的网络编程(八):从数据传输层深度解密HTTP》《鲜为人知的网络编程(九):实践联系实际,全方位深刻了解DNS》《鲜为人知的网络编程(十):深刻操作系统,从内核了解网络包的接管过程(Linux篇)》《鲜为人知的网络编程(十一):从底层动手,深度剖析TCP连贯耗时的机密》(本文)《鲜为人知的网络编程(十二):彻底搞懂TCP协定层的KeepAlive保活机制》《鲜为人知的网络编程(十三):深刻操作系统,彻底搞懂127.0.0.1本机网络通信》《鲜为人知的网络编程(十四):拔掉网线再插上,TCP连贯还在吗?一文即懂!》 3、现实状况下的TCP连贯耗时剖析要想搞清楚TCP连贯的耗时,咱们须要具体理解连贯的建设过程。 在前文《深刻操作系统,从内核了解网络包的接管过程(Linux篇)》中咱们介绍了数据包在接收端是怎么被接管的:数据包从发送方进去,通过网络达到接管方的网卡;在接管方网卡将数据包DMA到RingBuffer后,内核通过硬中断、软中断等机制来解决(如果发送的是用户数据的话,最初会发送到socket的接管队列中,并唤醒用户过程)。 在软中断中,当一个包被内核从RingBuffer中摘下来的时候,在内核中是用struct sk_buff构造体来示意的(参见内核代码include/linux/skbuff.h)。其中的data成员是接管到的数据,在协定栈逐层被解决的时候,通过批改指针指向data的不同地位,来找到每一层协定关怀的数据。 对于TCP协定包来说,它的Header中有一个重要的字段-flags。 如下图: 通过设置不同的标记位,将TCP包分成SYNC、FIN、ACK、RST等类型: 1)客户端通过connect零碎调用命令内核收回SYNC、ACK等包来实现和服务器TCP连贯的建设;2)在服务器端,可能会接管许许多多的连贯申请,内核还须要借助一些辅助数据结构-半连贯队列和全连贯队列。咱们来看一下整个连贯过程: 在这个连贯过程中,咱们来简略剖析一下每一步的耗时: 1)客户端收回SYNC包:客户端个别是通过connect零碎调用来收回SYN的,这里牵涉到本机的零碎调用和软中断的CPU耗时开销;2)SYN传到服务器:SYN从客户端网卡被收回,开始“跨过山和大海,也穿过三三两两......”,这是一次短途远距离的网络传输;3)服务器解决SYN包:内核通过软中断来收包,而后放到半连贯队列中,而后再收回SYN/ACK响应。又是CPU耗时开销;4)SYC/ACK传到客户端:SYC/ACK从服务器端被收回后,同样跨过很多山、可能很多大海来到客户端。又一次短途网络跋涉;5)客户端解决SYN/ACK:客户端内核收包并解决SYN后,通过几us的CPU解决,接着收回ACK。同样是软中断解决开销;6)ACK传到服务器:和SYN包,一样,再通过简直同样远的路,传输一遍。 又一次短途网络跋涉;7)服务端收到ACK:服务器端内核收到并解决ACK,而后把对应的连贯从半连贯队列中取出来,而后放到全连贯队列中。一次软中断CPU开销;8)服务器端用户过程唤醒:正在被accpet零碎调用阻塞的用户过程被唤醒,而后从全连贯队列中取出来曾经建设好的连贯。一次上下文切换的CPU开销。 以上几步操作,能够简略划分为两类: 第一类:是内核耗费CPU进行接管、发送或者是解决,包含零碎调用、软中断和上下文切换。它们的耗时根本都是几个us左右;第二类:是网络传输,当包被从一台机器上收回当前,两头要通过各式各样的网线、各种交换机路由器。所以网络传输的耗时相比本机的CPU解决,就要高的多了。依据网络远近个别在几ms~到几百ms不等。 1ms就等于1000us,因而网络传输耗时比双端的CPU开销要高1000倍左右,甚至更高可能还到100000倍。 所以:在失常的TCP连贯的建设过程中,个别思考网络延时即可。 PS:一个RTT指的是包从一台服务器到另外一台服务器的一个来回的延迟时间。所以从全局来看:TCP连贯建设的网络耗时大概须要三次传输,再加上少许的单方CPU开销,总共大概比1.5倍RTT大一点点。 不过,从客户端视角来看:只有ACK包收回了,内核就认为连贯是建设胜利了。所以如果在客户端打点统计TCP连贯建设耗时的话,只须要两次传输耗时-既1个RTT多一点的工夫。(对于服务器端视角来看同理,从SYN包收到开始算,到收到ACK,两头也是一次RTT耗时)。 4、极其状况下的TCP连贯耗时剖析上一节能够看到:在客户端视角,失常状况下一次TCP连贯总的耗时也就就大概是一次网络RTT的耗时。如果所有的事件都这么简略,我想我的这次分享也就没有必要了。事件不肯定总是这么美妙,意外的产生在劫难逃。 在某些状况下,可能会导致TCP连贯时的网络传输耗时上涨、CPU解决开销减少、甚至是连贯失败。本节将就我在线上遇到过的各种切身体会的沟沟坎坎,来剖析一下极其状况下的TCP连贯耗时状况。 4.1 客户端connect调用耗时失控案例失常一个零碎调用的耗时也就是几个us(微秒)左右。然而在我的《追踪将服务器CPU耗光的凶手!》一文中,笔者的一台服务器过后遇到一个情况:某次运维同学转达过去说该服务CPU不够用了,须要扩容。 过后的服务器监控如下图: 该服务之前始终每秒抗2000左右的qps,CPU的idel始终有70%+,怎么忽然就CPU一下就不够用了呢。 而且更奇怪的是CPU被打到谷底的那一段时间,负载却并不高(服务器为4核机器,负载3-4是比拟失常的)。 起初通过排查当前发现当TCP客户端TIME_WAIT有30000左右,导致可用端口不是特地短缺的时候,connect零碎调用的CPU开销间接上涨了100多倍,每次耗时达到了2500us(微秒),达到了毫秒级别。 当遇到这种问题的时候,尽管TCP连贯建设耗时只减少了2ms左右,整体TCP连贯耗时看起来还可承受。但这里的问题在于这2ms多都是在耗费CPU的周期,所以问题不小。 解决起来也非常简单,方法很多:批改内核参数net.ipv4.ip_local_port_range多预留一些端口号、改用长连贯都能够。 4.2 TCP半/全连贯队列满的案例如果连贯建设的过程中,任意一个队列满了,那么客户端发送过去的syn或者ack就会被抛弃。客户端期待很长一段时间无果后,而后会收回TCP Retransmission重传。 拿半连贯队列举例: 要晓得的是下面TCP握手超时重传的工夫是秒级别的。也就是说一旦server端的连贯队列导致连贯建设不胜利,那么光建设连贯就至多须要秒级以上。而失常的在同机房的状况下只是不到1毫秒的事件,整整高了1000倍左右。 尤其是对于给用户提供实时服务的程序来说,用户体验将会受到较大影响。如果连重传也没有握手胜利的话,很可能等不及二次重试,这个用户拜访间接就超时了。 还有另外一个更坏的状况是:它还有可能会影响其它的用户。 如果你应用的是过程/线程池这种模型提供服务,比方:php-fpm。咱们晓得fpm过程是阻塞的,当它响应一个用户申请的时候,该过程是没有方法再响应其它申请的。如果你开了100个过程/线程,而某一段时间内有50个过程/线程卡在和redis或者mysql服务器的握手连贯上了(留神:这个时候你的服务器是TCP连贯的客户端一方)。这一段时间内相当于你能够用的失常工作的过程/线程只有50个了。而这个50个worker可能基本解决不过去,这时候你的服务可能就会产生拥挤。再继续略微工夫长一点的话,可能就产生雪崩了,整个服务都有可能会受影响。 既然结果有可能这么重大,那么咱们如何查看咱们手头的服务是否有因为半/全连贯队列满的状况产生呢? 在客户端:能够抓包查看是否有SYN的TCP Retransmission。如果有偶发的TCP Retransmission,那就阐明对应的服务端连贯队列可能有问题了。 在服务端的话:查看起来就更不便一些了。netstat -s 可查看到以后零碎半连贯队列满导致的丢包统计,但该数字记录的是总丢包数。你须要再借助 watch 命令动静监控。如果上面的数字在你监控的过程中变了,那阐明以后服务器有因为半连贯队列满而产生的丢包。你可能须要加大你的半连贯队列的长度了。 $ watch'netstat -s | grep LISTEN' 8 SYNs to LISTEN sockets ignored对于全连贯队列来说呢,查看办法也相似: $ watch'netstat -s | grep overflowed' ...

May 26, 2022 · 1 min · jiezi

关于网络编程:各位网工地址你会分类吗

大家早晨好,明天的内容来啦! 地址,你会分类吗?? A类可用于调配应用的地址范畴: 1.0.0.0~126.255.255.255 B始终10结尾的地址是B类地址: 10 000000-10 111111 128.0.0.0-191.255.255.255 C始终110结尾的地址: 110 00000-110 11111 192.0.0.0-223.255.255.255 D始终110开关的地址: 11100000-11101111 224.0.0.0 – 239.255.255.255 E始终1111结尾的地址: 111 0000-1111 1111 240.0.0.0-255.255.255.255 ABC类为单播地址,用于1对1通信,D类为组播地址,用于1对多通信,E类为保留的单播地址,用于军事,科研,当初曾经应用结束。 ABC中分为私网地址和公网地址: 私网地址:所有机构或者集体能够随便应用,无需申请,用于企业外部组网 私网地址能够重复使用,进步地址利用率,节俭公网地址 公网地址:用于拜访互联网,须要申请 A类私网地址 10.0.0.0 -10.255.255.255 B类私网地址 172.16.0.0 - 172.31.255.255 C类私网地址 192.168.0.0 - 192.168.255.255 其余的均为公网地址,目前所有ipv4公网地址均已调配结束 A类地址构造:8bit 网络位 + 24bit 主机位 B类地址构造:16bit 网络位 + 16bit 主机位 C类地址构造:24bit 网络位 + 8bit 主机位 为了解决IP地址短缺的问题,提出了公有地址的概念。公有地址是指外部网络或主机地址,这些地址只能用于某个外部网络,不能用于公共网络。 公网IP地址:连贯到Internet的网络设备必须具备由ICANN调配的公网IP地址。 私网IP地址:私网IP地址的应用使得网络能够失去更为自在地扩大,因为同一个私网IP地址是能够在不同的公有网络中重复使用的。 公有网络连接到Internet:公有网络因为应用了私网IP地址,是不容许连贯到Internet的。起初在理论需要的驱动下,许多公有网络也心愿可能连贯到Internet上,从而实现私网与Internet之间的通信,以及通过Internet实现私网与私网之间的通信。私网与Internet的互联,必须应用网络地址转换 (NAT)技术实现。 注: NAT (Network Address Translation),网络地址转换,其根本作用是实现私网IP地址与公网IP地址之间的转换。 IANA (Internet Assigned Numbers Authority),因特网地址调配组织。 ...

May 16, 2022 · 1 min · jiezi

关于网络编程:网络编程Socket-套接字编程

网络编程内容介绍 网络通信协定UDP通信TCP通信 内容学习指标可能独立实现“文件上传”案例的源代码编写、编译、运行的操作网络通信协定通过计算机网络能够使多台计算机实现连贯,位于同一个网络中的计算机在进行连贯和通信时须要恪守肯定的规定,这就好比在路线中行驶的汽车肯定要恪守交通规则一样。在计算机网络中,这些连贯和通信的规定被称为网络通信协定,它对数据的传输格局、传输速率、传输步骤等做了对立规定,通信单方必须同时恪守能力实现数据交换。网络通信协定有很多种,目前利用最宽泛的是TCP/IP协定(Transmission Control Protocal/Internet Protoal传输控制协议/英特网互联协定),它是一个包含TCP协定和IP协定,UDP(User Datagram Protocol)协定和其它一些协定的协定组,在学习具体协定之前首先理解一下TCP/IP协定组的层次结构。在进行数据传输时,要求发送的数据与收到的数据齐全一样,这时,就须要在原有的数据上增加很多信息,以保证数据在传输过程中数据格式完全一致。TCP/IP协定的层次结构比较简单,共分为四层,如图所示。 上图中,TCP/IP协定中的四层别离是应用层、传输层、网络层和链路层,每层别离负责不同的通信性能,接下来针对这四层进行具体地解说。链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设施的驱动协定,例如针对光纤、网线提供的驱动。网络层:网络层是整个TCP/IP协定的外围,它次要用于将传输的数据进行分组,将分组数据发送到指标计算机或者网络。运输层:次要使网络程序进行通信,在进行网络通信时,能够采纳TCP协定,也能够采纳UDP协定。应用层:次要负责应用程序的协定,例如HTTP协定、FTP协定等。IP地址和端口号要想使网络中的计算机可能进行通信,必须为每台计算机指定一个标识号,通过这个标识号来指定承受数据的计算机或者发送数据的计算机。在TCP/IP协定中,这个标识号就是IP地址,它能够惟一标识一台计算机,目前,IP地址宽泛应用的版本是IPv4,它是由4个字节大小的二进制数来示意,如:00001010000000000000000000000001。因为二进制模式示意的IP地址十分不便记忆和解决,因而通常会将IP地址写成十进制的模式,每个字节用一个十进制数字(0-255)示意,数字间用符号“.”离开,如 “192.168.1.100”。随着计算机网络规模的不断扩大,对IP地址的需要也越来越多,IPV4这种用4个字节示意的IP地址面临枯竭,因而IPv6 便应运而生了,IPv6应用16个字节示意IP地址,它所领有的地址容量约是IPv4的8×1028倍,达到2128个(算上全零的),这样就解决了网络地址资源数量不够的问题。通过IP地址能够连贯到指定计算机,但如果想拜访指标计算机中的某个应用程序,还须要指定端口号。在计算机中,不同的应用程序是通过端口号辨别的。端口号是用两个字节(16位的二进制数)示意的,它的取值范畴是065535,其中,01023之间的端口号用于一些出名的网络服务和利用,用户的一般应用程序须要应用1024以上的端口号,从而防止端口号被另外一个利用或服务所占用。接下来通过一个图例来形容IP地址和端口号的作用,如下图所示。 从上图中能够分明地看到,位于网络中一台计算机能够通过IP地址去拜访另一台计算机,并通过端口号拜访指标计算机中的某个应用程序。InetAddress理解了IP地址的作用,咱们看学习下JDK中提供了一个InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相干的办法,下表中列出了InetAddress类的一些罕用办法。办法申明性能形容InetAddress getByName(String host)参数host示意指定的主机,该办法用于在给定主机名的状况下确定主机的 IP 地址InetAddress getLocalHost()创立一个示意本地主机的InetAddress对象String getHostName()失去IP地址的主机名,如果是本机则是计算机名,不是本机则是主机名,如果没有域名则是IP地址String getHostAddress()失去字符串格局的原始 IP 地址上表中,列举了InetAddress的四个罕用办法。其中,前两个办法用于取得该类的实例对象,第一个办法用于取得示意指定主机的InetAddress对象,第二个办法用于取得示意本地的InetAddress对象。通过InetAddress对象便可获取指定主机名,IP地址等,接下来通过一个案例来演示InetAddress的罕用办法,如下所示。import java.net.InetAddress;public class Example01 {public static void main(String[] args) throws Exception {InetAddress localAddress = InetAddress.getLocalHost();InetAddress remoteAddress = InetAddress.getByName("www.atguigu.cn");System.out.println("本机的IP地址:" +localAddress.getHostAddress());System.out.println("atguigu的IP地址:" +remoteAddress.getHostAddress());System.out.println("atguigu的主机名为:" + remoteAddress.getHostName());}UDP与TCP协定在介绍TCP/IP构造时,提到传输层的两个重要的高级协定,别离是UDP和TCP,其中UDP是User Datagram Protocol的简称,称为用户数据报协定,TCP是Transmission Control Protocol的简称,称为传输控制协议。UDP协定介绍UDP是无连贯通信协议,即在数据传输时,数据的发送端和接收端不建设逻辑连贯。简略来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会收回数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。因为应用UDP协定耗费资源小,通信效率高,所以通常都会用于音频、视频和一般数据的传输例如视频会议都应用UDP协定,因为这种状况即便偶然失落一两个数据包,也不会对接管后果产生太大影响。然而在应用UDP协定传送数据时,因为UDP的面向无连接性,不能保证数据的完整性,因而在传输重要数据时不倡议应用UDP协定。UDP的替换过程如下图所示。 TCP协定介绍TCP协定是面向连贯的通信协议,即在传输数据前先在发送端和接收端建设逻辑连贯,而后再传输数据,它提供了两台计算机之间牢靠无差错的数据传输。在TCP连贯中必须要明确客户端与服务器端,由客户端向服务端收回连贯申请,每次连贯的创立都须要通过“三次握手”。第一次握手,客户端向服务器端收回连贯申请,期待服务器确认,第二次握手,服务器端向客户端回送一个响应,告诉客户端收到了连贯申请,第三次握手,客户端再次向服务器端发送确认信息,确认连贯。整个交互过程如下图所示。 因为TCP协定的面向连贯个性,它能够保障传输数据的安全性,所以是一个被宽泛采纳的协定,例如在下载文件时,如果数据接管不残缺,将会导致文件数据失落而不能被关上,因而,下载文件时必须采纳TCP协定。UDP通信DatagramPacket后面介绍了UDP是一种面向无连贯的协定,因而,在通信时发送端和接收端不必建设连贯。UDP通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接管货物时都须要应用集装箱来装载货物,UDP通信也是一样,发送和接管的数据也须要应用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接管的数据。想要创立一个DatagramPacket对象,首先须要理解一下它的构造方法。在创立发送端和接收端的DatagramPacket对象时,应用的构造方法有所不同,接收端的构造方法只须要接管一个字节数组来寄存接管到的数据,而发送端的构造方法岂但要接管寄存了发送数据的字节数组,还须要指定发端口号送端IP地址和。接下来依据API文档的内容,对DatagramPacket的构造方法进行逐个具体地解说。 DatagramPacket(byte[] buf,int length): 应用该构造方法在创立DatagramPacket对象时,指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号。很显著,这样的对象只能用于接收端,不能用于发送端。因为发送端肯定要明确指出数据的目的地(ip地址和端口号),而接收端不须要明确晓得数据的起源,只须要接管到数据即可。 DatagramPacket(byte[] buf,int length,InetAddress addr,int port): 应用该构造方法在创立DatagramPacket对象时,不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的指标IP地址(addr)和端口号(port)。该对象通常用于发送端,因为在发送数据时必须指定接收端的IP地址和端口号,就如同发送货物的集装箱下面必须表明接管人的地址一样。下面咱们解说了DatagramPacket的构造方法,接下来对DatagramPacket类中的罕用办法进行具体地解说,如下表所示。办法申明性能形容InetAddress getAddress()该办法用于返回发送端或者接收端的IP地址,如果是发送端的DatagramPacket对象,就返回接收端的IP地址,反之,就返回发送端的IP地址int getPort()该办法用于返回发送端或者接收端的端口号,如果是发送端的DatagramPacket对象,就返回接收端的端口号,反之,就返回发送端的端口号byte[] getData()该办法用于返回将要接管或者将要发送的数据,如果是发送端的DatagramPacket对象,就返回将要发送的数据,反之,就返回接管到的数据int getLength()该办法用于返回接管或者将要发送数据的长度,如果是发送端的DatagramPacket对象,就返回将要发送的数据长度,反之,就返回接管到数据的长度DatagramSocketDatagramPacket数据包的作用就如同是“集装箱”,能够将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还须要有码头。在程序中须要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的作用就相似于码头,应用这个类的实例对象就能够发送和接管DatagramPacket数据包,发送数据的过程如下图所示。 在创立发送端和接收端的DatagramSocket对象时,应用的构造方法也有所不同,上面对DatagramSocket类中罕用的构造方法进行解说。 DatagramSocket(): 该构造方法用于创立发送端的DatagramSocket对象,在创立DatagramSocket对象时,并没有指定端口号,此时,零碎会调配一个没有被其它网络程序所应用的端口号。 DatagramSocket(int port): 该构造方法既可用于创立接收端的DatagramSocket对象,又能够创立发送端的DatagramSocket对象,在创立接收端的DatagramSocket对象时,必须要指定一个端口号,这样就能够监听指定的端口。下面咱们解说了DatagramSocket的构造方法,接下来对DatagramSocket类中的罕用办法进行具体地解说。办法申明性能形容void receive(DatagramPacket p)该办法用于将接管到的数据填充到DatagramPacket数据包中,在接管到数据之前会始终处于阻塞状态,只有当接管到数据包时,该办法才会返回void send(DatagramPacket p)该办法用于发送DatagramPacket数据包,发送的数据包中蕴含将要发送的数据、数据的长度、近程主机的IP地址和端口号void close()敞开以后的Socket,告诉驱动程序开释为这个Socket保留的资源UDP网络程序解说了DatagramPacket和DatagramSocket的作用,接下来通过一个案例来学习一下它们在程序中的具体用法。下图为UDP发送端与接收端交互图解,原图为UDP图解.bmp ...

April 15, 2022 · 2 min · jiezi

关于网络编程:网络编程入门从未如此简单三什么是IPv6漫画式图文一篇即懂

本文由小枣君分享,文案:小枣君、漫画:杨洋,来自鲜枣课堂,有少许改变,原文链接见文末。 1、引言网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的实践根基,因此粗浅精确地了解计算机网络常识显然能夯实你的即时通讯利用的实际品质。 本文格调连续了社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,没有更多的实践堆砌,艰深而不失外延,非常适合心愿轻松高兴地学习计算机网络常识的网络编程爱好者们浏览,心愿能给你带来不一样的网络常识入门视角。 本篇文章将利用简洁活泼的文字,配上轻松风趣的漫画,助你从零开始疾速建设起对IPv6技术的直观了解,非常适合入门者浏览。 学习交换: 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2... (本文同步公布于:http://www.52im.net/thread-38...) 2、系列文章本文是该系列文章中的第3篇: 《网络编程入门从未如此简略(一):如果你来设计网络,会怎么做?》《网络编程入门从未如此简略(二):如果你来设计TCP协定,会怎么做?》《网络编程入门从未如此简略(三):什么是IPv6?漫画式图文,一篇即懂!》(本文) 本文是IPv6的轻松入门文章,心愿你能喜爱。 举荐浏览:本文作者的另一篇也同样优良:网络编程懒人入门(十一):一文读懂什么是IPv6,感兴趣的倡议一并浏览 。3、技术背景随着挪动网络的一直建设和遍及,减速了咱们迈入万物互联时代的步调。 咱们的整个互联网络,正在产生天翻地覆的变动。急剧减少的网络连接数和流量,对网络的承载和传送能力,提出了前所未有的挑战。 除了速率和带宽之外,5G在垂直行业的落地,也要求网络可能提供灵便的差异化定制服务能力。 也就是说,面对不同的行业利用场景,网络须要可能提供套餐式的服务,反对不同的QoS(Quality of Service,服务质量),反对端到端的切片。 4、IP协定家喻户晓,咱们当初如影随行的互联网,最早诞生于上世纪60年代。它的外围根底,就是赫赫有名的IP协定(Internet Protocol,网际互连协定,见《技术往事:扭转世界的TCP/IP协定(宝贵多图、手机慎点)》)。 如果没有IP协定,以及基于它的IP地址,咱们就没方法刷剧、网购、吃鸡、聊微信。 说白了,互联网就是一套“快递零碎”。IP地址是你的快递地址,而IP协定,则是快递公司的“工作流程和制度”。 所有咱们须要传递的信息,包含文字、图片、音频、视频等,都须要被打包成一个个的“快递包裹”,而后通过快递零碎的运输,送到最终目的地。 5、第一、第二代“快递零碎”:IPv4互联网诞生后,长期应用的是v4版本的IP协定,也就是大家熟知的IPv4。 咱们能够把它了解为第一代快递零碎,它为互联网的晚期倒退奠定了坚实基础。 起初,随着互联网的迅速倒退扩张,原始的IPv4零碎暴露出了很多的问题,进行了一些技术上的降级改良。尤其是MPLS(Multi-Protocol Label Switching,多协定标签替换)技术的引入,将这个快递系统升级到了第二代。 到了最近这几年,因为后面咱们提到的网络挑战,远远超过了第二代快递零碎的能力范畴。 6、第三代“快递零碎”:IPv6于是,IPv6以及IPv6+,作为第三代快递零碎,正式闪亮退场。 IPv6,是v6版本的IP协定。而IPv6+,则是IPv6的降级加强版。 具体来说,IPv6+基于IPv6,实现了更多的翻新。 这些翻新,既包含以IPv6分段路由、网络切片、随流检测、新型组播和利用感知网络等协定为代表的协定翻新,又包含以网络分析、主动调优、网络自愈等网络智能化为代表的技术创新。 凭借这些翻新,IPv6+更适宜行业用户,更可能无力撑持行业的数字化转型和倒退。 接下来,咱们认真看看,IPv6+到底带来了哪些变动和降级。 7、IPv6劣势1:IP地址大幅减少首先,IPv6最广为人知的长处就是IP地址的大幅减少。具体来说,IPv6的地址数量是IPv4的2的96次方倍(详见《一文读懂什么是IPv6》的第6节内容)。 这么说吧,如果采纳IPv6,即使是给地球上的每粒沙子都赋予一个IP地址,都入不敷出。 传统的IPv4快递零碎,邮箱地址不够,快递员往往须要将疾速送到门卫处或快递柜,而后再二次派送给用户(在IPv4时代,这就是NAT路由技术啦,详见《NAT详解——具体原理、P2P简介》、《什么是公网IP和内网IP?NAT转换又是什么鬼?》)。 在IPv6疾速零碎下,每个用户都有属于本人的邮箱地址,快递员能够间接将快递送到用户手中。 很显然,这样不仅晋升了快递的收发速度,也节俭了门卫或快递柜的开销,简化了保护,缩小了能耗,升高了老本。 其实,IP地址数量的压力,次要来自物联网场景。因为物的数量远远超过人的数量。而且,物联网的管制,更须要端到端的中转。这样能力有更低的时延,实现更精准的管制。 8、IPv6劣势2:“快递包装”的降级IPv6的第二个重大改良,在于“快递包装”的降级。IPv6的数据报文构造变得更加丰盛,外面能够记录更多的内容和信息。 简略来说,就是运输快递的纸箱变得更高级了。 传统的快递零碎,包装很简略,咱们并不知道外面到底是什么物品。 IPv6的快递零碎,纸箱上能够贴更多的标签,标识纸箱里的货物属性,例如重货、易碎品、紧急文件等。零碎依据标签,能够疾速判断这个快递包裹所需的服务,例如须要加急、须要小心轻放等。 这样一来,快递公司能够依据包裹显示的信息,为不同的客户提供更精细化的服务,采纳差异化的免费规范。 快递公司还能够走精品路线,提供专属的快递通道,实现高端用户的资源独享。 IPv6+对数据包属性的精准辨认,也能够帮忙运营商更好地把握整个网络中数据业务的流动趋势,更好地调动和分配资源。 例如,从A地到B地的视频大颗粒传输需要很多,那么,就能够建设视频大颗粒业务专线,更好地满足传输需要。 这就如同从A地到B地的海鲜运输需要很多,那快递公司就洽购更多的冷链运输车,专门投入到这条线路上,赚取更多的利润。 9、IPv6劣势3:降级了“导航能力”传统快递零碎的运输门路,是绝对固定和死板的。运输车从终点到起点,通过每一个路口,都由路口指定下一步后退的方向。 而IPv6+的话,通过与SR(Segment Routing,分段路由)技术、SDN(Software Defined Network,软件定义网络)技术进行联合,具备更强的门路抉择能力。 快递包裹在登程时,就曾经从管理中心取得了从终点到起点的最佳门路。每一次选路,都依照布局进行,能够避开拥挤,也能够防止绕路。 换言之,IPv6+超强的门路编排能力,能够实现数据报文的一跳入云,大幅晋升效率。 10、IPv6劣势4:升高运维老本因为网络的治理性能集中,能够更不便地将配置用意转换成脚本,主动部署给各个网络节点。 引入AI之后,更可能对故障景象进行主动剖析,更快地找到起因。 甚至说,AI还能够依据对故障模型的学习,被动提前辨认网络中潜在的故障危险,实现事变预防。 集中管理+AI治理,大幅升高了网络的保护难度,晋升了运维效率,缩小了保护老本。 11、IPv6劣势5:更平安IPv6+的平安防御能力相比IPv4有了很大的晋升,真正实现了云、网、安一体化进攻。 传统网络中,因为大量私网的存在,歹意行为很难溯源。也就是说,很多好人躲在暗处,收回有问题的包裹,对快递零碎造成毁坏。 在IPv6+网络中,节点采纳公网地址取代私网地址,这就意味着,在快递零碎中运输的每一个包裹,都有实在可溯源的寄件人信息。失去了私网的假装,毁坏行为将无所遁形。 降级后的快递包装(数据报文构造),也大幅减少了破坏分子对包裹进行歹意伪造和窃听的难度,加强了包裹的安全性和私密性。 ...

March 30, 2022 · 1 min · jiezi

关于网络编程:用-Python-写网络编程四

复习功课 第一篇地址 第二篇地址 第三篇地址 逐渐讲述回包间接入正题,第三篇曾经提到了如何收到回包,以后这个主题网络编程都是讲 Tcp,协定申请形式自身会决定个性,咱们这里先讲和发包收包程序无关的。 Tcp 首先是一个双工的,意思就是客户端 C 端发消息给 S 端,S 端也能够发消息给客户端,传输协定数据类型外面传输在网卡那层都是二进制文件流。为啥是流而不是包能够回顾之前的,也能够抉择死记硬背。 那么 C 端是不是发给 S 端音讯,S 端肯定是要回复的呢,这个是未必的。因为在协定申请/传输方式还会传输协定数据类型,这个类型和业务是间接无关的,大体能够分为须要应答和不须要应答。不须要应答的最常见的就是心跳包。这里为啥要叫包而不是叫心跳流呢,只能说是一种通用的叫法。 当客户端链接上服务后,每隔约一段时间,往服务器固定传输一段信息,就和人的心电图一样,证实以后客户端是沉闷的。如果不沉闷服务器会把客户端对象断开(Tcp 挥手),这里不沉闷个别是指多少次没有收到,才会判断不沉闷。 断开的益处,这里能够这样记忆,每个 socket 链接是肯定有老本的,放弃链接状态也一样,每个 socket 做一些事会产生内存变动(这里不思考软件缓存,硬件的几级缓存),如果在把一些数据存储到数据库,就会把内存数据交换到数据库或者数据库缓存,交互过程也会产生内存碎片和数据库 IO 开销。只是是沉闷的,就会依据这个 socket 做得事件产生一系列的非用户态的一些开销,所以有必要剔除不沉闷的申请。 比方 30 分钟没有取得教训/多少分钟没有挪动(挪动也会产生挪动数据包,这个数据包会逐条同步给他四周的沉闷用户),而后就会进入挂机状态,这种其实也是相似把 fb 标记为了不沉闷 (leave = no alive),不沉闷就只须要定期同步一次。 如果是齐全下线 (close),这里撇开业务,齐全下线也会主动挂机获取教训。 以上次要缓缓开展客户端发了 3 次 100 个字节后期待几百 ms,然而服务器只回了一组包,这个是 Tcp 独有黏包的问题。 然而发现这样跨度有点大,例子比拟根底,会先来通过一个 Tcp 心跳的例子(分四,五章节)来缓缓往后延长,反正最终都会讲清楚的。 心跳学习和设计写个例子来做一些直观性的推理和设计,例子也会联合之前的一些知识点。 心跳信息:json 字串 # 实战外面是一个 bytes 模式 这个 butes 会比拟小,只是为了让服务器计数客户端是沉闷的。 详解 服务器那边记录一个客户端连贯句柄的治理字典,链接的客户端对象在服务器那边会是一个"fd",是否沉闷会是一个字段"status":"alive",""leave","close" 别离代表 沉闷,非沉闷暂离,敞开。 服务器那边进行开发设计,反对状态为一个双向的程序 ("alive"<-->"leave"<-->"close") 对于 status:"alive"状态条件 客户端来说是默认的,没在 socket.error 那层被拦挡掉,所以链接上了,链接上分为地址正确,写法正确,防火墙容许 (这里测试用不上这个) ...

February 16, 2022 · 3 min · jiezi

关于网络编程:网络编程懒人入门十四到底什么是Socket一文即懂

本文由cxuan分享,原题“原来这才是 Socket”,有订正。 1、引言本系列文章后面那些次要解说的是计算机网络的实践根底,但对于即时通讯IM这方面的应用层开发者来说,跟计算机网络打道的其实是各种API接口。 本篇文章就来聊一下网络应用程序员最相熟的Socket这个货色,抛开生涩的计算机网络实践,从应用层的角度来了解到底什么是Socket。 对于 Socket 的意识,本文将从以下几个方面着手介绍: 1)Socket 是什么;2)Socket 是如何创立的;3)Socket 是如何连贯的;4)Socket 是如何收发数据的;5)Socket 是如何断开连接的;6)Socket 套接字的删除等。 特地阐明:本文中提到的“Socket”、“网络套接字”、“套接字”,如无非凡指明,指的都是同一个货色哦。 学习交换: 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文已同步公布于:http://www.52im.net/thread-38...) 2、Socket 是什么一个数据包经由应用程序产生,进入到协定栈中进行各种报文头的包装,而后操作系统调用网卡驱动程序指挥硬件,把数据发送到对端主机。 整个过程的大体的图示如下: 咱们大家晓得,协定栈其实是位于操作系统中的一些协定的重叠,这些协定包含 TCP、UDP、ARP、ICMP、IP等。 通常某个协定的设计都是为了解决特定问题的,比方: 1)TCP 的设计就负责安全可靠的传输数据;2)UDP 设计就是报文小,传输效率高;3)ARP 的设计是可能通过 IP 地址查问物理(Mac)地址;4)ICMP 的设计目标是返回谬误报文给主机;5)IP 设计的目标是为了实现大规模主机的互联互通。 应用程序比方浏览器、电子邮件、文件传输服务器等产生的数据,会通过传输层协定进行传输。而应用程序是不会和传输层间接建立联系的,而是有一个可能连贯应用层和传输层之间的套件,这个套件就是 Socket。 在下面这幅图中,应用程序蕴含 Socket 和解析器,解析器的作用就是向 DNS 服务器发动查问,查问指标 IP 地址(对于DNS请见《实践联系实际,全方位深刻了解DNS》)。 应用程序的上面:就是操作系统外部,操作系统外部包含协定栈,协定栈是一系列协定的重叠。 操作系统上面:就是网卡驱动程序,网卡驱动程序负责管制网卡硬件,驱动程序驱动网卡硬件实现收发工作。 在操作系统外部有一块用于寄存管制信息的存储空间,这块存储空间记录了用于管制通信的管制信息。其实这些管制信息就是 Socket 的实体,或者说寄存管制信息的内存空间就是Socket的实体。 这里大家有可能不太分明所以然,所以我用了一下 netstat 命令来给大伙看一下Socket是啥玩意。 咱们在 Windows 的命令提示符中输出: netstat-ano netstat 用于显示Socket内容 , -ano 是可选选项a 不仅显示正在通信的Socket,还显示包含尚未开始通信等状态的所有Socketn 显示 IP 地址和端口号o 显示Socket的程序 PID我的计算机会呈现上面后果: 如上图所示: 1)每一行都相当于一个Socket;2)每一列也被称为一个元组。 所以,一个Socket就是五元组: 1)协定;2)本地地址;3)内部地址;4)状态;5)PID。 PS:有的时候也被叫做四元组,四元组不包含协定。 ...

February 16, 2022 · 2 min · jiezi

关于网络编程:用-Python-写网络编程三

前言明天是一个特地的节日,1946 年情人节(原文发表日期是2021.2.14),世界上第一台计算机 ENIAC 在米国的宾夕法尼亚大学被 new 了,标记着新的时代到来。计算机陪伴人类曾经走过了 75 个年头,所以明天,没啥特地的事件,请多去陪一陪本人家的电脑,手动狗头,手动狗头。网络编程会是一个比拟宏大的常识体系,第三篇会开始讲如何 encode 和 decode。第一篇的数据结构是提供给第三篇应用的,而后通过第二篇的通道进行传输。 复习功课第一篇地址第二篇地址 Tcp pickleTcp 网络流,加工过程也能够了解成是字节流到二进制流,字节就是第一篇提到的 bytes。encode 压包就是把字节流转换到二进制流,那么 Python 是通过怎么做到的呢。 次要分为二种,pickle(python 独有序列化字节数组),struct(从 C 那边继承来的序列化字节数组的)库。咱们看看 pickle 是如何序列化数据的。 def encode_pickle(packet:bytes): """ 压入pickle :param packet: :return: """ return pickle.pack(">i",len(packet))+packet留神这里并没有发包进来,回顾后面的,须要先建设 socket 链接,确认地址,能力进行发包。pickle.pack(fmt,*args) 的第一个参数 fmt 是个很重要的知识点。 先来理解下最重要的概念之一 fmt,家喻户晓,Python 是不须要先申明内存宽度,能力编程的。内存宽度是指内存外面占位的长度,在申明对象前会标注数据类型(动静语言没这个,动态语言很多有主动推断申明的 比方 golang var 和:=) 网络编程须要学习这块,是因为操作二进制,粗疏的话会标记为有符号和无符号。有符号和无符号做一些原子计算,做减法的时候,局部语言须要做一些非凡解决,还好 Python 不必放心这些,有符号个别是指蕴含正数。short 是有符号的 2 个字节的,unsigned short 是无符号的 2 个字节,正数这个下面图须要背下来。 网络自定义字节和字节序下面代码外面是 int 和 unsigned int,fmt 后面是主机字节序,">i"代表大端有符号的 4 个字节,"<"代表小端,"!"代表不必匹配。临时不思考具体学字节序转换的问题,目前网络编程是模仿客户端往服务器发。字节序别离有大端(big endian)和小端(little endian),程序的内容都是以字节为单位的,一个字节 8 位,每个地址对应一个字节。大端模式就是将数据的高位放在低位地址,低位地址就是左侧。转 16 进制只是给人读的,int 类型 4 个字节,ff 6c 5a 4s。小端就是大端反过来,是 4s 5a 6c ff。从这里能够发现大小端只是对内存寻址的程序无关,然而内存地址外面的 6c,5a 是不会变成 c6 和 a5 的这块问题,后期不相熟的话,能够通过问需要来确认如何写。 ...

February 15, 2022 · 2 min · jiezi

关于网络编程:iouring-vs-epoll-谁在网络编程领域更胜一筹

本文作者:王小光,「高性能存储技术SIG」核心成员。背景io_uring 在传统存储 io 场景曾经证实其价值,但 io_uring 不仅反对传统存储 io,也反对网络 io。io_uring 社区有泛滥的开发者尝试将 io_uring 用于网络应用。咱们之前也在《你认为 io_uring 只实用于存储 IO?大错特错!》中也摸索过 io_uring 在网络场景的利用及其与传统网络编程基石 epoll 的比照,过后咱们的测试结果显示在 cpu 破绽缓解使能的前提下,io_uring 相比于 epoll 能够带来肯定的劣势,在 cpu 漏铜缓解未使能时,io_uring 相比于 epoll 没有劣势,可能还会存在性能降落。在 io_uring 社区,对于 io_uring 和 epoll 孰优孰劣也始终存在争执,有些开发者声称 io_uring 能够取得比 epoll 更好的性能,有些开发者则声称二者性能持平或者 io_uring 甚至不如 epoll。相干的探讨十分多,具体可参见如下两例:https://github.com/axboe/libu...https://github.com/frevib/io_...以上探讨从 2020 年 8 月始终继续到当初,其过程十分长也十分地强烈。能够看出 io_uring 和 epoll 在网络编程畛域孰优孰劣目前的确比拟难以达成共识。目前很多业务想将 io_uring 在网络场景利用起来,但 io_uring 是否能比 epoll 带来性能晋升,大家或多或少存在些许疑难。为了彻底厘清这个问题,龙蜥社区高性能存储 SIG尝试从定量分析的角度,通过量化 io_uring 和 epoll 两种编程框架下的相干操作的耗时,来剖析二者的性能差别。评估模型咱们依然选用 echo server 模型进行性能评估,server 端采纳单线程模型,同时为偏心比照,io_uring 不应用外部的 io-wq 机制(io_uring 在内核态保护的线程池,能够用来执行用户提交的 io 申请)。epoll 采纳 send(2) 和 recv(2) 进行数据的读写操作;而 io_uring 采纳 IORING_OP_SEND 和 IORING_OP_RECV 进行数据的读写操作。联合 echo server 的模型,咱们剖析有四个因素会影响 io_uring 和 epoll 的性能,别离是:1、零碎调用用户态到内核态上下文切换开销,记为 s;2、零碎调用本身内核态工作逻辑开销,记为 w;3、io_uring 框架自身开销,记为 o;4、io_uring 的 batch 量,记为 n,epoll 版 echo server 因为间接调用 recv(2) 和 send(2), 其 batch 理论为 1。同时在本文中咱们仅评估 io_uring 和 epoll 申请读写操作的开销,对于 io_uring 和 epoll 自身的事件告诉机制自身不做掂量,因为通过 perf 工具剖析,读写申请自身开销占据绝大部分。零碎调用用户态到内核态上下文切换开销能够通过专门的程序进行测量,因素 2、3、4 等能够通过掂量内核相干函数的执行工夫进行测量,用 bpftrace 进行剖析。epoll 版 echo server 开销度量从用户态视角,send(2) 或者 recv(2) 开销次要蕴含两个方面,零碎调用用户态到内核态上下文切换开销和零碎调用本身内核态工作逻辑开销,其中零碎调用自身工作逻辑的开销,send(2) 和 recv(2) 别离掂量 sys_sendto(), sys_recvfrom() 即可。因为 epoll 场景下其零碎调用的 batch 为 1,因而 epoll 模型下收发申请的均匀耗时为 (s + w)。.io_uring 版 echo server 开销度量io_uring 中 io_uring_enter(2) 零碎调用既能够用来提交 sqe,也能够用来 reap cqe,两种操作混合在一个零碎调用中,精确掂量 sqe 的提交收发申请的耗时比拟艰难。简略起见,咱们采纳跟踪 io_submit_sqes() 的开销来掂量 IORING_OP_SEND 和 IORING_OP_RECV 的开销,此函数被 io_uring_enter(2) 所调用。io_submit_sqes() 蕴含send(2) 和 revc(2) 内核侧工作逻辑开销,及 io_uring 框架的开销,记为 t。同时咱们采纳 io_uring 的 multi-shot 模式,从而确保 io_submit_sqes() 中的提交的 IORING_OP_SEND 和 IORING_OP_RECV 申请都能够间接实现,而不会用到io_uring的 task-work 机制。因为 io_uring 场景下能够 batch 零碎调用的执行,因而 io_uirng 模型下收发申请的均匀耗时为 (s + t) / n。理论度量咱们测试环境 Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz,掂量 echo server 单链接性能数据。用户态内核态零碎调用上下文切换开销cpu 破绽对系统调用用户态内核态上下文切换的影响比拟大,在咱们的测试环境中:漏铜缓解使能时,零碎调用的上下文切换开销为 700ns 左右;漏铜缓解未使能时,零碎调用的上下文切换开销为 230ns 左右。epoll 模型下 send(2)/recv(2) 内核侧开销采纳bpftrace 脚本别离掂量 sys_sendto(),sys_recvfrom() 即可。bpftrace 脚本如下:BEGIN{ @start = 0; @send_time = 0; @send_count = 0;} ...

December 16, 2021 · 3 min · jiezi

关于网络编程:网络编程-学习系列目录更新ing

一、TCP/IP 网络编程学习

September 18, 2021 · 1 min · jiezi

关于网络编程:锁屏面试题百日百刷面试必问三次握手

锁屏面试题百日百刷,每个工作日保持更新面试题。锁屏面试题app、小程序现已上线,官网地址:https://www.demosoftware.cc/#/introductionPage。已收录了每日更新的面试题的所有内容,还蕴含特色的解锁屏幕温习面试题、每日编程题目邮件推送等性能。让你在面试中后人一步,吊打面试官!接下来的是今日的面试题: ====运行在TCP 或UDP的应用层协定剖析?运行在TCP协定上的协定:HTTP(Hypertext Transfer Protocol,超文本传输协定),次要用于一般浏览。HTTPS(HTTP over SSL,平安超文本传输协定),HTTP协定的平安版本。FTP(File Transfer Protocol,文件传输协定),用于文件传输。POP3(Post Office Protocol, version 3,邮局协定),收邮件用。SMTP(Simple Mail Transfer Protocol,简略邮件传输协定),用来发送电子邮件。TELNET(Teletype over the Network,网络电传),通过一个终端(terminal)登陆到网络。SSH(Secure Shell,用于代替安全性差的TELNET),用于加密平安登陆用。运行在UDP协定上的协定:BOOTP(Boot Protocol,启动协定),利用于无盘设施。NTP(Network Time Protocol,网络工夫协定),用于网络同步。DHCP(Dynamic Host Configuration Protocol,动静主机配置协定),动静配置IP地址。运行在TCP和UDP协定上:DNS(Domain Name Service,域名服务),用于实现地址查找,邮件转发等工作。ECHO(Echo Protocol,回绕协定),用于查错及测量应答工夫(运行在TCP和UDP协定上)。SNMP(Simple Network Management Protocol,简略网络管理协定),用于网络信息的收集和网络管理。DHCP(Dynamic Host Configuration Protocol,动静主机配置协定),动静配置IP地址。 ====什么是ARP协定 (Address Resolution Protocol)?ARP协定实现了IP地址与物理地址的映射。每一个主机都设有一个 ARP 高速缓存,外面有所在的局域网上的各主机和路由器的 IP 地址到硬件地址的映射表。当源主机要发送数据包到目标主机时,会先查看本人的ARP高速缓存中有没有目标主机的MAC地址,如果有,就间接将数据包发到这个MAC地址,如果没有,就向所在的局域网发动一个ARP申请的播送包(在发送本人的 ARP 申请时,同时会带上本人的 IP 地址到硬件地址的映射),收到申请的主机查看本人的IP地址和目标主机的IP地址是否统一,如果统一,则先保留源主机的映射到本人的ARP缓存,而后给源主机发送一个ARP响应数据包。源主机收到响应数据包之后,先增加目标主机的IP地址与MAC地址的映射,再进行数据传送。如果源主机始终没有收到响应,示意ARP查问失败。如果所要找的主机和源主机不在同一个局域网上,那么就要通过 ARP 找到一个位于本局域网上的某个路由器的硬件地址,而后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络。剩下的工作就由下一个网络来做。 ====什么是NAT (Network Address Translation, 网络地址转换)?用于解决内网中的主机要和因特网上的主机通信。由NAT路由器将主机的本地IP地址转换为寰球IP地址,分为动态转换(转换失去的寰球IP地址固定不变)和动静NAT转换。 ====从输出址到取得页面的过程?(重点常问)1). 浏览器查问 DNS,获取域名对应的IP地址:具体过程包含浏览器搜寻本身的DNS缓存、搜寻操作系统的DNS缓存、读取本地的Host文件和向本地DNS服务器进行查问等。对于向本地DNS服务器进行查问,如果要查问的域名蕴含在本地配置区域资源中,则返回解析后果给客户机,实现域名解析(此解析具备权威性);如果要查问的域名不禁本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,实现域名解析(此解析不具备权威性)。如果本地域名服务器并未缓存该网址映射关系,那么将依据其设置发动递归查问或者迭代查问;2). 浏览器取得域名对应的IP地址当前,浏览器向服务器申请建设链接,发动三次握手;3). TCP/IP链接建设起来后,浏览器向服务器发送HTTP申请;4). 服务器接管到这个申请,并依据门路参数映射到特定的申请处理器进行解决,并将处理结果及相应的视图返回给浏览器;5). 浏览器解析并渲染视图,若遇到对js文件、css文件及图片等动态资源的援用,则反复上述步骤并向服务器申请这些资源;6). 浏览器依据其申请到的资源、数据渲染页面,最终向用户出现一个残缺的页面。 ====讲一讲TCP的三次握手(重点常问)?在网络数据传输中,传输层协定TCP是要建设连贯的牢靠传输,TCP建设连贯的过程,咱们称为三次握手。 第一次握手:Client将SYN置1,随机产生一个初始序列号seq发送给Server,进入SYN_SENT状态;第二次握手:Server收到Client的SYN=1之后,晓得客户端申请建设连贯,将本人的SYN置1,ACK置1,产生一个acknowledge number=sequence number+1,并随机产生一个本人的初始序列号,发送给客户端;进入SYN_RCVD状态;第三次握手:客户端查看acknowledge number是否为序列号+1,ACK是否为1,查看正确之后将本人的ACK置为1,产生一个acknowledge number=服务器发的序列号+1,发送给服务器;进入ESTABLISHED状态;服务器查看ACK为1和acknowledge number为序列号+1之后,也进入ESTABLISHED状态;实现三次握手,连贯建设。简略来说就是:1). 客户端向服务端发送SYN2). 服务端返回SYN,ACK3). 客户端发送ACK====建设连贯能够两次握手吗?为什么?不能够。因为可能会呈现已生效的连贯申请报文段又传到了服务器端。 > client 收回的第一个连贯申请报文段并没有失落,而是在某个网络结点长时间的滞留了,以至延误到连贯开释当前的某个工夫才达到server。原本这是一个早已生效的报文段。但 server 收到此生效的连贯申请报文段后,就误认为是 client 再次收回的一个新的连贯申请。于是就向 client 收回确认报文段,批准建设连贯。假如不采纳 “三次握手”,那么只有 server 收回确认,新的连贯就建设了。因为当初 client 并没有收回建设连贯的申请,因而不会理会 server 的确认,也不会向 server 发送数据。但 server 却认为新的运输连贯曾经建设,并始终期待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采纳 “三次握手” 的方法能够避免上述景象产生。例如方才那种状况,client 不会向 server 的确认收回确认。server 因为收不到确认,就晓得 client 并没有要求建设连贯。而且,两次握手无奈保障Client正确接管第二次握手的报文(Server无奈确认Client是否收到),也无奈保障Client和Server之间胜利调换初始序列号。 ...

July 14, 2021 · 1 min · jiezi

关于网络编程:不为人知的网络编程十三深入操作系统彻底搞懂127001本机网络通信

本文作者张彦飞,原题“127.0.0.1 之本机网络通信过程知多少 ”,首次公布于“开发内功修炼”,转载请分割作者。本次有改变。 1、引言继《你真的理解127.0.0.1和0.0.0.0的区别?》之后,这是我整顿的第2篇无关本机网络方面的网络编程根底文章。 这次的文章由作者张彦飞原创分享,写作本文的起因是当初本机网络 IO 利用十分广。在 php 中 个别 Nginx 和 php-fpm 是通过 127.0.0.1 来进行通信的;在微服务中,因为 side car 模式的利用,本机网络申请更是越来越多。所以,如果能深度了解这个问题在各种网络通信利用的技术实际中将十分的有意义。 明天咱们就把 127.0.0.1 本机网络通信相干问题搞搞分明! 为了不便探讨,我把这个问题拆分成3问: 1)127.0.0.1 本机网络 IO 须要通过网卡吗?2)和外网网络通信相比,在内核收发流程上有啥差异?3)应用 127.0.0.1 能比 192.168.x 更快吗?下面这几个问题,置信包含常期混迹于即时通讯网的即时通讯老鸟们在内,都是看似很相熟,但实则依然无奈透彻讲清楚的话题。这次,咱们就来彻底搞清楚! (本文同步公布于:http://www.52im.net/thread-3600-1-1.html) 2、系列文章本文是系列文章中的第13篇,本系列文章的纲要如下: 《鲜为人知的网络编程(一):浅析TCP协定中的疑难杂症(上篇)》《鲜为人知的网络编程(二):浅析TCP协定中的疑难杂症(下篇)》《鲜为人知的网络编程(三):敞开TCP连贯时为什么会TIME_WAIT、CLOSE_WAIT》《鲜为人知的网络编程(四):深入研究剖析TCP的异样敞开》《鲜为人知的网络编程(五):UDP的连接性和负载平衡》《鲜为人知的网络编程(六):深刻地了解UDP协定并用好它》《鲜为人知的网络编程(七):如何让不牢靠的UDP变的牢靠?》《鲜为人知的网络编程(八):从数据传输层深度解密HTTP》《鲜为人知的网络编程(九):实践联系实际,全方位深刻了解DNS》《鲜为人知的网络编程(十):深刻操作系统,从内核了解网络包的接管过程(Linux篇)》《鲜为人知的网络编程(十一):从底层动手,深度剖析TCP连贯耗时的机密》《鲜为人知的网络编程(十二):彻底搞懂TCP协定层的KeepAlive保活机制》《鲜为人知的网络编程(十三):深刻操作系统,彻底搞懂127.0.0.1本机网络通信》(* 本文)3、作为比照,先看看跨机网路通信在开始讲述本机通信过程之前,咱们先看看跨机网络通信(以Linux零碎内核中的实现为例来解说)。 3.1 跨机数据发送从 send 零碎调用开始,直到网卡把数据发送进来,整体流程如下: 在下面这幅图中,咱们看到用户数据被拷贝到内核态,而后通过协定栈解决后进入到了 RingBuffer 中。随后网卡驱动真正将数据发送了进来。当发送实现的时候,是通过硬中断来告诉 CPU,而后清理 RingBuffer。 不过下面这幅图并没有很好地把内核组件和源码展现进去,咱们再从代码的视角看一遍。 等网络发送结束之后。网卡在发送结束的时候,会给 CPU 发送一个硬中断来告诉 CPU。收到这个硬中断后会开释 RingBuffer 中应用的内存。 3.2 跨机数据接管当数据包达到另外一台机器的时候,Linux 数据包的接管过程开始了(更具体的解说能够看看《深刻操作系统,从内核了解网络包的接管过程(Linux篇)》)。 ▲ 上图援用自《深刻操作系统,从内核了解网络包的接管过程(Linux篇)》 当网卡收到数据当前,CPU发动一个中断,以告诉 CPU 有数据达到。当CPU收到中断请求后,会去调用网络驱动注册的中断处理函数,触发软中断。ksoftirqd 检测到有软中断请求达到,开始轮询收包,收到后交由各级协定栈解决。当协定栈解决完并把数据放到接管队列的之后,唤醒用户过程(假如是阻塞形式)。 咱们再同样从内核组件和源码视角看一遍。 3.3 跨机网络通信汇总对于跨机网络通信的了解,能够艰深地用上面这张图来总结一下: 4、本机网络数据的发送过程在上一节中,咱们看到了跨机时整个网络数据的发送过程 。 在本机网络 IO 的过程中,流程会有一些差异。为了突出重点,本节将不再介绍整体流程,而是只介绍和跨机逻辑不同的中央。有差别的中央总共有两个,别离是路由和驱动程序。 4.1 网络层路由发送数据会进入协定栈到网络层的时候,网络层入口函数是 ip_queue_xmit。在网络层里会进行路由抉择,路由抉择结束后,再设置一些 IP 头、进行一些 netfilter 的过滤后,将包交给街坊子系统。 ...

June 28, 2021 · 4 min · jiezi

关于网络编程:计算机网络编程一网络基础

当你停下来劳动的时候别忘了他人还在奔跑计算机之间是如何通信的?晚期:联机 以太网 : 局域网与交换机 IP地址和IP协定规定网络地址的协定叫ip协定,它定义的地址称之为ip地址,宽泛采纳的v4版本即ipv4,它规定网络地址由32位2进制示意;IP地址就像是咱们的家庭住址一样,如果你要写信给一个人,你就要晓得他(她)的地址,这样邮递员能力把信送到;范畴0.0.0.0-255.255.255.255;一个ip地址通常写成四段十进制数,例:192.168.1.1IP地址划分类 其中A、B、C3类(如下表格)由InternetNIC在寰球范畴内统一分配,D、E类为非凡地址。 分类IP地址范畴公有IP地址范畴A类1.0.0.0~127.255.255.25410.0.0.0--10.255.255.255B类128.0.0.1~191.255.255.254172.16.0.0--172.31.255.255C类192.0.0.1~223.255.255.254192.168.0.0--192.168.255.255然而随着Internet的飞速发展,这种划分计划的局限性很快显现出来,大多数组织都申请B类网络地址, 导致B类地址很快就调配完了,而A类却节约了大量地址。针对这种状况提出了新的划分计划, 称为CIDR(Classless Interdomain Routing) 域名只管==IP地址==可能惟一地标记网络上的计算机,但IP地址是一长串数字,不直观,而且用户记忆非常不不便,于是人们又创造了另一套字符型的地址计划,即所谓的域名地址。IP地址和域名是一一对应的,这份域名地址的信息寄存在一个叫域名服务器(DNS,Domain name server)的主机内,使用者只需理解易记的域名地址,其对应转换工作就留给了域名服务器。域名服务器就是提供IP地址和域名之间的转换服务的服务器。一个 IP 地址能够对应多个域名,一个域名只能对应一个 IP 地址。 例如当用户在浏览器输出域名时,浏览器首先申请 DNS 服务器,将域名转换为 IP 地址,而后将转换后的 IP 地址反馈给浏览器,而后再进行理论的数据传输。 个别状况DNS服务器失常运行的时候,咱们用域名或者IP地址都能连贯到网络中的设施,然而DNS服务器挂了的时候,你就会发现只能应用IP地址来拜访该设施了,所以IP地址其实比域名更加的通用。 端口如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,然而一个IP地址的端口能够有65536(即:2^16)个之多!端口是通过端口号来标记的,端口号只有整数,范畴是从0 到65535(2^16-1)。同一个计算机中每个程序对应惟一的端口,这样一个计算机上就能够通过端口辨别发送给每个端口的数据了,换句话说,也就是一个计算机上能够并发运行多个网络程序,而不会相互之间产生烦扰。在硬件上规定,端口的号码必须位于 0-65535 之间,每个端口惟一的对应一个网络程序,一个网络程序能够应用多个端口。一个网络程序运行在一台计算上时,不论是客户端还是服务器,都是至多占用一个端口进行网络通讯。在接收数据时,首先发送给对应的计算机,而后计算机依据端口把数据转发给对应的程序。网络通讯网络通讯基于“申请-响应”模型。在网络通讯中,第一次被动发动通信的程序被称作客户端(Client)程序,简称客户端,而在第一次通信中期待连贯的程序被称作服务器端(Server)程序,简称服务器。一旦通信建设,则客户端和服务器端齐全一样,没有实质的区别。其实很容易就了解客户端和服务器端的,QQ,咱们用的腾讯的,在咱们这里就是客户端程序,而服务器端程序在腾讯那边,为大量的QQ用户服务,这种网络编程构造也成为客户端/服务器构造,C/S构造。切实运行很多程序时,没有必要应用专用的客户端,而须要应用通用的客户端,例如浏览器,应用浏览器作为客户端的构造被称作浏览器/服务器构造,也叫做 Browser/Server 构造,简称为 B/S 构造。协定网络协议为计算机网络中进行数据交换而建设的规定、规范或约定的汇合。网络编程就是运行在不同计算机中两个程序之间的数据交换。在理论进行数据交换时,为了让接收端了解该数据,计算机比拟笨,什么都不懂的,那么就须要规定该数据的格局,这个数据的格局就是协定。 在理论的网络程序编程中,最麻烦的内容不是数据的发送和接管,因为这个性能在简直所有的程序语言中都提供了封装好的 API 进行调用,最麻烦的内容就是协定的设计以及协定的生产和解析,这个才是网络编程中最外围的内容。 通信形式在现有的网络中,网络通讯的形式次要有两种: TCP(传输控制协议)形式UDP(用户数据报协定)形式在网络通讯中,TCP 形式就相似于拨打电话,应用该种形式进行网络通讯时,须要建设专门的虚构连贯,而后进行牢靠的数据传输,如果数据发送失败,则客户端会主动重发该数据;而 UDP 形式就相似于发送短信,应用这种形式进行网络通讯时,不须要建设专门的虚构连贯,传输也不是很牢靠,如果发送失败则客户端无奈取得。 两者区别: 重要数据应用TCP形式进行传输;大量的非核心数据应用UDP形式进行传输;因为TCP形式须要建设专用的虚构连贯以及确认传输是否正确,所以应用 TCP 形式的速度略微慢一些,而且传输时产生的数据量要比 UDP 略微大一些。

April 19, 2021 · 1 min · jiezi

关于即时通讯:跟着源码一起学手把手教你用WebSocket打造Web端IM聊天

本文作者芋艿,原题“芋道 Spring Boot WebSocket 入门”,本次有订正和改变。 一、引言WebSocket现在在Web端即时通讯技术利用里应用宽泛,不仅用于传统PC端的网页里,也被很多挪动端开发者用于基于HTML5的混合APP里。对于想要在基于Web的利用里增加IM、推送等实时通信性能,WebSocket简直是必须要把握的技术。 本文将基于Tomcat和Spring框架实现一个逻辑简略的入门级IM利用,对于即时通讯初学者来说,能找到一个简略间接且能顺利跑通的实例代码,显然意义更大,本文正是如此。心愿能给你的IM开发和学习带来启发。 注:源码在本文第四、五节结尾的附件处可下载。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(本文同步公布于:http://www.52im.net/thread-3483-1-1.html) 二、常识筹备如果你对Web端即时通讯常识一头雾水,务必先读:《新手入门贴:史上最全Web端即时通讯技术原理详解》、《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。 限于篇幅,本文不会深究WebSocket技术实践,如有趣味请从根底学习: 《老手疾速入门:WebSocket扼要教程》《WebSocket从入门到精通,半小时就够!》《八问WebSocket协定:为你疾速解答WebSocket热门疑难》《WebSocket详解(一):初步意识WebSocket技术》《WebSocket详解(二):技术原理、代码演示和利用案例》《WebSocket详解(三):深刻WebSocket通信协议细节》《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》《WebSocket详解(六):刨根问底WebSocket与Socket的关系》如果想要更硬核一点的,能够读读上面这几篇: 《WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器》《Web端即时通讯实际干货:如何让你的WebSocket断网重连更疾速?》《实践联系实际:从零了解WebSocket的通信原理、协定格局、安全性》三、内容概述相比 HTTP 协定来说,WebSocket 协定对大多数后端开发者是比拟生疏的。 相对而言:WebSocket 协定重点是提供了服务端被动向客户端发送数据的能力,这样咱们就能够实现实时性较高的需要。例如:聊天 IM 即便通信性能、音讯订阅服务、网页游戏等等。 同时:因为 WebSocket 应用 TCP 通信,能够防止反复创立连贯,晋升通信品质和效率。例如:美团的长连贯服务,具体能够看看 《美团点评的挪动端网络优化实际:大幅晋升连贯成功率、速度等》 。 情谊提醒: 这里有个误区,WebSocket 相比一般的 Socket 来说,仅仅是借助 HTTP 协定实现握手,创立连贯。后续的所有通信,都和 HTTP 协定无关。看到这里,大家肯定认为又要开始哔哔 WebSocket 的概念。哈哈,我偏不~如果对这块不了的敌人,能够浏览本文“2、常识筹备”这一章。 要想应用WebSocket,个别有如下几种解决方案可选: 1)计划一:Spring WebSocket;2)计划二:Tomcat WebSocket;3)计划三:Netty WebSocket。目前笔者手头有个波及到 IM 即便通信的我的项目,采纳的是计划三。 次要起因是:咱们对 Netty 框架的实战、原理与源码,都绝对相熟一些,所以就思考了它。并且,除了须要反对 WebSocket 协定,咱们还想提供原生的 Socket 协定。 如果仅仅是仅仅提供 WebSocket 协定的反对,能够思考采纳计划一或者计划二,在应用上,两个计划是比拟靠近的。相比来说,计划一 Spring WebSocket 内置了对 STOMP 协定的反对。 不过:本文还是采纳计划二“Tomcat WebSocket”来作为入门示例。咳咳咳,没有非凡的起因,次要是开始写本文之前,曾经花了 2 小时应用它写了一个示例。切实是有点懒,不想改。如果能重来,我要选李白,哈哈哈哈~ 当然,不要慌,计划一和计划二的实现代码,真心没啥差异。 在开始搭建 Tomcat WebSocket 入门示例之前,咱们先来理解下 JSR-356 标准,定义了 Java 针对 WebSocket 的 API :即 Javax WebSocket 。标准是大哥,打死不会提供实现,所以 JSR-356 也是如此。目前,支流的 Web 容器都曾经提供了 JSR-356 的实现,例如说 Tomcat、Jetty、Undertow 等等。 ...

April 6, 2021 · 7 min · jiezi

关于网络编程:小菜学网络以太网组建与冲突域

通过以太网通信的主机,能够用 集线器 或者 交换机 连接起来。无论集线器还是交换机,端口数量都是无限的。一般交换机个别有 4 口, 8 口、 16 口或 24 口,最多也有 48 口的。 这是一台典型的 48 口交换机: 当初问题来了:当主机数量超过端口数后,该怎么办呢? 咱们能够将多台以太网设施连接起来,组成更大的网络: 那么,组建以太网个别采纳什么拓扑构造?须要思考哪些因素呢?开始探讨之前,咱们先来认识一下抵触域的概念。 抵触域咱们晓得,集线器是一种很低级的物理层设施,实质能够了解成共用导线。因而,连贯在集线器上的主机,不能同时通信。如下图,当主机①与主机③正在通信时,其余主机是无奈通信的: 如果一个以太网区域内,多台主机因为抵触而无奈同时通信,这个区域形成一个 抵触域 ( collision domain )。很显然,连贯在同个集线器下的所有主机处于同一抵触域,它们的通信效率是十分低下的: 交换机就不一样了,它工作在数据链路层,依据目标 MAC 地址转发以太网帧。因为交换机端口外部不会共用导线,因而不同端口能够同时通信。如下图,就算主机①和主机③正在通信,但并不影响其余端口上的主机: 这时,主机④仍能够向主机②发送数据,齐全不受任何影响;但其余主机不能给主机③发数据。 因而,交换机每个端口都是一个独立的抵触域: 回到后面的拓扑图,因为交换机每个端口都是独立的抵触域,而整个集线器是一个抵触域,因而整个拓扑形成了两个相互独立的抵触域: 因为集线器无奈隔离抵触域,因而当初曾经很少用了,更不用说通过连贯多个集线器来组网: 交换机级联级联是连贯多台以太网交换机的传统办法,只需用网线将交换机端口连接起来。以两台交换机为例: 图中的两台交换机,各有一个端口通过网线连接起来。这样一来,右边主机与左边主机通信,都须要通过两头的这根网线,共享带宽。因而,在右边主机看来,左边主机都在一个抵触域内,左右两边通信效率较差。 尽管如此,同个交换机下的不同主机,抵触域是独立,因此通信效率更高。 因为左右两边的主机通信都要通过两头的网线,这根小水管应该最先面临瓶颈。那么,如何进步左右两边的通信带宽呢?一根网线不够用,那就两根嘛,别离插两个端口。 这样的双线级联构造,左右两边的通信带宽实践上能够达到原来的两倍,不够还能够再加。 交换机重叠有些交换机还反对重叠,重叠个别通过专门的重叠口和重叠线进行: 以重叠形式连贯的交换机,组成一个有机整体,在内部看来就是一台,如上图。因而,重叠交换机每个端口都是独立的抵触域。此外,重叠端口带宽也比一般网络端口大得多,更不容易遇到瓶颈。 美中不足的是,不是所有交换机都反对重叠,而且个别只有同个品牌型号的交换机能力重叠。此外,重叠对交换机间隔也有要求,不能离得太远。 连贯形式长处毛病级联实现简略; 节约老本; 间隔根本不受限制; 兼容不同品牌设施性能较差重叠性能更好; 信号不易衰减实现艰难; 投入较大; 间隔受限; 要求同一品牌【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注:

March 10, 2021 · 1 min · jiezi

关于网络编程:从根上理解高性能高并发七深入操作系统一文读懂进程线程协程

本文援用了“一文读懂什么是过程、线程、协程”一文的次要内容,感激原作者的自私分享。 1、系列文章引言1.1 文章目标作为即时通讯技术的开发者来说,高性能、高并发相干的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或者你对具备这些技术特色的技术框架比方:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到了面视或者技术实际过程中遇到无奈释怀的纳闷时,方知自已所把握的不过是皮毛。 返璞归真、回归实质,这些技术特色背地的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻了解这些技术背地的原理,正是《从根上了解高性能、高并发》系列文章所要分享的。 1.2 文章源起我整顿了相当多无关IM、音讯推送等即时通讯技术相干的资源和文章,从最开始的开源IM框架MobileIMSDK,到网络编程经典巨著《TCP/IP详解》的在线版本,再到IM开发纲领性文章《新手入门一篇就够:从零开发挪动端IM》,以及网络编程由浅到深的《网络编程懒人入门》、《脑残式网络编程入门》、《高性能网络编程》、《鲜为人知的网络编程》系列文章。 越往常识的深处走,越感觉对即时通讯技术理解的太少。于是起初,为了让开发者门更好地从根底电信技术的角度了解网络(尤其挪动网络)个性,我跨专业收集整理了《IM开发者的零根底通信技术入门》系列高阶文章。这系列文章未然是一般即时通讯开发者的网络通信技术常识边界,加上之前这些网络编程材料,解决网络通信方面的常识盲点根本够用了。 对于即时通讯IM这种零碎的开发来说,网络通信常识的确十分重要,但回归到技术实质,实现网络通信自身的这些技术特色:包含下面提到的线程池、零拷贝、多路复用、事件驱动等等,它们的实质是什么?底层原理又是怎么?这就是整顿本系列文章的目标,心愿对你有用。 1.3 文章目录《从根上了解高性能、高并发(一):深刻计算机底层,了解线程与线程池》《从根上了解高性能、高并发(二):深刻操作系统,了解I/O与零拷贝技术》《从根上了解高性能、高并发(三):深刻操作系统,彻底了解I/O多路复用》《从根上了解高性能、高并发(四):深刻操作系统,彻底了解同步与异步》《从根上了解高性能、高并发(五):深刻操作系统,了解高并发中的协程》《从根上了解高性能、高并发(六):通俗易懂,高性能服务器到底是如何实现的》《从根上了解高性能、高并发(七):深刻操作系统,一文读懂过程、线程、协程》(* 本文)1.4 本篇概述本系文章中的《从根上了解高性能、高并发(一):深刻计算机底层,了解线程与线程池》、《从根上了解高性能、高并发(五):深刻操作系统,了解高并发中的协程》两篇文章,尽管都有波及到过程、线程、协程常识,但感觉还是不够零碎,零碎独自整顿了本文,心愿将这方面的常识零碎梳理和总结,达到彻底解惑的目标。 本篇是本系列文章的长期续篇,本篇将由浅入深,总结过程、线程、协程这3个技术概念,将3者的技术原理、用处、关系进行了零碎梳理和总结,心愿有助于解决你这方面的技术困惑。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注。公众号上的链接是:点此进入。 2、本文原作者本文内容援用了“一文读懂什么是过程、线程、协程”一文的次要内容(原文地址已无奈查到),原作者:luoweifu,毕业于江西农业大学,现就职于阿里钉钉。集体博客地址:https://blog.csdn.net/luoweifu。 3、什么是过程?3.1 基本常识咱们须要明确一下几个常识: 1)计算机的外围是CPU,它承当了所有的计算工作;2)操作系统是计算机的管理者,它负责工作的调度、资源的调配和治理,统领整个计算机硬件;3)应用程序则是具备某种性能的程序,程序是运行于操作系统之上的。过程是一个具备肯定独立性能的程序在一个数据集上的一次动静执行的过程,是操作系统进行资源分配和调度的一个独立单位,是利用程序运行的载体。过程是一种形象的概念,素来没有对立的规范定义。 过程个别由程序、数据汇合和过程管制块三局部组成: 1)程序用于形容过程要实现的性能,是管制过程执行的指令集;2)数据汇合是程序在执行时所须要的数据和工作区;3)程序控制块(Program Control Block,简称PCB),蕴含过程的形容信息和管制信息,是过程存在的惟一标记。过程具备的特色: 1)动态性:过程是程序的一次执行过程,是长期的,有生命期的,是动静产生,动静沦亡的;2)并发性:任何过程都能够同其余过程一起并发执行;3)独立性:过程是零碎进行资源分配和调度的一个独立单位;4)结构性:过程由程序、数据和过程管制块三局部组成。3.2 为什么要有多过程?多过程目标:进步cpu的使用率。 一个例子:一个用户当初既想应用打印机,又想玩游戏。 假如只有一个过程(先不谈多线程): 从操作系统的层面看,咱们应用打印机的步骤有如下: 1)应用CPU执行程序,去硬盘读取须要打印的文件,而后CPU会长工夫的期待,直到硬盘读写实现;2)应用CPU执行程序,让打印机打印这些内容,而后CPU会长工夫的期待,期待打印完结。在这样的状况下:其实CPU的使用率其实十分的低。 打印一个文件从头到尾须要的工夫可能是1分钟,而cpu应用的工夫总和可能加起来只有几秒钟。而前面如果单过程执行游戏的程序的时候,CPU也同样会有大量的闲暇工夫。 应用多过程后: 当CPU在期待硬盘读写文件,或者在期待打印机打印的时候,CPU能够去执行游戏的程序,这样CPU就能尽可能高的进步使用率。 再具体一点说,其实也进步了效率。因为在期待打印机的时候,这时候显卡也是闲置的,如果用多过程并行的话,游戏过程齐全能够并行应用显卡,并且与打印机之间也不会相互影响。 3.3 小结一下过程,直观点说:保留在硬盘上的程序运行当前,会在内存空间里造成一个独立的内存体,这个内存体有本人独立的地址空间,有本人的堆,下级挂靠单位是操作系统。 操作系统会以过程为单位,调配系统资源(CPU工夫片、内存等资源),过程是资源分配的最小单位。 4、什么是线程?4.1 基本常识晚期:操作系统中并没有线程的概念,过程是能领有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采纳的是工夫片轮转的抢占式调度形式,而过程是任务调度的最小单位,每个过程有各自独立的一块内存,使得各个过程之间内存地址互相隔离。 起初:随着计算机的倒退,对CPU的要求越来越高,过程之间的切换开销较大,曾经无奈满足越来越简单的程序的要求了。于是就创造了线程。 线程是程序执行中一个繁多的顺序控制流程: 1)是程序执行流的最小单元;2)是处理器调度和分派的根本单位。一个过程能够有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在过程的内存空间)。一个规范的线程由线程ID、以后指令指针(PC)、寄存器和堆栈组成。而过程由内存空间(代码、数据、过程空间、关上的文件)和一个或多个线程组成。 PS:读到这里可能有的读者迷糊,感觉这和Java的内存空间模型不太一样,但如果你深刻的读过《深刻了解Java虚拟机》这本书的话你就会豁然开朗。 如上图所示:在工作管理器的过程一栏里,有道词典和有道云笔记就是过程,而在过程下又有着多个执行不同工作的线程。 4.2 任务调度线程是什么?要了解这个概念,须要先理解一下操作系统的一些相干概念。 大部分操作系统(如Windows、Linux)的任务调度是采纳工夫片轮转的抢占式调度形式。 在一个过程中:当一个线程工作执行几毫秒后,会由操作系统的内核(负责管理各个工作)进行调度,通过硬件的计数器中断处理器,让该线程强制暂停并将该线程的寄存器放入内存中,通过查看线程列表决定接下来执行哪一个线程,并从内存中复原该线程的寄存器,最初复原该线程的执行,从而去执行下一个工作。 上述过程中:工作执行的那一小段时间叫做工夫片,工作正在执行时的状态叫运行状态,被暂停的线程工作状态叫做就绪状态,意为期待下一个属于它的工夫片的到来。 这种形式保障了每个线程轮流执行,因为CPU的执行效率十分高,工夫片十分短,在各个工作之间疾速地切换,给人的感觉就是多个工作在“同时进行”,这也就是咱们所说的并发(别感觉并发有多浅近,它的实现很简单,但它的概念很简略,就是一句话:多个工作同时执行)。 多任务运行过程的示意图如下: ▲ 操作系统中的任务调度 4.3 过程与线程的区别后面讲了过程与线程,但可能你还感觉迷糊,感觉他们很相似。确实,过程与线程有着千头万绪的关系。 上面就让咱们一起来理一理: 1)线程是程序执行的最小单位,而过程是操作系统分配资源的最小单位;2)一个过程由一个或多个线程组成,线程是一个过程中代码的不同执行路线;3)过程之间互相独立,但同一过程下的各个线程之间共享程序的内存空间(包含代码段、数据集、堆等)及一些过程级的资源(如关上文件和信号),某过程内的线程在其它过程不可见;4)线程上下文切换比过程上下文切换要快得多。以下线程与过程关系的示意图。 ▲ 过程与线程的资源共享关系 ▲ 单线程与多线程的关系 总之:线程和过程都是一种形象的概念,线程是一种比过程更小的形象,线程和过程都可用于实现并发。 在晚期的操作系统中并没有线程的概念,过程是能领有资源和独立运行的最小单位,也是程序执行的最小单位。它相当于一个过程里只有一个线程,过程自身就是线程。所以线程有时被称为轻量级过程(Lightweight Process,LWP)。 ▲ 晚期的操作系统只有过程,没有线程 ...

March 3, 2021 · 1 min · jiezi

关于网络编程:小菜学网络观察集线器和交换机

集线器和交换机是两种典型的网络设备,集线器 位于 物理层,而 交换机 位于于 数据链路层 ,行为显著不同。本节筹备了两个简略试验,旨在通过实际加深对理论知识的了解,逐渐把握 Linux 主机网络操作。 试验一:察看以太网集线器本试验将 3 台 Linux 主机连到一个集线器上,以此察看集线器的工作行为,网络拓扑图如下: 试验环境以 docker 容器的模式提供,执行这个 docker 命令即可一键关上: docker run --name hub-lab --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h hub-lab fasionchan/netbox:0.5 bash /script/hub-lab.sh试验环境关上后,能够看到 3 个窗口,各自代表一台主机: 这是用 tmux 命令实现的窗口划分,按下_ Ctrl-B_ 后再按方向键,即可在不同主机窗口间切换。 请特地留神,按下 Ctrl-B 后要松手,而后再按方向键,能力切到想要操作的主机窗口。还有一种更快捷的切换办法,先按下 Ctrl-B ,松手后再按 Q 。这时,每个窗口都会显示一个数字。接着,按下对应的数字即可切到想要的窗口: 咱们先切到主机 ant ,察看它的网卡信息, ifconfig 或 ip 命令均可: root@ant [ ~ ] ➜ ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 ether 32:90:b9:9f:35:56 txqueuelen 1000 (Ethernet) RX packets 6 bytes 540 (540.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3 bytes 270 (270.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0root@ant [ ~ ] ➜ ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.03: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd ::6: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 32:90:b9:9f:35:56 brd ff:ff:ff:ff:ff:ff link-netnsid 0接着,切到主机 bee 和 cicada ,持续察看它们的网卡信息: ...

February 25, 2021 · 5 min · jiezi

关于网络编程:小菜学网络MTU

不同的以太网接入设施,一帧能传输的数据量是有差别的。 一般的以太网卡,一帧最多可能传输 1500 字节的数据;而某些虚构设施,传输能力要打些折扣。此外,链路层除了以太网还有其余协定,这些协定中数据帧传输能力也有差别。 最大传输单元如果待发送的数据超过帧的最大承载能力,就须要先对数据进行分片,而后再通过若干个帧进行传输。 上面是一个典型例子,待发送的数据总共 4000 字节,假如以太网设施一帧最多只能承载 1500 字节。很显著,数据须要划分成 3 片,再通过 3 个帧进行发送: 换句话讲,咱们须要晓得接入设施一帧最多能发送多少数据。这个参数在网络畛域被称为 最大传输单元 ( maximum transmission unit ),简称 MTU 。 MTU 形容链路层可能传输的最大数据单元。 查看、设置MTU咱们晓得,在 Linux 零碎能够用 ifconfig 或者 ip 这两个命令来查看网卡信息,其中包含 MTU 。 接下来,咱们关上 docker 进入 netbox 环境进行演示: docker run --name netbox --rm -it --privileged --cap-add=NET_ADMIN --cap-add=SYS_ADMIN -v /data -h netbox fasionchan/netbox:0.5 bash /script/netbox.sh先以 ifconfig 命令为例: root@netbox [ ~ ] ➜ ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.2 netmask 255.255.255.0 broadcast 0.0.0.0 ether 5a:ff:7e:28:81:bc txqueuelen 1000 (Ethernet) RX packets 24 bytes 2165 (2.1 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 27 bytes 2164 (2.1 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0ip 命令也能够,咱们更举荐应用这个: ...

February 24, 2021 · 3 min · jiezi

关于网络编程:网络编程入门从未如此简单二假如你来设计TCP协议会怎么做

本文原题“你管这破玩意儿叫TCP?”,由闪客sun分享,转载请分割作者。 1、引言网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的实践根基,因此粗浅精确地了解计算机网络常识显然能夯实你的即时通讯利用的实际品质。本文格调相似于《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但艰深又不失外延,简洁又不简陋,非常适合对计算机网络常识有向往但又有害怕的网络编程爱好者们浏览,心愿能给你带来不一样的网络常识入门视角。本篇将使用通俗易懂的语言,配上粗疏准确的图片动画,循序渐进地疏导你了解TCP协定的次要个性和技术原理,让TCP协定的学习不再如此干燥和生涩,非常适合入门者浏览。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注。公众号上的链接是:点此进入。 2、系列文章本文是该系列文章中的第2篇: 《网络编程入门从未如此简略(一):如果你来设计网络,会怎么做?》《网络编程入门从未如此简略(二):如果你来设计TCP协定,会怎么做?》(本文)本文次要波及计算机网络的传输层,心愿让TCP协定的学习不再干燥和生涩。 3、初识传输层你是一台电脑,你的名字叫 A。通过上篇《如果你来设计网络,会怎么做?》的一番折腾,只有你晓得另一位搭档 B 的 IP 地址,且你们之间的网络是通的,无论多远,你都能够将一个数据包发送给你的搭档 B。上篇中分享的这就是物理层、数据链路层、网络层这三层所做的事件。站在第四层的你,就能够不要脸地利用下三层所做的铺垫,得心应手地发送数据,而不用放心找不到对方了。尽管你此时还什么都没干,但你还是给本人这一层起了个嘹亮的名字,叫做传输层。你本认为本人所在的第四层高枕无忧,啥事没有,但很快问题就接踵而至。 4、问题来了前三层协定只能把数据包从一个主机搬到另外一台主机,然而到了目的地当前,数据包具体交给哪个程序(过程)呢?所以:你须要把通信的过程辨别开来,于是就给每个过程调配一个数字编号,你给它起了一个嘹亮的名字:端口号。而后:你在要发送的数据包上,减少了传输层的头部:源端口号与指标端口号。OK,这样你将本来主机到主机的通信,降级为了过程和过程之间的通信。你没有意识到,你人不知;鬼不觉实现了UDP协定! 当然 UDP 协定中不光有源端口和指标端口,还有数据包长度和校验值,咱们暂且略过。就这样,你用 UDP 协定无牵无挂地同 B 进行着通信,始终没产生什么问题。但很快,你发现事件变得非常复杂 ... ... 5、丢包问题因为网络的不牢靠,数据包可能在半路失落,而 A 和 B 却无奈觉察。对于丢包问题,只有解决两个事就好了。第一个:A 怎么晓得包丢了?答案是:让 B 通知 A。第二个:丢了的包怎么办?答案是:重传。于是你设计了如下计划:A 每发一个包,都必须收到来自 B 的确认(ACK),再发下一个,否则在肯定工夫内没有收到确认,就重传这个包。你管它叫进行期待协定。只有依照这个协定来,尽管 A 无奈保障 B 肯定能收到包,但 A 可能确认 B 是否收到了包,收不到就重试,尽最大致力让这个通信过程变得牢靠,于是你们当初的通信过程又有了一个新的特色,牢靠交付。 6、效率问题进行期待尽管能解决问题,然而效率太低了。A 本来能够在发完第一个数据包之后立即开始发第二个数据包,但因为进行期待协定,A 必须等数据包达到了 B ,且 B 的 ACK 包又回到了 A,才能够持续发第二个数据包。这效率慢得可不是一点两点。于是:你对这个过程进行了改良,采纳流水线的形式,不再傻傻地等。 7、程序问题然而网路是简单的、不牢靠的。这导致的问题是:有的时候 A 收回去的数据包,别离走了不同的路由达到 B,可能无奈保障和发送数据包时一样的程序。对应于咱们的例子:在流水线中有多个数据包和ACK包在乱序流动,他们之间对应关系就乱掉了。如果回到下面的进行期待协定,那么A 每收到一个包的确认(ACK)再发下一个包,那就基本不存在程序问题。但,应该有更好的方法吧?是的,更好的方法就是:A 在发送的数据包中减少一个_序号_(seq),同时 B 要在 ACK 包上减少一个_确认号_(ack)。这样岂但解决了进行期待协定的效率问题,也通过这样标序号的形式解决了程序问题。而 B 这个确认号意味深长:比方 B 发了一个确认号为 ack = 3,它不仅仅示意 A 发送的序号为 2 的包收到了,还示意 2 之前的数据包都收到了。这种形式叫_累计确认_或_累计应答_。 ...

February 24, 2021 · 2 min · jiezi

关于网络编程:网络编程入门从未如此简单一假如你来设计网络会怎么做

本文原题“如果让你来设计网络”,由闪客sun分享,转载请分割作者。 1、引言网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的实践根基,因此粗浅精确地了解计算机网络常识显然能夯实你的即时通讯利用的实际品质。 本文格调相似于52im社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但艰深又不失外延,简洁又不简陋,非常适合对计算机网络常识有向往但又有害怕的网络编程爱好者们浏览,心愿能给你带来不一样的网络常识入门视角。 本篇次要以通俗易懂的文风,疏导你了解计算机网络是如何演化成今日的样子,文中交叉了集线器、替换杨、路由器等设施的应用背景以及技术原理,由浅入深,非常适合入门者浏览。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注。公众号上的链接是:点此进入。 2、系列文章本文是该系列文章中的第1篇: 《网络编程入门从未如此简略(一):如果你来设计网络,会怎么做?》(本文)《网络编程入门从未如此简略(二):如果你来设计TCP协定,会怎么做?(稍后公布...)》本文是系列文章中的开篇,次要波及计算机网络的物理层、数据链路层、网络层。 3、阶段1:就两台电脑,要网络作甚你是一台电脑,你的名字叫 A。 很久很久以前,你不与任何其余电脑相连接,孤苦伶仃。 直到有一天,你心愿与另一台电脑 B 建设通信,于是你们各开了一个网口,用一根网线连贯了起来。 用一根网线连接起来怎么就能"通信"了呢?我能够给你讲 IO、讲中断、讲缓冲区,但这不是钻研网络时该关怀的问题。 如果你纠结,要么去钻研一下操作系统是如何解决网络 IO 的,要么去钻研一下包是如何被网卡转换成电信号发送进来的,要么就仅仅把它当做电脑里有个君子在开枪吧~ 反正,你们就是连起来了,并且能够通信。 4、阶段2:电脑多起来了,须要组个网4.1 集线器有一天,一个新搭档 C 退出了,但聪慧的你们很快发现,能够每个人开两个网口,用一共三根网线,彼此相连。 随着越来越多的人退出,你发现身上开的网口切实太多了,而且网线稀稀拉拉,凌乱不堪。(PS:实际上一台电脑基本开不了这么多网口,所以这种连线只在实践上可行,所以连不上的我就用红色虚线示意了,就是这么谨严哈哈~) 于是你们创造了一个中间设备,你们将网线都插到这个设施上,由这个设施做转发,就能够彼此之间通信了,实质上和原来一样,只不过网口的数量和网线的数量缩小了,不再那么凌乱。 你给它取名叫:集线器,它仅仅是无脑将电信号转发到所有进口(播送),不做任何解决,你感觉它是没有智商的,因而把人家定性在了物理层。 4.2 MAC地址因为转发到了所有进口,那 BCDE 四台机器怎么晓得数据包是不是发给本人的呢? 首先,你要给所有的连贯到集线器的设施,都起个名字。原来你们叫 ABCD,但当初须要一个更业余的,全局惟一的名字作为标识,你把这个更高端的名字称为 MAC地址。 你的 MAC 地址是 _aa-aa-aa-aa-aa-aa_,你的搭档 b 的 MAC 地址是 bb-bb-bb-bb-bb-bb,以此类推,不反复就好。 这样,A 在发送数据包给 B 时,只有在头部拼接一个这样构造的数据,就能够了。 B 在收到数据包后,依据头部的指标 MAC 地址信息,判断这个数据包确实是发给本人的,于是便收下。 其余的 CDE 收到数据包后,依据头部的指标 MAC 地址信息,判断这个数据包并不是发给本人的,于是便抛弃。 尽管集线器使整个布局洁净不少,但原来我只有发给电脑 B 的音讯,当初却要发给连贯到集线器中的所有电脑,这样既不平安,又不节俭网络资源。 5、阶段3:一个网不够用了,得级连组网5.1 交换机如果把这个集线器弄得更智能一些:“只发给指标 MAC 地址指向的那台电脑”,就好了。 ...

February 2, 2021 · 3 min · jiezi

关于网络编程:从根上理解高性能高并发六通俗易懂高性能服务器到底是如何实现的

本文原题“高并发高性能服务器是如何实现的”,转载请分割作者。 1、系列文章引言1.1 文章目标作为即时通讯技术的开发者来说,高性能、高并发相干的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或者你对具备这些技术特色的技术框架比方:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到了面视或者技术实际过程中遇到无奈释怀的纳闷时,方知自已所把握的不过是皮毛。 返璞归真、回归实质,这些技术特色背地的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻了解这些技术背地的原理,正是《从根上了解高性能、高并发》系列文章所要分享的。 1.2 文章源起我整顿了相当多无关IM、音讯推送等即时通讯技术相干的资源和文章,从最开始的开源IM框架MobileIMSDK,到网络编程经典巨著《TCP/IP详解》的在线版本,再到IM开发纲领性文章《新手入门一篇就够:从零开发挪动端IM》,以及网络编程由浅到深的《网络编程懒人入门》、《脑残式网络编程入门》、《高性能网络编程》、《鲜为人知的网络编程》系列文章。 越往常识的深处走,越感觉对即时通讯技术理解的太少。于是起初,为了让开发者门更好地从根底电信技术的角度了解网络(尤其挪动网络)个性,我跨专业收集整理了《IM开发者的零根底通信技术入门》系列高阶文章。这系列文章未然是一般即时通讯开发者的网络通信技术常识边界,加上之前这些网络编程材料,解决网络通信方面的常识盲点根本够用了。 对于即时通讯IM这种零碎的开发来说,网络通信常识的确十分重要,但回归到技术实质,实现网络通信自身的这些技术特色:包含下面提到的线程池、零拷贝、多路复用、事件驱动等等,它们的实质是什么?底层原理又是怎么?这就是整顿本系列文章的目标,心愿对你有用。 1.3 文章目录《从根上了解高性能、高并发(一):深刻计算机底层,了解线程与线程池》《从根上了解高性能、高并发(二):深刻操作系统,了解I/O与零拷贝技术》《从根上了解高性能、高并发(三):深刻操作系统,彻底了解I/O多路复用》《从根上了解高性能、高并发(四):深刻操作系统,彻底了解同步与异步》《从根上了解高性能、高并发(五):深刻操作系统,了解高并发中的协程》《从根上了解高性能、高并发(六):通俗易懂,高性能服务器到底是如何实现的》(* 本文)1.4 本篇概述接上篇《从根上了解高性能、高并发(五):深刻操作系统,了解高并发中的协程》,本篇是高性能、高并发系列的第6篇文章(也是完结篇)。 本篇是本系列文章的完结篇,你将能理解到,一个典型的服务器端是如何利用前5篇中解说的各单项技术从而实现高性能高并发的。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注。公众号上的链接是:点此进入。 2、本文作者应作者要求,不提供真名,也不提供集体照片。 本文作者次要技术方向为互联网后端、高并发高性能服务器、检索引擎技术,网名是“码农的荒岛求生”。感激作者的自私分享。 3、注释引言当你在浏览本篇文章的时候,有没有想过,服务器是怎么把这篇文章发送给你的呢? 说起来很简略:不就是一个用户申请吗?服务器依据申请从数据库中捞出这篇文章,而后通过网络发回去吗。 其实有点简单:服务器端到底是如何并行处理成千上万个用户申请的呢?这外面又波及到哪些技术呢? 这篇文章就是来为你解答这个问题的。 4、多过程历史上最早呈现也是最简略的一种并行处理多个申请的办法就是利用多过程。 比方在Linux世界中,咱们能够应用fork、exec等零碎调用创立多个过程,咱们能够在父过程中接管用户的连贯申请,而后创立子过程去解决用户申请。 就像这样: 这种办法的长处就在于: 1)编程简略,非常容易了解;2)因为各个过程的地址空间是互相隔离的,因而一个过程解体后并不会影响其它过程;3)充分利用多核资源。多过程并行处理的长处很显著,然而毛病同样显著: 1)各个过程地址空间互相隔离,这一长处也会变成毛病,那就是过程间要想通信就会变得比拟艰难,你须要借助过程间通信(IPC,interprocess communications)机制,想一想你当初晓得哪些过程间通信机制,而后让你用代码实现呢?显然,过程间通信编程绝对简单,而且性能也是一大问题;2)咱们晓得创立过程开销是比线程要大的,频繁的创立销毁过程无疑会减轻零碎累赘。幸好,除了过程,咱们还有线程。 5、多线程不是创立过程开销大吗?不是过程间通信艰难吗?这些对于线程来说通通不是问题。 什么?你还不理解线程,连忙看看这篇《深刻计算机底层,了解线程与线程池》,这里具体解说了线程这个概念是怎么来的。 因为线程共享过程地址空间,因而线程间通信人造不须要借助任何通信机制,间接读取内存就好了。 线程创立销毁的开销也变小了,要晓得线程就像寄居蟹一样,房子(地址空间)都是过程的,本人只是一个租客,因而十分的轻量级,创立销毁的开销也十分小。 咱们能够为每个申请创立一个线程,即便一个线程因执行I/O操作——比方读取数据库等——被阻塞暂停运行也不会影响到其它线程。 就像这样: 但线程就是完满的、包治百病的吗,显然,计算机世界素来没有那么简略。 因为线程共享过程地址空间,这在为线程间通信带来便当的同时也带来了无尽的麻烦。 正是因为线程间共享地址空间,因而一个线程解体会导致整个过程解体退出,同时线程间通信几乎太简略了,简略到线程间通信只须要间接读取内存就能够了,也简略到呈现问题也极其容易,死锁、线程间的同步互斥、等等,这些极容易产生bug,有数程序员贵重的工夫就有相当一部分用来解决多线程带来的无尽问题。 尽管线程也有毛病,然而相比多过程来说,线程更有劣势,但想单纯的利用多线程就能解决高并发问题也是不切实际的。 因为尽管线程创立开销相比过程小,但仍然也是有开销的,对于动辄数万数十万的链接的高并发服务器来说,创立数万个线程会有性能问题,这包含内存占用、线程间切换,也就是调度的开销。 因而,咱们须要进一步思考。 6、事件驱动:Event Loop到目前为止,咱们提到“并行”二字就会想到过程、线程。 然而:并行编程只能依赖这两项技术吗?并不是这样的! 还有另一项并行技术广泛应用在GUI编程以及服务器编程中,这就是近几年十分风行的事件驱动编程:event-based concurrency。 PS:搞IM服务端开发的程序员必定不生疏,驰名的Java NIO高性能网络编程框架Netty中EvenLoop 这个接口意味着什么(无关Netty框架的高性能原理能够读这篇《新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析》)。 大家不要感觉这是一项很难懂的技术,实际上事件驱动编程原理上非常简单。 这一技术须要两种原料: 1)event;2)解决event的函数,这一函数通常被称为event handler;剩下的就简略了:你只须要宁静的期待event到来就好,当event到来之后,检查一下event的类型,并依据该类型找到对应的event处理函数,也就是event handler,而后间接调用该event handler就好了。 That's it ! 以上就是事件驱动编程的全部内容,是不是很简略! 从下面的探讨能够看到:咱们须要一直的接管event而后解决event,因而咱们须要一个循环(用while或者for循环都能够),这个循环被称为Event loop。 应用伪代码示意就是这样: while(true) {    event = getEvent();    handler(event);}Event loop中要做的事件其实是非常简单的,只须要期待event的带来,而后调用相应的event处理函数即可。 ...

January 25, 2021 · 1 min · jiezi

关于网络编程:小菜学网络交换机与MAC地址学习

上一大节介绍了 集线器 ,一种工作于物理层的简略网络设备。因为集线器采纳播送的形式中继、转发物理信号,传输效率受到极大制约。 精准转发为了解决集线器工作效率低下的难堪,咱们须要设计一种更高级的网络设备。新设施依据以太网帧的目标 MAC 地址,将它精准地转发到正确端口: 正文:这里 端口 ( port )指的是转发设施的插口,也可叫做网口。如上图,两头节点是转发设施,它在外部保护着一张主机 MAC 地址与对应端口的映射表,现与 3 台主机相连。这样一来, 当转发设施接到主机 A 发给主机 C 的数据后,依据目标 MAC 地址搜寻映射表,便可将数据精确地转发到对应的端口 3 。 当初,传输模式变得更有针对性了——数据帧被精准转发到正确的端口,其余端口不再收到多余的数据: 不仅如此,主机 A 与 B 通信的同时,其余计算机也可通信,互不烦扰。转发设施每个端口是一个独立的抵触域,带宽也是独立的。 集线器的缺点全副防止了! 交换机可能依据以太网帧目标地址转发数据的网络设备就是 以太网交换机 ( ethernet switch ): 交换机长相跟集线器没啥区别嘛。当然了,大部分网络设备都是一个布满端口的盒子,关键在于外部结构。 再看看事实中的交换机长啥样: 总结起来,以太网交换机属于 二层网络设备 ,特点如下: 依据目标地址转发以太网帧;每个端口是独立抵触域;每个端口带宽独立;Mac地址学习交换机完满地解决集线器的毛病,但新问题又来了,映射表如何取得呢? 最原始的形式是:保护一张动态映射表。当新设施接入,向映射表增加一条记录;当设施移除,从映射表删除对应记录。然而,纯手工操作形式多少有些焦躁。 好在计算机领域能够实现各种花色的自动化——通过算法主动学习映射表。咱们先来看看大抵思路: 初始状态下,映射表是空的。当初,主机 A 向 B 发送一个数据帧 FRAME1 。因为映射表中没有地址 B 的记录,交换机便将数据帧播送到其余所有端口。 因为交换机是从 Fa0/1 端口收到数据帧的,便晓得 A 连贯 Fa0/1 端口,而数据帧的源地址就是 A 的地址!此时,交换机能够将 A 的地址和端口 Fa0/1 作为一条记录退出映射表。交换机学习到 A 的地址! ...

January 21, 2021 · 1 min · jiezi

关于网络编程:小菜学网络集线器

采纳以太网进行通信的主机,须要通过网线之类的介质连贯到一起。那么,如何将多根网线连贯在一起呢? 最简略的形式是将所有网线接到一个 集线器 ( hub )上,如下图: 集线器结构集线器外部结构很简略,能够了解成只是把所有网线连接起来而已。换句话讲,集线器充当了 共用导线 的性能。 这样一来,从某个端口发送进来的电信号,将被传送到所有其余端口: 正文:这里 端口 ( port )是指集线器的插口,或称为网口。换句话讲,从一台主机发送进去的数据,将被传送到所有其余主机上。 以 A 往 B 发送数据为例: 看起来就像 A 发动了 播送 ,其余所有主机都能够收到这个数据。 因为数据帧中蕴含 目标地址 ,最终只有 B 接管并解决这个数据。 因而并无大碍,至多是能够失常工作的。 尽管如此,集线器还是存在一些缺点,次要体现在两方面: 所有主机(端口)共享带宽;所有主机(端口)处于同一 抵触域 (一台主机发送,其余只能期待);这两方面缺点重大制约着集线器的传输效率,在接入端口数较多的状况下更是如此。 总结一下,集线器工作于物理层,次要特点如下: 扩大终端数量;中继放大物理信号;延长网络传输间隔;所有端口同属一个抵触域;所有端口共享带宽;【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注:

January 18, 2021 · 1 min · jiezi

关于网络编程:Socket简介和IO多路复用

最近在学nio,遇到了多路复用这个概念,而后我又想了想本人大学学的《计算机网络》,那个时候学网络总是感觉是一堆空洞洞的实践,因为我学到的和实际没有分割在一起。学习NIO的过程中,感觉对计算机网络又有新的意识,于是打算整顿一下对网络的认知。留神本篇文章只是概论,并不会探讨具体的协定,只是搭建一个了解网络的简略模型。[TOC] 程序和协定的桥梁现在的互联网曾经很遍及了,每天的地铁上都会有许多人在用手机做很多事件,比方浏览新闻、玩王者光荣、刷抖音,这些都是在应用网络应用程序。乏味的是,所有的网络应用都是基于基本相同的编程模型,有着类似的整体逻辑构造,并且依赖雷同的编程接口。网络是很简单的零碎,在这里我能说介绍的是一点点皮毛,我的指标是从程序员的角度建设一个容易了解的网络通信模型。 当咱们说起网络通信时,事实上说的是位于两台计算机上的过程之间通过互联网替换信息,如果说咱们将网络当做一个黑盒子的话。每个网络应用都是基于客户端-服务器模型的,服务器管控着某些资源,并且通过操纵这些资源向客户端提供某种服务。 粗略的说,过程就是正在运行中的程序,那咱们当初要使咱们的应用程序取得互联网反对,或者说就是要进行网络通信,然而咱们又不能间接应用曾经标准化了的互联网的利用协定,那咱们该当怎么做呢? 要答复这个问题,实际上就要理解上面介绍的Socket,事实上更齐备的答复应该由《网络编程》给出。 Socket通常各个高级编程语言都有对应的接口或者类库,供开发者调用。 然而事实上程序还是须要借助操作系统能力取得互联网的反对。 对计算机而言,网络又是一种I/O设施,是数据源和接管方。网卡提供了到网络的物理接口(什么你不晓得什么叫网卡?,等着我)。从网络上接管的数据从网卡通过I/O和内存总线复制到内存,通常 通过DMA传送。类似地,数据也能从内存复制到网络。看过我的《操作系统与通用计算机组成原理简论》这篇文章的应该晓得程序是无奈间接接触硬件的,程序只能通过操作系统提供的服务,来进行I/O操作。同样的从网络上获取信息,发送信息,也是须要调用操作系统提供的接口的。 当初TCP/IP协定软件曾经驻留在操作系统中。因为TCP/IP协定族被设计成能运行在多种操作系统的环境中,因而TCP/IP协定规范没有规定应用程序与TCP/IP协定软件如何接口(调用)的细节,而是容许零碎设计者可能抉择无关API的具体实现细节。 目前来说只有几种可供应用程序应用的TCP/IP的利用程序接口,最驰名的就是美国加利福利亚大学伯克利分校为Berkeley UNIX操作系统定义的API,被称为套接字接口(socket interface)。微软在其操作系统中采纳了套接字 API,然而有一点不同,咱们称之为Windows Socket。AT&T的Unix System V版本定义的接口,简写为TLI(Transport Layer port) 咱们能够认为套接字作为过程和运输层协定之间的接口,像上面这样。 请留神: 在套接字以上的过程是受利用程序控制的,而在套接字以下则属于操作系统的管制。因而,只有程序要应用TCP/IP协定进行通信,它就必须调用操作系统提供的网络通信接口。这里的套接字是一个相对来说有些形象的概念,那么该怎么了解这里的套接字呢? 为什么说这里的套接字? 因为在其余语境下套接字领有其余语义,然而也叫套接字。我认为这里的套接字的就是一个规定、协约、机制 : 当程序须要应用网络通信时,必须首先调用操作系统提供的Socket接口,也能够称之为收回Socket零碎调用,申请操作系统创立一个"套接字"。这个调用的实际效果就是申请操作系统把网络通信所须要的的一些资源(CPU工夫,网络带宽、存储器空间等)调配给该利用过程。操作系统为这些资源的总和创立一个套接字描述符的号码(小的整数)来示意,而后将这个套接字描述符返回给利用过程。尔后,利用过程所进行的网络操作(建设连贯、收发数据、调整网络通信参数等)都必须应用这个套接字描述符。 所以简直所有的网络调用都把这个套接字描述符作为作为第一个参数,在调用操作系统提供的网络通信接口时,通过套接字描述符,就能够辨认应该应用哪些资源来实现利用过程所申请的服务。 通信结束后,应用程序通过一个敞开套接字的close调用告诉操作系统回收与该套接字描述符相干的所有资源。 这里可能有些形象,艰深的说,咱们能够将Socket了解为一份合约,这份合约由操作系统提供,合约上规定了网络通信的一些事宜,利用过程遵循此合约,即可享受到操作系统提供的网络通信服务。 一个操作系统同时存在多个网络应用程序是非常天然的,因而须要有一个寄存套接字描述符的表,而每一个套接字描述符都有一个指针指向寄存套接字的地址。 Socket的不同语义Socket在不同的语境,有不同的语义。 在TCP连贯下的语义咱们晓得TCP将连贯作为最根本的形象,每一套TCP连贯有两个端点,TCP连贯的端点即为套接字(Socket)。依据RFC 793的定义: 端口号拼接到IP地址即形成了套接字。因而套接字的示意办法是在点分十进制的ip地址前面写上端口号,两头用冒号或逗号隔开。总之咱们有 socket = (ip地址:端口号)每一条TCP连贯惟一地被通信两端的套接字所确定。高级语言拜访互联网的接口,即运输层和应用层的一个接口,也能够称之为socket.java 中就有一个叫Socket的类。操作系统内核中与互联网通信的加利福利亚大学伯克利分校实现,称之为socket实现。网络通信的过程咱们以操作系统提供的TCP协定服务来介绍,网络通信的过程。 套接字 期待连贯所做的筹备工作首先过程调用操作系统提供的服务创立套接字,操作系统将对应的资源分配给对应申请的过程。在套接字创立后它的端口号和IP地址都是空的。因而利用过程须要绑定ip地址和端口号来指明套接字的本地地址,这里的绑定也是操作系统提供的服务,调用绑定服务事实上就是将ip地址和端口号填写调已创立的套接字中。 咱们晓得TCP是面向连贯的,那么此时仅仅创立套接字是不够的,该当调用操作系统提供的监听服务(咱们经常称为listen),将套接字设置为被动形式,以便随时承受客户的服务申请。UDP服务因为只提供无连贯服务,不应用listen服务。 再接着应用程序就调用承受服务,这个承受咱们经常称之为accept服务,以便把连贯申请提取进去。 调用accept服务之后要实现的动作比拟多,因为服务器必须同时解决多个连贯。这块在java的计划是多线程来解决,一个线程解决一个连贯,当连贯过多的时候,咱们就须要换别的思路了,这也就是下文提到的多路复用。 数据传送阶段这个其实就是连贯建设之后,客户端和服务端相互发送数据的过程。连贯开释阶段咱们上文讲到创立套接字是要向操作系统申请资源的,咱们也晓得TCP的连接时间不可能无限度的始终连贯上来,当连贯敞开,就须要开释向操作系统申请的资源。I/O 多路复用咱们晓得在客户端比拟少的时候,采纳多线程去解决客户端的连贯是没有什么问题的,这种模型个别被称为多线程并发模型,线程在某种意义上能够称之为轻量级的过程,所以这种模型也被称为多过程并发模型。 当初经常也是多核CPU,能充沛的利用多核。然而这个模型也有不合理之处,咱们须要为每一个客户端创立一个线程。不论客户端是否有发送数据。客户端一旦变多,这种开销就变得难以承受起来。 咱们来剖析一下这个模型不合理在哪里? 服务端始终在随时监听客户端的连贯,当连贯建设实现之后,服务端不论客户端有没有数据发过来就随即启动一个线程解决这个客户端的通信。很多线程在数据还未到来就处于闲暇状态,相当的节约。改良的计划就是抽出一个线程来记录这些客户端的状态。这个线程就是管理者,连贯建设好了,数据还没来,先不启动线程,有数据来了再解决,这样的益处就是缩小了线程开销,不用是每一个客户端都一个线程,建设连贯,客户端的数据总会有先后顺序,谁先到来我就解决谁。再反复一遍,连贯就绪了服务端过程临时不解决,哪个客户端的数据到来就解决谁。这就是多路复用,英文名是 I/O multiplexing。 Linux下的select,poll,epoll都是I/O多路复用的具体实现,为什么会有三个呢? 因为这三个的呈现是有先后顺序的。widnows下多路复用的具体实现为 select function (winsock2.h) - Win32 apps | Microsoft Docs 具体的能够参看《IO 多路复用是什么意思?》 参考资料: ...

August 1, 2020 · 1 min · jiezi

Netty如何接入新连接

欢迎关注公众号:【爱编程】如果有需要后台回复2019赠送1T的学习资料哦!!前文再续,书接上一回【NioEventLoop】。在研究NioEventLoop执行过程的时候,检测IO事件(包括新连接),处理IO事件,执行所有任务三个过程。其中检测IO事件中通过持有的selector去轮询事件,检测出新连接。这里复用同一段代码。 Channel的设计在开始分析前,先了解一下Channel的设计 顶层Channel接口定义了socket事件如读、写、连接、绑定等事件,并使用AbstractChannel作为骨架实现了这些方法。查看器成员变量,发现大多数通用的组件,都被定义在这里 第二层AbstractNioChannel定义了以NIO,即Selector的方式进行读写事件的监听。其成员变量保存了selector相关的一些属性。 第三层内容比较多,定义了服务端channel(左边继承了AbstractNioMessageChannel的NioServerSocketChannel)以及客户端channel(右边继承了AbstractNioByteChannel的NioSocketChannel)。 如何接入新连接?本文开始探索一下Netty是如何接入新连接?主要分为四个部分 1.检测新连接2.创建NioSocketChannel3.分配线程和注册Selector4.向Selector注册读事件1.检测新连接Netty服务端在启动的时候会绑定一个bossGroup,即NioEventLoop,在bind()绑定端口的时候注册accept(新连接接入)事件。扫描到该事件后,便处理。因此入口从:NioEventLoop#processSelectedKeys()开始。 private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe(); //省略代码 // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead // to a spin loop //如果当前NioEventLoop是workGroup 则可能是OP_READ,bossGroup是OP_ACCEPT if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { //新连接接入以及读事件处理入口 unsafe.read(); } }关键的新连接接入以及读事件处理入口unsafe.read(); a).这里的unsafe是在Channel创建过程的时候,调用了父类AbstractChannel#AbstractChannel()的构造方法,和pipeline一起初始化的。 protected AbstractChannel(Channel parent) { this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }服务端:unsafe 为NioServerSockeChannel的父类AbstractNioMessageChannel#newUnsafe()创建,可以看到对应的是AbstractNioMessageChannel的内部类NioMessageUnsafe; ...

June 7, 2019 · 7 min · jiezi

Java网络编程基础一

计算机网络体系结构开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架。 OSI分为7层: 应用层:网络服务与最终用户的一个接口 表示层:把应用层提供的信息变换为能够共同理解的形式 会话层:建立、管理、终止会话 传输层:定义传输数据的协议端口号,以及流控和差错校验,平衡互连系统的性能差异 网络层:路由选择和中继,在一条数据链路上复用多条网络连接(IP位于网络层,通过IP地址进行路由选择) 数据链路层:数据链路的建立,拆除,对数据的检错,纠错是数据链路层的基本任务 物理层:物理层并不是物理媒体本身,它只是开放系统中利用物理媒体实现物理连接的功能描述和执行连接的规程。物理层的媒体包括架空明线、平衡电缆、光纤、无线信道等。通信用的互连设备指DTE(Data Terminal Equipment)和DCE(Data Communications Equipment)间的互连设备。DTE即数据终端设备,又称物理设备,如计算机、终端等都包括在内。而DCE则是数据通信设备或电路连接设备,如调制解调器等。数据传输通常是经过DTE-DCE,再经过DCE-DTE的路径。互连设备指将DTE、DCE连接起来的装置,如各种插头、插座。LAN中的各种粗、细同轴电缆、T型接头、插头、接收器、发送器、中继器等都属物理层的媒体和连接器 TCP/IP协议Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。协议采用了4层的层级结构。然而在很多情况下,它是利用 IP 进行通信时所必须用到的协议群的统称。 TCP/IP中的数据包: 包是全能性术语;帧用于表示数据链路层中包的单位;片是 IP中数据的单位;段则表示 TCP 数据流中的信息;消息是指应用协议中数据的单位。TCP/IP通信过程数据的流转过程: 1.数据发送时从应用层一层层往下传并且附加首部,2.通过以太网传到对端的计算机,3.再从数据链路层一层层往上传并剥离首部,剥离后的数据往上传到应用层. 备注:计算机收到包之后会剥离首部,如在数据链路层剥离首部取出MAC地址(MAC地址是网卡的信息,是属于数据链路层),若MAC地址不匹配自己的,则丢掉包.而客户端获取服务端的MAC地址是在建立连接的时候。

June 4, 2019 · 1 min · jiezi

网上威尼斯人新葡京异常维护审核不给提现怎么办

咨询扣扣78/54/14/66,有很多虚拟的网站黑了一些玩家的钱,给很多网上的朋友造成很大的损失,对于这种情况,经过我长时间的接触被黑的朋友和自己的思考,总结出了一下方法:第一种,假装代理,找人去注册,注册后联系他们说能提款后你朋友就开始充值游戏,第二种,输到本金,再提款,不过本金多也有可能不给提款,运气成分很大,还是在没有说穿的情况下才能用,第3种,找人攻击网站,不给就不停攻击,一般半个月左右,半个月也没有效果就不用再攻击了,他们运营不了也许会给,具体还要看网站情况,这几个办法用的好,也是有点几率出款的,扣扣78/54/14/66还有网上说的藏分和以分,以前很多网站都能用这种办法,后来网站多少关闭bbin电子游戏,所以后期大多数网站都不能再用这个办法了,被黑本身是很麻烦的事,大部分都是没办法的,所以选择靠谱的网站很重要,更多办法和具体操作可以来找我,这种事情,毕竟是比较复杂,三言两语的说不完,也说不清楚,伽企鹅 《785//414//66 》,空间日志文章技巧方法追回!!

May 30, 2019 · 1 min · jiezi

Java-Socket编程之UDP编程

更多资料请看:https://www.yuque.com/shizhiy... Java Socket编程之UDP编程UDP协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快      进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去;**      DatagramPacket类:表示数据报包      DatagramSocket类:进行端到端通信的类 服务器端实现步骤创建DatagramSocket,指定端口号创建DatagramPacket接受客户端发送的数据信息读取数据//服务器端,实现基于UDP的用户登录//1、创建服务器端DatagramSocket,指定端口DatagramSocket socket =new datagramSocket(10010);//2、创建数据报,用于接受客户端发送的数据byte[] data =newbyte[1024];//DatagramPacket packet =newDatagramPacket(data,data.length);//3、接受客户端发送的数据socket.receive(packet);//此方法在接受数据报之前会一致阻塞//4、读取数据String info =newString(data,o,data.length);System.out.println("我是服务器,客户端告诉我"+info);//=========================================================//向客户端响应数据//1、定义客户端的地址、端口号、数据InetAddress address = packet.getAddress();int port = packet.getPort();byte[] data2 = "欢迎您!".geyBytes();//2、创建数据报,包含响应的数据信息DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port);//3、响应客户端socket.send(packet2);//4、关闭资源socket.close(); 客户端实现步骤定义发送信息创建DatagramPacket,包含将要发送的信息创建DatagramSocket发送数据//客户端//1、定义服务器的地址、端口号、数据InetAddress address =InetAddress.getByName("localhost");int port =10010;byte[] data ="用户名:admin;密码:123".getBytes();//2、创建数据报,包含发送的数据信息DatagramPacket packet = newDatagramPacket(data,data,length,address,port);//3、创建DatagramSocket对象DatagramSocket socket =newDatagramSocket();//4、向服务器发送数据socket.send(packet);//接受服务器端响应数据//======================================//1、创建数据报,用于接受服务器端响应数据byte[] data2 = new byte[1024];DatagramPacket packet2 = new DatagramPacket(data2,data2.length);//2、接受服务器响应的数据socket.receive(packet2);String raply = new String(data2,0,packet2.getLenth());System.out.println("我是客户端,服务器说:"+reply);//4、关闭资源socket.close();

May 3, 2019 · 1 min · jiezi

Java-Socket编程之TCP编程

Java Socket编程之TCP编程全套的:https://www.yuque.com/shizhiy...基础:https://blog.51cto.com/wangdy/1588379Java Socket编程基础及深入讲解:https://www.cnblogs.com/yiwangzhibujian/p/7107785.html TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低Java中基于TCP协议实现网络通信的类 客户端的Socket类服务器端的ServerSocket类 Socket通信的步骤                ① 创建ServerSocket和Socket                ② 打开连接到Socket的输入/输出流                ③ 按照协议对Socket进行读/写操作                ④ 关闭输入输出流、关闭Socket 服务器端:               ① 创建ServerSocket对象,绑定监听端口                ② 通过accept()方法监听客户端请求                ③ 连接建立后,通过输入流读取客户端发送的请求信息                ④ 通过输出流向客户端发送乡音信息                ⑤ 关闭相关资源** ...

May 3, 2019 · 2 min · jiezi

Java-Socket编程之常识网络基础知识

更多物联网高并发编程知识请移步:https://www.yuque.com/shizhiy... Java Socket编程之常识网络基础知识网络基础知识(参考计算机网络)  《TCP/IP协议栈及OSI参考模型详解》           两台计算机间进行通讯需要以下三个条件           IP地址、协议、端口号 TCP/IP协议目前世界上应用最为广泛的协议,是以TCP和IP为基础的不同层次上多个协议的集合,也成TCP/IP协议族、或TCP/IP协议栈 TCP:Transmission Control Protocol 传输控制协议IP:Internet Protocol 互联网协议 TCP/IP五层模型应用层:HTTP、FTP、SMTP、Telnet等传输层:TCP/IP网络层:数据链路层:物理层:网线、双绞线、网卡等 IP地址为实现网络中不同计算机之间的通信,每台计算机都必须有一个唯一的标识---IP地址。 32位二进制 端口区分一台主机的多个不同应用程序,端口号范围为0-65535,其中0-1023位为系统保留。     如:HTTP:80  FTP:21 Telnet:23IP地址+端口号组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础 Socket套接字网络上具有唯一标识的IP地址和端口组合在一起才能构成唯一能识别的标识符套接字。Socket原理机制: 通信的两端都有Socket网络通信其实就是Socket间的通信数据在两个Socket间通过IO传输       Java中的网络支持针对网络通信的不同层次,Java提供了不同的API,其提供的网络功能有四大类: InetAddress:用于标识网络上的硬件资源,主要是IP地址URL:统一资源定位符,通过URL可以直接读取或写入网络上的数据Sockets:使用TCP协议实现的网络通信Socket相关的类Datagram:使用UDP协议,将数据保存在用户数据报中,通过网络进行通信。  InetAddressInetAddress类用于标识网络上的硬件资源,标识互联网协议(IP)地址。  //获取本机的InetAddress实例InetAddress address =InetAddress.getLocalHost();address.getHostName();//获取计算机名address.getHostAddress();//获取IP地址byte[] bytes = address.getAddress();//获取字节数组形式的IP地址,以点分隔的四部分//获取其他主机的InetAddress实例InetAddress address2 =InetAddress.getByName("其他主机名");InetAddress address3 =InetAddress.getByName("IP地址"); URL类URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址,协议名:资源名称  //创建一个URL的实例URL baidu =new URL("http://www.baidu.com");URL url =new URL(baidu,"/index.html?username=tom#test");//?表示参数,#表示锚点url.getProtocol();//获取协议url.getHost();//获取主机url.getPort();//如果没有指定端口号,根据协议不同使用默认端口。此时getPort()方法的返回值为 -1url.getPath();//获取文件路径url.getFile();//文件名,包括文件路径+参数url.getRef();//相对路径,就是锚点,即#号后面的内容url.getQuery();//查询字符串,即参数 使用URL读取网页内容通过URL对象的openStream()方法可以得到指定资源的输入流,通过流能够读取或访问网页上的资源 //使用URL读取网页内容//创建一个URL实例URL url = new URL("http://www.baidu.com");InputStream is = url.openStream();//通过openStream方法获取资源的字节输入流InputStreamReader isr = newInputStreamReader(is, "UTF-8");//将字节输入流转换为字符输入流,如果不指定编码,中文可能会出现乱码BufferedReader br = newBufferedReader(isr);//为字符输入流添加缓冲,提高读取效率String data = br.readLine();//读取数据while (data != null) { System.out.println(data);//输出数据 data = br.readerLine();}br.close();isr.colose();is.close();      ...

May 3, 2019 · 1 min · jiezi

网络编程理论篇

对于初学者,或者没有接触过网络编程的程序员,会觉得网络编程涉及的知识很高深,很难,其实这是一种误解,当你的语法熟悉以后,其实基本的网络编程现在已经被实现的异常简单了。 网络通信作为互联网的技术支持,已被广泛应用在软件开发中,无论是Web,服务端,客户端还是桌面应用,都是必须掌握的一门技术。 网络编程是什么?在软件开发层面实现远程数据交换的编程技术。网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。数据传递本身没有多大的难度,不就是把一个设备中的数据发送给另外一个设备,然后接受另外一个设备反馈的数据。 OSI参考模型OSI参考模型,也可以叫做OSI七层模型,在学习网络编程的时候,都会接触到OSI七层模型,我们一般使用的网络数据传输由下而上分为七层,这是一个理论的模型。分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。如下表所示: 层数名称描述第七层应用层应用层是 OSI 参考模型的最高层,负责为用户的应用程序提供网络服务。与 OSI 其他层不同的是,它不为任何其他 OSI 层提供服务,而只是为 OSI 模型以外的应用程序提供服务。包括为相互通信的应用程序或进行之间建立连接、进行同步,建立关于错误纠正和控 制数据完整性过程的协商等。应用层还包含大量的应用协议,如分布式数据库的访问、文件的交换、电子邮件、虚拟终端等。第六层表示层表示层以下的各层只关心可靠的数据传输,而表示层关心的是所传输数据的语法和语义。它主要涉及处理在两个通信系统之间所交换信息的表示方式,包括数据格式变换、数据加密与解密、数据压缩与恢复等功能。第五层会话层会话层的功能是在两个节点间建立、维护和释放面向用户的连接。它是在传输连接的基础上建立会话连接,并进行数据交换管理,允许数据进行单工、半双工和全双工的传送。会话层提供了令牌管理和同步两种服务功能。第四层传输层传输层是OSI七层模型中唯一负责端到端节点间数据传输和控制功能的层。传输层是OSI七层模型中承上启下的层,它下面的三层主要面向网络通信,以确保信息被准确有效地传输;它上面的三个层次则面向用户主机,为用户提供各种服务。传输层通过弥补网络层服务质量的不足,为会话层提供端到端的可靠数据传输服务。它为会话层屏蔽了传输层以下的数据通信的细节,使会话层不会受到下三层技术变化的影响。但同时,它又依靠下面的三个层次控制实际的网络通信操作,来完成数据从源到目标的传输。传输层为了向会话层提供可靠的端到端传输服务,也使用了差错控制和流量控制等机制。第三层网络层网络中的两台计算机进行通信时,中间可能要经过许多中间结点甚至不同的通信子网。 网络层的任务就是在通信子网中选择一条合适的路径,使发送端传输层所传下来的数据能 够通过所选择的路径到达目的端。网络层必须使用寻址方案来确定存在哪些网络以及设备在这些网络中所处的位置,不同网络层协议所采用的寻址方案是不同的。在确定了目标结点的位置后, 网络层还要负责引导数据包正确地通过网络,找到通过网络的最优路径,即路由选择。如果子网中同时出现过多的分组,它们将相互阻塞通路并可能形成网络瓶颈,所以网络层还需要提供拥塞控制机制以避免此类现象的出现。第二层数据链路层数据链路层涉及相邻节点之间的可靠数据传输,数据链路层通过加强物理层传输原始比特的功能,使之对网络层表现为一条无错线路。为了能够实现相邻节点之间无差错的数据传送,数据链路层在数据传输过程中提供了确认、差错控制和流量控制等机制。第一层物理层物理层位于OSI参考模型的最低层,它直接面向原始比特流的传输。为了实现原始比特流的物理传输,物理层必须解决好包括传输介质、信道类型、数据与信号之间的转换、信号传输中的衰减和噪声等在内的一系列问题。另外,物理层标准要给出关于物理接口的机械、 电气、功能和规程特性,以便于不同的制造厂家既能够根据公认的标准各自独立地制造设备,又能使各个厂家的产品能够相互兼容。为什么OSI要采用分层的形式?因为一个软件逻辑的实现,就是对其进行分层处理。最熟悉不过的就是MVC,如把后台的代码会分为,数据层,表现层,业务逻辑层,还有现在的前后台分离这种,其实都是分层的一种表现形式,让每一部分的工作都变的跟加的精确和具体。 但是在项目中不会像IOS参考模型中那样分层那么细致,比较常用的可能就是TCP/IP协议,那么说到这,什么又是TCP/IP协议: TCP/IP提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层,采取协议堆栈的方式,分别实现出不同通信协议。协议族下的各种协议,依其功能不同,被分别归属到这四个层次结构之中,常被视为是简化的七层OSI模型。 层数名称涵盖协议第四层应用层TELNET/SSH/HTTP/SMTP/POP/MIB/SIP/HTML(超文本传输协议)...第三层传输层TCP/UDP/SCTP/DCCP...第二层网际层ARP/IPv4/ICMP...第一层物理层以太网/无线LAN/PPP...通过上表中可以看出各个层级所包含的协议,可以把第一层和第二层看作为底层协议,然而在编写软件过程中很少的时候会用到这两层,因为这辆层一般用到会涉及到物理设备,例如链路、无线这些东西,很少会涉及到软件的逻辑。第三层是在软件开发过程中比较常用的,比如TCP,UDP之后会详细介绍。应用层会更加的熟悉,在做远程登录,数据传输时会频繁的使用到。 DNS解析DNS解析的过程就是寻找哪台机器上有你需要资源的过程。当你在浏览器中输入一个地址时,例如www.google.com,其实不是百度网站真正意义上的地址。互联网上每一台计算机的唯一标识是它的IP地址,但是IP地址并不方便记忆。用户更喜欢用方便记忆的网址去寻找互联网上的其它计算机,也就是上面提到的百度的网址。所以互联网设计者需要在用户的方便性与可用性方面做一个权衡,这个权衡就是一个网址到IP地址的转换,这个过程就是DNS解析。它实际上充当了一个翻译的角色,实现了网址到IP地址的转换。网址到IP地址转换的过程是如何进行的? 首先在本地域名服务器中查询IP地址,如果没有找到的情况下,本地域名服务器会向根域名服务器发送一个请求,如果根域名服务器也不存在该域名时,本地域名会向com顶级域名服务器发送一个请求,依次类推下去。直到最后本地域名服务器得到google的IP地址并把它缓存到本地,供下次查询使用。从上述过程中,可以看出网址的解析是一个从右向左的过程: com -> google.com -> www.google.com。但是你是否发现少了点什么,根域名服务器的解析过程呢?事实上,真正的网址是www.google.com.,并不是我多打了一个.,这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,既然是默认情况下,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上,所有网址真正的解析过程为: . -> .com -> google.com. -> www.google.com。 浏览器缓存 - 当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在);系统缓存 - 当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP;路由器缓存 - 当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查,以上三步均为客服端的DNS缓存;ISP(互联网服务提供商)DNS缓存 - 当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;根域名服务器 - 当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器;顶级域名服务器 - 顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器;主域名服务器 - 主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确纪录;保存结果至缓存 - 本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个IP地址与web服务器建立链接。TCP连接HTTP协议是使用TCP作为其传输层协议的,当TCP出现瓶颈时,HTTP也会受到影响。我不知道把HTTPS放在这个部分是否合适,但是放在这里好像又说的过去。HTTP报文是包裹在TCP报文中发送的,服务器端收到TCP报文时会解包提取出HTTP报文。但是这个过程中存在一定的风险,HTTP报文是明文,如果中间被截取的话会存在一些信息泄露的风险。那么在进入TCP报文之前对HTTP做一次加密就可以解决这个问题了。HTTPS协议的本质就是HTTP+SSL(orTLS)。在HTTP报文进入TCP报文之前,先使用SSL对HTTP报文进行加密。从网络的层级结构看它位于HTTP协议与TCP协议之间。 原理:Net模块提供一个异步API能够创建基于流的TCP服务器,客户端与服务端简历连接后,服务器可以获得一个全双工Socket对象,服务器可以保存Socket对象列表,在接收某客户端消息时,推送给客户端。 dome 服务端: const net = require("net");const chatServer = net.createServer();const clientList = [];chatServer.on("connection",client => { client.write("Hi!\n"); clientList.push(client); client.on("data",data => { console.log("receive:",data.toString()); clientList.forEach(v => { v.write(data); }) })});chatServer.listen(9000);TCP特性 ...

April 25, 2019 · 1 min · jiezi

netty学习总结(一)

netty学习总结(一)netty是什么?netty是一个异步的,事件驱动的网络编程框架。netty的技术基础netty是对Java NIO和Java线程池技术的封装netty解决了什么问题使用Java IO进行网络编程,一般一个用户一个线程,无法处理海量用户使用Java NIO进行网络编程,编程复杂性太高,如果没有深厚的NIO网络编程基础,写出的程序可能还不如Java IO写的程序至于Java AIO,目前还没有弄清楚其与netty孰优孰劣netty架构netty架构是基于Reactor和责任链模式进行设计的。reactor关于reactor的原理,参考“【NIO系列】——之Reactor模型”netty的reactor是多reactor多线程模型,其中reactor在netty中以eventloop的形式出现。责任链模式netty通过popeline将handler组装起来,通过向pipeline里添加handler来监听处理发生的事件。netty服务端编程模式// 用于监听客户端链接的eventloop池,一般只有一个eventloopNioEventLoopGroup bossGroup = new NioEventLoopGroup();// 用于处理客户端IO的eventloop池NioEventLoopGroup workGroup = new NioEventLoopGroup();// 辅助类,帮助初始化服务器ServerBootStrap bootstrap = new ServerBootStrap();bootstrap.group(bossGroup, workGroup) // bossGroup和workGroup可以是同一个 .channel(NioServerSocketChannel.class) // 设置服务端监听套接字的channel类型 .option(ChannelOption.SO_BACKLOG, 1024) // 设置监听套接字的参数 .handler(new LoggingHandler()) // 设置监听套接字的handler .childHandler(new ChannelInitializer<SocketChannel>(){ // 设置客户端套接字的handler public void initChannle(SocketChannel ch){ // 向pipleline中添加handler,用于处理客户端IO ch.pipeline().addLast(…); } });int port = 8080;try{ ChannelFuture f = bootstrap.bind(port).sync(); f.channel().closeFuture().sync();}catch(IOException e){ e.printStacktrac();}finally{ bossGroup.shutdownGracefully(); workGroup.shutdownGracefully();}netty客户端编程模型// 用于处理与服务端IO的eventloop池NioEventLoopGroup group = new NioEventLoopGroup();// 辅助类,帮助初始化客户端BootStrap bootstrap = new BootStrap();bootstrap.group(group) .channel(NioSocketChannel.class) // 设置客户端套接字的channel类型 .option(ChannelOption.NO_DELAY, true) // 设置客户端套接字的参数 .handler(new ChannelInitializer<SocketChannel>(){ // 设置客户端套接字的handler public void initChannel(SocketChannel ch){ // 向pipleline中添加handler,用于处理客户端IO ch.pipeline().addLast(…); } });String host = “127.0.0.1”;int port = 8080;try{ ChannelFuture f = bootstrap.connect(host, port).sync(); f.channel().closeFuture().sync();}catch(IOException e){ e.printStacktrac();}finally{ group.shutdownGracefully();}buffernetty认为Java NIO的Buffer太难用了,因此自己实现了一套Buffer。相比于Java NIO的netty的buffer不仅易用,而且还支持自动扩容。netty的buffer可以抽象为三个指针readIndex, writeIndex, limit.读buffer增加readIndex,写buffer会增加writeIndex,如果写的数据量超过limit,则会增加buffer容量。netty buffer也支持随机读写netty中buffer一般通过Unpooled工具类创建,有三大类buffer:在JVM堆上分配的buffer。优点是分配快速,易于回收,缺点是最终还是要将数据复制到直接缓存中直接缓冲区,直接通过系统调用malloc分配的内存,优点是减少数据移动,缺点是分配慢,回收麻烦组合缓冲区,即将不同种类的buffer进行封装,访问时就像访问一个buffer,可以通过这个方式对缓冲区进行划分,但是会增加访问时间handlerhandler分为处理入站事件的handler和出站事件的handler。通过实现相应的方法来监听相应的事件netty也提供了一些adapter类来减少开发者的工作量。入站handler入站事件一般是由外部触发的,如收到数据。基类为ChannelInboundHandler出栈handler出站事件由内部触发,如写数据基类为ChannelOutboundHandler ...

April 14, 2019 · 1 min · jiezi

零拷贝总结(zero copy)

零拷贝总结(zero copy)前言在学习netty的过程中,发现Netty对缓存做了很多优化,其中零拷贝一直令我迷惑,所以在网上找了一些博客进行学习,并作此总结定义零复制(英语:Zero-copy;也译零拷贝)技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。[1]应用场景[2]在web应用中,经常需要传输一些静态文件(css, js, 图片等),可讲这一过程抽象为下面两个系统调度:read(file, tmp_buf, len); write(socket, tmp_buf, len);系统调用会进行上下文切换,共两次上下文切换:用户态 -> 内核态 -> 用户态上面的传输过程中,共涉及4次上下文切换,4次数据复制,其流程如下图上图中分为两部分,上半部分表示执行上下文(PC,寄存器等),下半部分表示数据区(堆栈等)上班部分描绘了这一过程的上下文切换,下半部分描述了数据移动。在第一个区间里(处于用户态),执行read系统调度,读取文件数据到tmp_buf中,因此会进行上下文切换,切换到内核态(第二区间),然后内核从磁盘中读取文件数据到内核的缓冲区中(红线所示,这种复制是利用DMA直接从磁盘复制到内存,不经过CPU的寄存器,所以称为DMA copy),接下来在将文件数据从内核缓冲区中复制到用户缓冲区tmp_buf(蓝色虚线所示,这种复制是先从内存到寄存器,然后寄存器到内核缓冲区,所以称为CPU copy),并切换回用户态(第三个区间),此时read调用就完成了,文件数据存在tmp_buf中。接下来进行write系统调用(处于第三个区间,用户态),讲tmp_buf的数据写入socket中,首先进行上下文切换,进入内核态(第四个区间),然后讲tmp_buf的数据复制到socket缓冲区中(蓝色虚线所示),最后利用DMA从socket缓冲区将数据复制到网卡,然后切换回用户态(第五个区间),此时wirte执行完成,但是数据可能还没有发送完成。当需要进行大量的上述操作时,上下文切换和内存复制就会严重的影响性能,为此Linux内核提供了sendFile来解决这个文件。为什么read调用,需要先将数据从磁盘复制到内核缓冲区,然后再从kernel buffer复制到user buffer呢?首先kernel buffer和user buffer大小不一定相等。kernel buffer的作用是预读,每次调用read时不一定会触发磁盘读,只用当kernel buffer中的数据都被读取完后,才会触发,然后从磁盘中多读取一些数据到kernel buffer(从磁盘的读取数据的大小,并不完全取决于用户执行的大小,还取决于kernel buffer的大小,以及文件的大小)。这样当用户多次调用read读取同一文件的数据时,就不需要每次都直接从硬盘中读取,因为每次会多读一些数据到kernel buffer中,这样read就可以直接从kernel buffer中读取数据,然后复制到user buffer,这种做法在每次读取数据量小于kernel buffer的大小时,可以显著的提高效率,但是当每次读取数据量超过kernel buffer大小时,就会显得低效了。为什么write调用,需要先将数据从user buffer复制到kernel buffer,然后在从kernel buffer复制到网卡呢?这样做的原因是为了快速返回,从user buffer复制到kernel buffer的速度应该是快于从kernel buffer到网卡的,如果直接冲user buffer复制到网卡,会影响程序的性能。在将数据从user buffer复制到kernel buffer后,write就可以返回了,剩下的就是利用DMA从kernel buffer读取数据到网卡。我认为,这是阻塞io的做法,对于一些异步io,是可以直接将user buffer的数据复制到网卡的(存疑,待以后解决)。sendfileLinux2.1在Linux2.1中,sendfile的执行过程如下图:这里只有一次系统调用,所以只有两次上下文切换:用户态 -> 内核态 -> 用户态数据复制有3次:磁盘 -> 内核缓冲区 -> socket缓冲区 -> 网卡上述的复制种,从内核缓冲区到socket缓冲区显得比较多余,因此在Linux2.4对其进行了优化Linux2.4在Linux2.4种,sendfile的执行过程如下图:关键的改动在于,将kernel buffer的信息添加到socket buffer,然后协议引擎利用这个信息,直接从kernel buffer读取数据。但是这种操作,需要网卡支持gather操作。问题零拷贝,虽然对提升程序性能有很大的帮助,但是对传输的文件的安全性没有保证,相当于明文传输。由于文件直接从磁盘读取到网络,所以无法对文件进行加密。因此对于需要对传输的数据进行加密的程序,如HTTPS,并不适用。参考文献[1] 零复制[2] 什么是Zero-Copy?[3] Zero-Copy&sendfile浅析[4] Efficient data transfer through zero copy[5] Zero Copy I: User-Mode Perspective

April 14, 2019 · 1 min · jiezi

物联网高并发编程之P2P技术NAT快速理解

物联网高并发编程之P2P技术NAT快速理解更多物联网高并发编程知识请移步:https://www.yuque.com/shizhiy…前言P2P技术在现实的应用场景中,主要用于诸如IM(尤其移动端IM)、在线直播、在线教育等(这些应用里的实时音视频功能通常都会涉及到P2P),了解P2P的原理对于开发相关的应用来说还是很有必要的。基础知识简单介绍一下 详细了解请翻阅他的上下篇文章什么是NAT?NAT(Network Address Translation,网络地址转换),也叫做网络掩蔽或者IP掩蔽。NAT是一种网络地址翻译技术,主要是将内部的私有IP地址(private IP)转换成可以在公网使用的公网IP(public IP)。为什么会有NAT?时光回到上个世纪80年代,当时的人们在设计网络地址的时候,觉得再怎么样也不会有超过32bits位长即2的32次幂台终端设备连入互联网,再加上增加ip的长度(即使是从4字节增到6字节)对当时设备的计算、存储、传输成本也是相当巨大的。后来逐渐发现IP地址不够用了,然后就NAT就诞生了!(虽然ipv6也是解决办法,但始终普及不开来,而且未来到底ipv6够不够用仍是未知)。因此,NAT技术能够兴起的原因还是因为在我们国家公网IP地址太少了,不够用,所以才会采取这种地址转换的策略。可见,NAT的本质就是让一群机器公用同一个IP,这样就暂时解决了IP短缺的问题。NAT有什么优缺点?优势其实上面已经刚刚讨论过了,根据定义,比较容易看出,NAT可以同时让多个计算机同时联网,并隐藏其内网IP,因此也增加了内网的网络安全性;此外,NAT对来自外部的数据查看其NAT映射记录,对没有相应记录的数据包进行拒绝,提高了网络安全性。那么,NAT与此同时也带来一些弊端:首先是,NAT设备会对数据包进行编辑修改,这样就降低了发送数据的效率;此外,各种协议的应用各有不同,有的协议是无法通过NAT的(不能通过NAT的协议还是蛮多的),这就需要通过穿透技术来解决。我们后面会重点讨论穿透技术。简单的背景了解过后,下面介绍下NAT实现的主要方式,以及NAT都有哪些类型。NAT的实现方式静态NAT也就是静态地址转换。是指一个公网IP对应一个私有IP,是一对一的转换,同时注意,这里只进行了IP转换,而没有进行端口的转换NAPT端口多路复用技术。与静态NAT的差别是,NAPT不但要转换IP地址,还要进行传输层的端口转换。具体的表现形式就是,对外只有一个公网IP,通过端口来区别不同私有IP主机的数据NAT的主要类型对于NAPT我们主要分为两大类:锥型NAT和对称型NAT。其中锥型NAT又分:完全锥型,受限锥型和端口受限锥型。概括的说:对称型NAT是一个请求对应一个端口;锥型NAT(非对称NAT)是多个请求(外部发向内部)对应一个端口,只要源IP端口不变,无论发往的目的IP是否相同,在NAT上都映射为同一个端口,形象的看起来就像锥子一样。下面分别介绍这四种类型及其差异:完全锥型NAT(Full Cone NAT,后面简称FC)特点:IP和端口都不受限。表现形式:将来自内部同一个IP地址同一个端口号(IP_IN_A : PORT_IN_A)的主机监听/请求,映射到公网IP某个端口(IP_OUT_B : PORT_OUT_B)的监听。任意外部IP地址与端口对其自己公网的IP这个映射后的端口访问(IP_OUT_B : PORT_OUT_B),都将重新定位到内部这个主机(IP_IN_A : PORT_IN_A)。该技术中,基于C/S架构的应用可以在任何一端发起连接。是不是很绕啊。再简单一点的说,就是,只要客户端,由内到外建立一个映射(NatIP:NatPort -> A:P1)之后,其他IP的主机B或端口A:P2都可以使用这个洞给客户端发送数据。受限锥型NAT(Restricted Cone NAT)特点:IP受限,端口不受限。表现形式:与完全锥形NAT不同的是,在公网映射端口后,并不允许所有IP进行对于该端口的访问,要想通信必需内部主机对某个外部IP主机发起过连接,然后这个外部IP主机就可以与该内部主机通信了,但端口不做限制。举个栗子。当客户端由内到外建立映射(NatIP:NatPort –> A:P1),A机器可以使用他的其他端口(P2)主动连接客户端,但B机器则不被允许。因为IP受限啦,但是端口随便。见下图(绿色是允许通信,红色是禁止通信)端口受限型NAT(Port Restricted Cone NAT)特点:IP和端口都受限。表现形式:该技术与受限锥形NAT相比更为严格。除具有受限锥形NAT特性,对于回复主机的端口也有要求。也就是说:只有当内部主机曾经发送过报文给外部主机(假设其IP地址为A且端口为P1)之后,外部主机才能以公网IP:PORT中的信息作为目标地址和目标端口,向内部主机发送UDP报文,同时,其请求报文的IP必须是A,端口必须为P1(使用IP地址为A,端口为P2,或者IP地址为B,端口为P1都将通信失败)。例子见下图。这一要求进一步强化了对外部报文请求来源的限制,从而较Restrictd Cone更具安全性对称型NAT(Symmetric NAT)特点:对每个外部主机或端口的会话都会映射为不同的端口(洞)。表现形式:只有来自同一内部IP:PORT、且针对同一目标IP:PORT的请求才被NAT转换至同一个公网(外部)IP:PORT,否则的话,NAT将为之分配一个新的外部(公网)IP:PORT。并且,只有曾经收到过内部主机请求的外部主机才能向内部主机发送数据包。内部主机用同一IP与同一端口与外部多IP通信。客户端想和服务器A(IP_A:PORT_A)建立连接,是通过NAT映射为NatIP:NatPortA来进行的。而客户端和服务器B(IP_B:PORT_B)建立连接,是通过NAT映射为NatIP:NatPortB来进行的。即同一个客户端和不同的目标IP:PORT通信,经过NAT映射后的公网IP:PORT是不同的。此时,如果B想要和客户端通信,也只能通过NatIP:NatPortB(也就是紫色的洞洞)来进行,而不能通过NatIP:NatPortA(也就是黄色的洞洞)小结可以看出从类型1至类型4,NAT的限制是越来越大的。NAT路由类型判断根据上面的介绍,我们可以了解到,在实际的网络情况中,各个设备所处的网络环境是不同的。那么,如果这些设备想要进行通信,首先判断出设备所处的网络类型就是非常重要的一步。举个例子来说:对于IM中的实时音视频功能和VoIP软件,对位于不同NAT内部的主机通信需要靠服务器来转发完成,这样就会增加服务器的负担。为了解决这种问题,要尽量使位于不同NAT内部的主机建立直接通信,其中,最重要的一点就是要判断出NAT的类型,然后才能根据NAT的类型,设计出直接通信方案。不然的话,两个都在NAT的终端怎么通信呢?我们不知道对方的内网IP,即使把消息发到对方的网关,然后呢?网关怎么知道这条消息给谁,而且谁允许网关这么做了?为了解决这个问题,也就是处于内网的主机之间能够穿越它们之间的NAT建立直接通信,已经提出了许多方法,STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)技术就是其中比较重要的一种解决方法,并得到了广泛的应用。在这个部分,我们将重点介绍下STUN技术的原理。PS:除此之外,还有UPNP技术,ALG应用层网关识别技术,SBC会话边界控制,ICE交互式连接建立,TURN中继NAT穿越技术等等,本文不一一做介绍。STUN协议介绍STUN基本介绍STUN是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。这些信息被用来在两个同时处于NAT路由器之后的主机之间建立UDP通信。该协议由RFC 5389定义。STUN由三部分组成:STUN客户端;STUN服务器端;NAT路由器。STUN服务端部署在一台有着两个公网IP的服务器上,大概的结构参考下图。STUN客户端通过向服务器端发送不同的消息类型,根据服务器端不同的响应来做出相应的判断,一旦客户端得知了Internet端的UDP端口,通信就可以开始了STUN的检测过程STUN协议定义了三类测试过程来检测NAT类型:Test1:STUN Client通过端口{IP-C1:Port-C1}向STUN Server{IP-S1:Port-S1}发送一个Binding Request(没有设置任何属性)。STUN Server收到该请求后,通过端口{IP-S1:Port-S1}把它所看到的STUN Client的IP和端口{IP-M1,Port-M1}作为Binding Response的内容回送给STUN Client。Test1#2:STUN Client通过端口{IP-C1:Port-C1}向STUN Server{IP-S2:Port-S2}发送一个Binding Request(没有设置任何属性)。STUN Server收到该请求后,通过端口{IP-S2:Port-S2}把它所看到的STUN Client的IP和端口{IP-M1#2,Port-M1#2}作为Binding Response的内容回送给STUN Client。Test2:STUN Client通过端口{IP-C1:Port-C1}向STUN Server{IP-S1:Port-S1}发送一个Binding Request(设置了Change IP和Change Port属性)。STUN Server收到该请求后,通过端口{IP-S2:Port-S2}把它所看到的STUN Client的IP和端口{IP-M2,Port-M2}作为Binding Response的内容回送给STUN Client。Test3:STUN Client通过端口{IP-C1:Port-C1}向STUN Server{IP-S1:Port-S1}发送一个Binding Request(设置了Change Port属性)。STUN Server收到该请求后,通过端口{IP-S1:Port-S2}把它所看到的STUN Client的IP和端口{IP-M3,Port-M3}作为Binding Response的内容回送给STUN Client。STUN协议的输出是:1)公网IP和Port;2)防火墙是否设置;3)客户端是否在NAT之后,及所处的NAT的类型。因此我们进而整理出,通过STUN协议,我们可以检测的类型一共有以下七种:A:公开的互联网IP:主机拥有公网IP,并且没有防火墙,可自由与外部通信;B:完全锥形NAT;C:受限制锥形NAT;D:端口受限制形NAT;E:对称型UDP防火墙:主机出口处没有NAT设备,但有防火墙,且防火墙规则如下:从主机UDP端口A发出的数据包保持源地址,但只有从之前该主机发出包的目的IP/PORT发出到该主机端口A的包才能通过防火墙;F:对称型NAT;G:防火墙限制UDP通信。STUN协议的判断过程输入和输出准备好后,附上一张维基百科的流程图,就可以描述STUN协议的判断过程了。STEP1:检测客户端是否有能力进行UDP通信以及客户端是否位于NAT后 – Test1客户端建立UDP socket,然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器返回客户端的IP和Port,客户端发送请求后立即开始接受数据包。重复几次。如果每次都超时收不到服务器的响应,则说明客户端无法进行UDP通信,可能是:G防火墙阻止UDP通信;如果能收到回应,则把服务器返回的客户端的(IP:PORT)同(Local IP: Local Port)比较: - 如果完全相同则客户端不在NAT后,这样的客户端是:A具有公网IP可以直接监听UDP端口接收数据进行通信或者E。 - 否则客户端在NAT后要做进一步的NAT类型检测(继续)。STEP2:检测客户端防火墙类型 – Test2STUN客户端向STUN服务器发送请求,要求服务器从其他IP和PORT向客户端回复包:收不到服务器从其他IP地址的回复,认为包前被前置防火墙阻断,网络类型为E;收到则认为客户端处在一个开放的网络上,网络类型为A。STEP3:检测客户端NAT是否是FULL CONE NAT – Test2客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器用另一对(IP-2,Port-2)响应客户端的请求往回发一个数据包,客户端发送请求后立即开始接受数据包。 重复这个过程若干次。如果每次都超时,无法接受到服务器的回应,则说明客户端的NAT不是一个Full Cone NAT,具体类型有待下一步检测(继续);如果能够接受到服务器从(IP-2,Port-2)返回的应答UDP包,则说明客户端是一个Full Cone NAT,这样的客户端能够进行UDP-P2P通信。STEP4:检测客户端NAT是否是SYMMETRIC NAT – Test1#2客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器返回客户端的IP和Port, 客户端发送请求后立即开始接受数据包。 重复这个过程直到收到回应(一定能够收到,因为第一步保证了这个客户端可以进行UDP通信)。用同样的方法用一个socket向服务器的(IP-2,Port-2)发送数据包要求服务器返回客户端的IP和Port。比较上面两个过程从服务器返回的客户端(IP,Port),如果两个过程返回的(IP,Port)有一对不同则说明客户端为Symmetric NAT,这样的客户端无法进行UDP-P2P通信(检测停止)因为对称型NAT,每次连接端口都不一样,所以无法知道对称NAT的客户端,下一次会用什么端口。否则是Restricted Cone NAT,是否为Port Restricted Cone NAT有待检测(继续)。STEP5:检测客户端NAT是Restricted Cone 还是 Port Restricted Cone – Test3客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器用IP-1和一个不同于Port-1的端口发送一个UDP 数据包响应客户端, 客户端发送请求后立即开始接受数据包。重复这个过程若干次。如果每次都超时,无法接受到服务器的回应,则说明客户端是一个Port Restricted Cone NAT,如果能够收到服务器的响应则说明客户端是一个Restricted Cone NAT。以上两种NAT都可以进行UDP-P2P通信。通过以上过程,至此,就可以分析和判断出客户端是否处于NAT之后,以及NAT的类型及其公网IP,以及判断客户端是否具备P2P通信的能力了。 ...

March 17, 2019 · 1 min · jiezi

物联网高并发编程之P2P技术NAT穿越方案

物联网高并发编程之P2P技术NAT穿越方案更多物联网高并发编程知识请移步:https://www.yuque.com/shizhiy…内容概述P2P即点对点通信,或称为对等联网,与传统的服务器客户端模式(如下图“P2P结构模型”所示)有着明显的区别,在即时通讯方案中应用广泛(比如IM应用中的实时音视频通信、实时文件传输甚至文字聊天等)。P2P可以是一种通信模式、一种逻辑网络模型、一种技术、甚至一种理念。在P2P网络中(如右图所示),所有通信节点的地位都是对等的,每个节点都扮演着客户机和服务器双重角色,节点之间通过直接通信实现文件信息、处理器运算能力、存储空间等资源的共享。P2P网络具有分散性、可扩展性、健壮性等特点,这使得P2P技术在信息共享、即时通讯、协同工作、分布式计算、网络存储等领域都有广阔的应用。1经典的CS模式: P2P结构模型:NAT技术和P2P技术作为经典的两项网络技术,在现在的网络上有着广泛的应用,P2P主机位于NAT网关后面的情况屡见不鲜。NAT技术虽然在一定程度上解决了IPv4地址短缺的问题,在构建防火墙、保证网络安全方面都发挥了一定的作用,却破坏了端到端的网络通信。NAT阻碍主机进行P2P通信的主要原因是NAT不允许外网主机主动访问内网主机,但是P2P技术却要求通信双方都能主动发起访问,所以要在NAT网络环境中进行有效的P2P通信,就必须采用新的解决方案。P2P作为一项实用的技术,有很大的优化空间,并且相对于网络设备,基于P2P的应用程序在实现上更为灵活。所以为了兼容NAT,基于P2P的应用程序在开发的时候大多会根据自身特点加入一些穿越NAT的功能以解决上述问题。以下着重介绍几种常见的P2P穿越NAT方案。**反向链接技术一种特殊的P2P场景(通信双方中只有一方位于NAT设备之后)此种情况是所有P2P场景中最简单的,它使用一种被称为“反向链接技术”来解决这个问题。大致的原理如下所述。如图所示,客户端A位于NAT之后,它通过TCP端口1234连接到服务器的TCP端口1235上,NAT设备为这个连接重新分配了TCP端口62000。客户端B也通过TCP端口1234连接到服务器端口1235上。A和B从服务器处获知的对方的外网地址二元组{IP地址:端口号}分别为{138.76.29.7:1234}和{155.99.25.11:62000},它们在各自的本地端口上进行侦听。由于B 拥有外网IP地址,所以A要发起与B的通信,可以直接通过TCP连接到B。但如果B尝试通过TCP连接到A进行P2P通信,则会失败,原因是A位于NAT设备后,虽然B发出的TCP SYN请求能够到达NAT设备的端口62000,但NAT设备会拒绝这个连接请求。要想与Client A通信, B不是直接向A发起连接,而是通过服务器给A转发一个连接请求,反过来请求A连接到B(即进行反向链接),A在收到从服务器转发过来的请求以后,会主动向B发起一个TCP的连接请求,这样在NAT设备上就会建立起关于这个连接的相关表项,使A和B之间能够正常通信,从而建立起它们之间的TCP连接。基于UDP协议的P2P打洞技术原理概述UDP打洞技术是通过中间服务器的协助在各自的NAT网关上建立相关的表项,使P2P连接的双方发送的报文能够直接穿透对方的NAT网关,从而实现P2P客户端互连。如果两台位于NAT设备后面的P2P客户端希望在自己的NAT网关上打个洞,那么他们需要一个协助者——集中服务器,并且还需要一种用于打洞的Session建立机制。什么是集中服务器?集中服务器本质上是一台被设置在公网上的服务器,建立P2P的双方都可以直接访问到这台服务器。位于NAT网关后面的客户端A和B都可以与一台已知的集中服务器建立连接,并通过这台集中服务器了解对方的信息并中转各自的信息。同时集中服务器的另一个重要作用在于判断某个客户端是否在NAT网关之后。具体的方法是:一个客户端在集中服务器上登陆的时候,服务器记录下该客户端的两对地址二元组信息{IP地址:UDP端口},一对是该客户端与集中服务器进行通信的自身的IP地址和端口号,另一对是集中服务器记录下的由服务器“观察”到的该客户端实际与自己通信所使用的IP地址和端口号。我们可以把前一对地址二元组看作是客户端的内网IP地址和端口号,把后一对地址二元组看作是客户端的内网IP地址和端口号经过NAT转换后的外网IP地址和端口号。集中服务器可以从客户端的登陆消息中得到该客户端的内网相关信息,还可以通过登陆消息的IP头和UDP头得到该客户端的外网相关信息。如果该客户端不是位于NAT设备后面,那么采用上述方法得到的两对地址二元组信息是完全相同的。P2P的Session建立原理:假定客户端A要发起对客户端B的直接连接,具体的“打洞”过程如下:1)A最初不知道如何向客户端B发起连接,于是A向集中服务器发送消息,请求集中服务器帮助建立与客户端B的UDP连接。2)集中服务器将含有B的外网和内网的地址二元组发给A,同时,集中服务器将包含有A的外网和内网的地址二元组信息的消息也发给B。这样一来, A与B就都知道对方外网和内网的地址二元组信息了。3)当A收到由集中服务器发来的包含B的外网和内网的地址二元组信息后, A开始向B的地址二元组发送UDP数据包,并且A会自动锁定第一个给出响应的B的地址二元组。同理,当B收到由集中服务器发来的A的外网和内网地址二元组信息后,也会开始向A的外网和内网的地址二元组发送UDP数据包,并且自动锁定第一个得到A回应的地址二元组。由于A与B互相向对方发送UDP数据包的操作是异步的,所以A和B发送数据包的时间先后并没有时序要求。下面来看下这三者之间是如何进行UDP打洞的。在这我们分三种具体情景来讨论:第一种是最简单的一种情景,两个客户端都位于同一个NAT设备后面,即位于同一内网中;第二种是最普遍的一种情景,两个客户端分别位于不同的NAT设备后面,分属不同的内网;第三种是客户端位于两层NAT设备之后,通常最上层的NAT是由网络提供商提供的,第二层NAT是家用的NAT路由器之类的设备提供的。典型P2P情景1: 两客户端位于同一NAT设备后面这是最简单的一种情况(如图4所示):客户端A和B分别与集中服务器建立UDP连接,经过NAT转换后,A的公网端口被映射为62000,B的公网端口映射为62005。位于同一个NAT设备后的UDP打洞过程: 当A向集中服务器发出消息请求与B进行连接,集中服务器将B的外网地址二元组以及内网地址二元组发给A,同时把A的外网以及内网的地址二元组信息发给B。A和B发往对方公网地址二元组信息的UDP数据包不一定会被对方收到,这取决于当前的NAT设备是否支持不同端口之间的UDP数据包能否到达(即Hairpin转换特性),无论如何A与B发往对方内网的地址二元组信息的UDP数据包是一定可以到达的,内网数据包不需要路由,且速度更快。A与B推荐采用内网的地址二元组信息进行常规的P2P通信。假定NAT设备支持Hairpin转换,P2P双方也应忽略与内网地址二元组的连接,如果A 和B采用外网的地址二元组做为P2P通信的连接,这势必会造成数据包无谓地经过NAT设备,这是一种对资源的浪费。就目前的网络情况而言,应用程序在“打洞”的时候,最好还是把外网和内网的地址二元组都尝试一下。如果都能成功,优先以内网地址进行连接。什么是Hairpin技术?Hairpin技术又被称为Hairpin NAT、Loopback NAT或Hairpin Translation。Hairpin技术需要NAT网关支持,它能够让两台位于同一台NAT网关后面的主机,通过对方的公网地址和端口相互访问,NAT网关会根据一系列规则,将对内部主机发往其NAT公网IP地址的报文进行转换,并从私网接口发送给目标主机。目前有很多NAT设备不支持该技术,这种情况下,NAT网关在一些特定场合下将会阻断P2P穿越NAT的行为,打洞的尝试是无法成功的。好在现在已经有越来越多的NAT设备商开始加入到对该转换的支持中来。典型P2P情景2: 两客户端位于不同的NAT设备后面这是最普遍的一种情况(如图5所示):客户端A与B经由各自的NAT设备与集中服务器建立UDP连接, A与B的本地端口号均为4321,集中服务器的公网端口号为1234。在向外的会话中, A的外网IP被映射为155.99.25.11,外网端口为62000;B的外网IP被映射为138.76.29.7,外网端口为31000。如下所示:**客户端A——>本地IP:10.0.0.1,本地端口:4321,外网IP:155.99.25.11,外网端口:62000客户端B——>本地IP:10.1.1.3,本地端口:4321,外网IP:138.76.29.7,外网端口:31000位于不同NAT设备后的UDP打洞过程:在A向服务器发送的登陆消息中,包含有A的内网地址二元组信息,即10.0.0.1:4321;服务器会记录下A的内网地址二元组信息,同时会把自己观察到的A的外网地址二元组信息记录下来。同理,服务器也会记录下B的内网地址二元组信息和由服务器观察到的客户端B的外网地址二元组信息。无论A与B二者中的任何一方向服务器发送P2P连接请求,服务器都会将其记录下来的上述的外网和内网地址二元组发送给A或B。A和B分属不同的内网,它们的内网地址在外网中是没有路由的,所以发往各自内网地址的UDP数据包会发送到错误的主机或者根本不存在的主机上。当A的第一个消息发往B的外网地址(如图3所示),该消息途经A的NAT设备,并在该设备上生成一个会话表项,该会话的源地址二元组信息是{10.0.0.1:4321},和A与服务器建立连接的时候NAT生成的源地址二元组信息一样,但它的目的地址是B的外网地址。在A的NAT设备支持保留A的内网地址二元组信息的情况下,所有来自A的源地址二元组信息为{10.0.0.1:4321}的数据包都沿用A与集中服务器事先建立起来的会话,这些数据包的外网地址二元组信息均被映射为{155.99.25.11:62000}。A向B的外网地址发送消息的过程就是“打洞”的过程,从A的内网的角度来看应为从{10.0.0.1:4321}发往{138.76.29.7:31000},从A在其NAT设备上建立的会话来看,是从{155.99.25.11:62000}发到{138.76.29.7:31000}。如果A发给B的外网地址二元组的消息包在B向A发送消息包之前到达B的NAT设备,B的NAT设备会认为A发过来的消息是未经授权的外网消息,并丢弃该数据包。B发往A的消息包也会在B的NAT设备上建立一个{10.1.1.3:4321,155.99.25.11:62000}的会话(通常也会沿用B与集中服务器连接时建立的会话,只是该会话现在不仅接受由服务器发给B的消息,还可以接受从A的NAT设备{155.99.25.11:6200}发来的消息)。一旦A与B都向对方的NAT设备在外网上的地址二元组发送了数据包,就打开了A与B之间的“洞”,A与B向对方的外网地址发送数据,等效为向对方的客户端直接发送UDP数据包了。一旦应用程序确认已经可以通过往对方的外网地址发送数据包的方式让数据包到达NAT后面的目的应用程序,程序会自动停止继续发送用于“打洞”的数据包,转而开始真正的P2P数据传输。 典型P2P情景3: 两客户端位于两层(或多层)NAT设备之后此种情景最典型的部署情况就像这样:最上层的NAT设备通常是由网络提供商(ISP)提供,下层NAT设备是家用路由器。如图所示:假定NAT C是由ISP提供的NAT设备,NAT C提供将多个用户节点映射到有限的几个公网IP的服务,NAT A和NAT B作为NAT C的内网节点将把用户的内部网络接入NAT C的内网,用户的内部网络就可以经由NAT C访问公网了。从这种拓扑结构上来看,只有服务器与NAT C是真正拥有公网可路由IP地址的设备,而NAT A和NAT B所使用的公网IP地址,实际上是由ISP服务提供商设定的(相对于NAT C而言)内网地址(我们将这种由ISP提供的内网地址称之为“伪”公网地址)。同理,隶属于NAT A与NAT B的客户端,它们处于NAT A,NAT B的内网,以此类推,客户端可以放到到多层NAT设备后面。客户端A和客户端B发起对服务器S的连接的时候,就会依次在NAT A和NAT B上建立向外的Session,而NAT A、NAT B要联入公网的时候,会在NAT C上再建立向外的Session。现在假定客户端A和B希望通过UDP“打洞”完成两个客户端的P2P直连。最优化的路由策略是客户端A向客户端B的“伪公网”IP上发送数据包,即ISP服务提供商指定的内网IP,NAT B的“伪”公网地址二元组,{10.0.1.2:55000}。由于从服务器的角度只能观察到真正的公网地址,也就是NAT A,NAT B在NAT C建立session的真正的公网地址{155.99.25.11:62000}以及{155.99.25.11:62005},非常不幸的是客户端A与客户端B是无法通过服务器知道这些“伪”公网的地址,而且即使客户端A和B通过某种手段可以得到NAT A和NAT B的“伪”公网地址,我们仍然不建议采用上述的“最优化”的打洞方式,这是因为这些地址是由ISP服务提供商提供的或许会存在与客户端本身所在的内网地址重复的可能性(例如:NAT A的内网的IP地址域恰好与NAT A在NAT C的“伪”公网IP地址域重复,这样就会导致打洞数据包无法发出的问题)。因此客户端别无选择,只能使用由公网服务器观察到的A,B的公网地址二元组进行“打洞”操作,用于“打洞”的数据包将由NAT C进行转发。当客户端A向客户端B的公网地址二元组{155.99.25.11:62005}发送UDP数据包的时候,NAT A首先把数据包的源地址二元组由A的内网地址二元组{10.0.0.1:4321}转换为“伪”公网地址二元组{10.0.1.1:45000},现在数据包到了NAT C,NAT C应该可以识别出来该数据包是要发往自身转换过的公网地址二元组,如果NAT C可以给出“合理”响应的话,NAT C将把该数据包的源地址二元组改为{155.99.25.11:62000},目的地址二元组改为{10.0.1.2:55000},即NAT B的“伪”公网地址二元组,NAT B最后会将收到的数据包发往客户端B。同样,由B发往A的数据包也会经过类似的过程。目前也有很多NAT设备不支持类似这样的“Hairpin转换”,但是已经有越来越多的NAT设备商开始加入对该转换的支持中来。一个需要考虑的现实问题:UDP在空闲状态下的超时当然,从应用的角度上来说,在完成打洞过程的同时,还有一些技术问题需要解决,如UDP在空闲状态下的超时问题。由于UDP转换协议提供的“洞”不是绝对可靠的,多数NAT设备内部都有一个UDP转换的空闲状态计时器,如果在一段时间内没有UDP数据通信,NAT设备会关掉由“打洞”过程打出来的“洞”。如果P2P应用程序希望“洞”的存活时间不受NAT网关的限制,就最好在穿越NAT以后设定一个穿越的有效期。对于有效期目前没有标准值,它与NAT设备内部的配置有关,某些设备上最短的只有20秒左右。在这个有效期内,即使没有P2P数据包需要传输,应用程序为了维持该“洞”可以正常工作,也必须向对方发送“打洞”心跳包。这个心跳包是需要双方应用程序都发送的,只有一方发送不会维持另一方的Session正常工作。除了频繁发送“打洞”心跳包以外,还有一个方法就是在当前的“洞”超时之前,P2P客户端双方重新“打洞”,丢弃原有的“洞”,这也不失为一个有效的方法。基于TCP协议的P2P打洞技术详细建立穿越NAT设备的P2P的TCP连接只比UDP复杂一点点,TCP协议的”“打洞”从协议层来看是与UDP的“打洞”过程非常相似的。尽管如此,基于TCP协议的打洞至今为止还没有被很好的理解,这也造成了的对其提供支持的NAT设备不是很多。在NAT设备支持的前提下,基于TCP的“打洞”技术实际上与基于UDP的“打洞”技术一样快捷、可靠。实际上,只要NAT设备支持的话,基于TCP的P2P技术的健壮性将比基于UDP技术的更强一些,因为TCP协议的状态机给出了一种标准的方法来精确的获取某个TCP session的生命期,而UDP协议则无法做到这一点。**套接字和TCP端口的重用实现基于TCP协议的P2P打洞过程中,最主要的问题不是来自于TCP协议,而是来自于应用程序的API接口。这是由于标准的伯克利(Berkeley)套接字的API是围绕着构建客户端/服务器程序而设计的,API允许TCP流套接字通过调用connect()函数来建立向外的连接,或者通过listen()和accept函数接受来自外部的连接,但是,API不提供类似UDP那样的,同一个端口既可以向外连接,又能够接受来自外部的连接。而且更糟的是,TCP的套接字通常仅允许建立1对1的响应,即应用程序在将一个套接字绑定到本地的一个端口以后,任何试图将第二个套接字绑定到该端口的操作都会失败。为了让TCP“打洞”能够顺利工作,我们需要使用一个本地的TCP端口来监听来自外部的TCP连接,同时建立多个向外的TCP连接。幸运的是,所有的主流操作系统都能够支持特殊的TCP套接字参数,通常叫做“SO_REUSEADDR”,该参数允许应用程序将多个套接字绑定到本地的一个地址二元组(只要所有要绑定的套接字都设置了SO_REUSEADDR参数即可)。BSD系统引入了SO_REUSEPORT参数,该参数用于区分端口重用还是地址重用,在这样的系统里面,上述所有的参数必须都设置才行。打开P2P的TCP流假定客户端A希望建立与B的TCP连接。我们像通常一样假定A和B已经与公网上的已知服务器建立了TCP连接。服务器记录下来每个接入的客户端的公网和内网的地址二元组,如同为UDP服务的时候一样。从协议层来看,TCP“打洞”与UDP“打洞”是几乎完全相同的过程:客户端A使用其与服务器的连接向服务器发送请求,要求服务器协助其连接客户端B;服务器将B的公网和内网的TCP地址的二元组信息返回给A,同时,服务器将A的公网和内网的地址二元组也发送给B;客户端A和B使用连接服务器的端口异步地发起向对方的公网、内网地址二元组的TCP连接,同时监听各自的本地TCP端口是否有外部的连接联入;A和B开始等待向外的连接是否成功,检查是否有新连接联入。如果向外的连接由于某种网络错误而失败,如:“连接被重置”或者“节点无法访问”,客户端只需要延迟一小段时间(例如延迟一秒钟),然后重新发起连接即可,延迟的时间和重复连接的次数可以由应用程序编写者来确定;TCP连接建立起来以后,客户端之间应该开始鉴权操作,确保目前联入的连接就是所希望的连接。如果鉴权失败,客户端将关闭连接,并且继续等待新的连接联入。客户端通常采用“先入为主”的策略,只接受第一个通过鉴权操作的客户端,然后将进入P2P通信过程不再继续等待是否有新的连接联入。TCP打洞:与UDP不同的是,因为使用UDP协议的每个客户端只需要一个套接字即可完成与服务器的通信,而TCP客户端必须处理多个套接字绑定到同一个本地TCP端口的问题,如图7所示。现在来看实际中常见的一种情景,A与B分别位于不同的NAT设备后面,如图5所示,并且假定图中的端口号是TCP协议的端口号,而不是UDP的端口号。图中向外的连接代表A和B向对方的内网地址二元组发起的连接,这些连接或许会失败或者无法连接到对方。如同使用UDP协议进行“打洞”操作遇到的问题一样,TCP的“打洞”操作也会遇到内网的IP与“伪”公网IP重复造成连接失败或者错误连接之类的问题。客户端向彼此公网地址二元组发起连接的操作,会使得各自的NAT设备打开新的“洞”允许A与B的TCP数据通过。如果NAT设备支持TCP“打洞”操作的话,一个在客户端之间的基于TCP协议的流通道就会自动建立起来。如果A向B发送的第一个SYN包发到了B的NAT设备,而B在此前没有向A发送SYN包,B的NAT设备会丢弃这个包,这会引起A的“连接失败”或“无法连接”问题。而此时,由于A已经向B发送过SYN包,B发往A的SYN包将被看作是由A发往B的包的回应的一部分,所以B发往A的SYN包会顺利地通过A的NAT设备,到达A,从而建立起A与B的P2P连接。从应用程序的角度来看TCP“打洞”从应用程序的角度来看,在进行TCP“打洞”的时候都发生了什么呢?假定A首先向B发出SYN包,该包发往B的公网地址二元组,并且被B的NAT设备丢弃,但是B发往A的公网地址二元组的SYN包则通过A的NAT到达了A,然后,会发生以下的两种结果中的一种,具体是哪一种取决于操作系统对TCP协议的实现:(1)A的TCP实现会发现收到的SYN包就是其发起连接并希望联入的B的SYN包,通俗一点来说就是“说曹操,曹操到”的意思,本来A要去找B,结果B自己找上门来了。A的TCP协议栈因此会把B作为A向B发起连接connect的一部分,并认为连接已经成功。程序A调用的异步connect()函数将成功返回,A的listen()等待从外部联入的函数将没有任何反映。此时,B联入A的操作在A程序的内部被理解为A联入B连接成功,并且A开始使用这个连接与B开始P2P通信。由于收到的SYN包中不包含A需要的ACK数据,因此,A的TCP将用SYN-ACK包回应B的公网地址二元组,并且将使用先前A发向B的SYN包一样的序列号。一旦B的TCP收到由A发来的SYN-ACK包,则把自己的ACK包发给A,然后两端建立起TCP连接。简单的说,第一种,就是即使A发往B的SYN包被B的NAT丢弃了,但是由于B发往A的包到达了A。结果是,A认为自己连接成功了,B也认为自己连接成功了,不管是谁成功了,总之连接是已经建立起来了。(2)另外一种结果是,A的TCP实现没有像(1)中所讲的那么“智能”,它没有发现现在联入的B就是自己希望联入的。就好比在机场接人,明明遇到了自己想要接的人却不认识,误认为是其他的人,安排别人给接走了,后来才知道是自己错过了机会,但是无论如何,人已经接到了任务已经完成了。然后,A通过常规的listen()函数和accept()函数得到与B的连接,而由A发起的向B的公网地址二元组的连接会以失败告终。尽管A向B的连接失败,A仍然得到了B发起的向A的连接,等效于A与B之间已经联通,不管中间过程如何,A与B已经连接起来了,结果是A和B的基于TCP协议的P2P连接已经建立起来了。第一种结果适用于基于BSD的操作系统对于TCP的实现,而第二种结果更加普遍一些,多数Linux和Windows系统都会按照第二种结果来处理。总结在IP地址极度短缺的今天,NAT几乎已经是无所不在的一项技术了,以至于现在任何一项新技术都不得不考虑和NAT的兼容。作为当下应用最广泛的技术之一,P2P技术也必然要面对NAT这个障碍。打洞技术看起来是一项近似乎蛮干的技术,却不失为一种有效的技术手段。在集中服务器的帮助下,P2P的双方利用端口预测的技术在NAT网关上打出通道,从而实现NAT穿越,解决了NAT对于P2P的阻隔,为P2P技术在网络中更广泛的推广作出了非常大的贡献。

March 17, 2019 · 1 min · jiezi

物联网高并发编程之P2P技术NAT详解

物联网高并发编程之P2P技术之NAT技术本时代由于 IPv6 的崛起建议各位看官先滑到文章最后看以下NAT现阶段的状况再决定要不要使用您宝贵的时间观看此片文章IPv4协议和NAT的由来今天,无数快乐的互联网用户在尽情享受Internet带来的乐趣。他们浏览新闻,搜索资料,下载软件,广交新朋,分享信息,甚至于足不出户获取一切日用所需。企业利用互联网发布信息,传递资料和订单,提供技术支持,完成日常办公。然而,Internet在给亿万用户带来便利的同时,自身却面临一个致命的问题:构建这个无所不能的Internet的基础IPv4协议已经不能再提供新的网络地址了。2011年2月3日中国农历新年, IANA对外宣布:IPv4地址空间最后5个地址块已经被分配给下属的5个地区委员会。2011年4月15日,亚太区委员会APNIC对外宣布,除了个别保留地址外,本区域所有的IPv4地址基本耗尽。一时之间,IPv4地址作为一种濒危资源身价陡增,各大网络公司出巨资收购剩余的空闲地址。其实,IPv4地址不足问题已不是新问题,早在20年以前,IPv4地址即将耗尽的问题就已经摆在Internet先驱们面前。这不禁让我们想去了解,是什么技术使这一危机延缓了尽20年。要找到问题的答案,让我们先来简略回顾一下IPv4协议。IPv4即网际网协议第4版——Internet Protocol Version 4的缩写。IPv4定义一个跨越异种网络互连的超级网,它为每个网际网的节点分配全球唯一IP地址。如果我们把Internet比作一个邮政系统,那么IP地址的作用就等同于包含城市、街区、门牌编号在内的完整地址。IPv4使用32bits整数表达一个地址,地址最大范围就是232 约为43亿。以IP创始时期可被联网的设备来看,这样的一个空间已经很大,很难被短时间用完。然而,事实远远超出人们的设想,计算机网络在此后的几十年里迅速壮大,网络终端数量呈爆炸性增长。更为糟糕的是,为了路由和管理方便,43亿的地址空间被按照不同前缀长度划分为A,B,C,D类地址网络和保留地址。其中,A类网络地址127段,每段包括主机地址约1678万个。B类网络地址16384段,每段包括65536个主机地址。IANA向超大型企业/组织分配A类网络地址,一次一段。向中型企业或教育机构分配B类网络地址,一次一段。这样一种分配策略使得IP地址浪费很严重,很多被分配出去的地址没有真实被利用,地址消耗很快。以至于二十世纪90年代初,网络专家们意识到,这样大手大脚下去,IPv4地址很快就要耗光了。于是,人们开始考虑IPv4的替代方案,同时采取一系列的措施来减缓IPv4地址的消耗。正是在这样一个背景之下,本期的主角闪亮登场,它就是网络地址转换——NAT。NAT是一项神奇的技术,说它神奇在于它的出现几乎使IPv4起死回生。在IPv4已经被认为行将结束历史使命之后近20年时间里,人们几乎忘了IPv4的地址空间即将耗尽这样一个事实——在新技术日新月异的时代,20年可算一段漫长的历史。更不用说,在NAT产生以后,网络终端的数量呈加速上升趋势,对IP地址的需求剧烈增加。此足见NAT技术之成功,影响之深远。说它神奇,更因为NAT给IP网络模型带来了深远影响,其身影遍布网络每个角落。根据一份最近的研究报告,70%的P2P用户位于NAT网关以内。因为P2P主要运行在终端用户的个人电脑之上,这个数字意味着大多数PC通过NAT网关连接到Internet。如果加上2G和3G方式联网的智能手机等移动终端,在NAT网关之后的用户远远超过这个比例。然而当我们求本溯源时却发现一个很奇怪的事实:NAT这一意义重大的技术,竟然没有公认的发明者。NAT第一个版本的RFC作者,只是整理归纳了已被广泛采用的技术。NAT的工作模型和特点NAT的概念模型NAT名字很准确,网络地址转换,就是替换IP报文头部的地址信息。NAT通常部署在一个组织的网络出口位置,通过将内部网络IP地址替换为出口的IP地址提供公网可达性和上层协议的连接能力。什么是内部网络IP地址?RFC1918规定了三个保留地址段落:10.0.0.0-10.255.255.255;172.16.0.0-172.31.255.255;192.168.0.0-192.168.255.255。这三个范围分别处于A,B,C类的地址段,不向特定的用户分配,被IANA作为私有地址保留。这些地址可以在任何组织或企业内部使用,和其他Internet地址的区别就是,仅能在内部使用,不能作为全球路由地址。这就是说,出了组织的管理范围这些地址就不再有意义,无论是作为源地址,还是目的地址。对于一个封闭的组织,如果其网络不连接到Internet,就可以使用这些地址而不用向IANA提出申请,而在内部的路由管理和报文传递方式与其他网络没有差异。对于有Internet访问需求而内部又使用私有地址的网络,就要在组织的出口位置部署NAT网关,在报文离开私网进入Internet时,将源IP替换为公网地址,通常是出口设备的接口地址。一个对外的访问请求在到达目标以后,表现为由本组织出口设备发起,因此被请求的服务端可将响应由Internet发回出口网关。出口网关再将目的地址替换为私网的源主机地址,发回内部。这样一次由私网主机向公网服务端的请求和响应就在通信两端均无感知的情况下完成了。依据这种模型,数量庞大的内网主机就不再需要公有IP地址了。NAT转换过程示意图实际过程远比这个复杂,NAT处理报文的几个关键特点:**网络被分为私网和公网两个部分,NAT网关设置在私网到公网的路由出口位置,双向流量必须都要经过NAT网关;网络访问只能先由私网侧发起,公网无法主动访问私网主机; NAT网关在两个访问方向上完成两次地址的转换或翻译,出方向做源信息替换,入方向做目的信息替换; NAT网关的存在对通信双方是保持透明的; NAT网关为了实现双向翻译的功能,需要维护一张关联表,把会话的信息保存下来。随着后面对NAT的深入描述,会发现这些特点是鲜明的,但又不是绝对的。其中第二个特点打破了IP协议架构中所有节点在通讯中的对等地位,这是NAT最大的弊端,为对等通讯带来了诸多问题,当然相应的克服手段也应运而生。事实上,第四点是NAT致力于达到的目标,但在很多情况下,NAT并没有做到,因为除了IP首部,上层通信协议经常在内部携带IP地址信息。这些我们稍后解释。一对一的NAT如果一个内部主机唯一占用一个公网IP,这种方式被称为一对一模型。此种方式下,转换上层协议就是不必要的,因为一个公网IP就能唯一对应一个内部主机。显然,这种方式对节约公网IP没有太大意义,主要是为了实现一些特殊的组网需求。比如用户希望隐藏内部主机的真实IP,或者实现两个IP地址重叠网络的通信。一对多的NATNAT最典型的应用场景就如同图片“NAT转换过程示意图”描述的,一个组织网络,在出口位置部署NAT网关,所有对公网的访问表现为一台主机。这就是所谓的一对多模型。这种方式下,出口设备只占用一个由Internet服务提供商分配的公网IP地址。面对私网内部数量庞大的主机,如果NAT只进行IP地址的简单替换,就会产生一个问题:当有多个内部主机去访问同一个服务器时,从返回的信息不足以区分响应应该转发到哪个内部主机。此时,需要NAT设备根据传输层信息或其他上层协议去区分不同的会话,并且可能要对上层协议的标识进行转换,比如TCP或UDP端口号。这样NAT网关就可以将不同的内部连接访问映射到同一公网IP的不同传输层端口,通过这种方式实现公网IP的复用和解复用。这种方式也被称为端口转换PAT、NAPT或IP伪装,但更多时候直接被称为NAT,因为它是最典型的一种应用模式。按照NAT端口映射方式分类在一对多模型中,按照端口转换的工作方式不同,又可以进行更进一步的划分。为描述方便,以下将IP和端口标记为(nAddr:nPort),其中n代表主机或NAT网关的不同角色。全锥形NAT其特点为:一旦内部主机端口对(iAddr:iPort)被NAT网关映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);任何一个外部主机发送到(eAddr:ePort)的报文将会被转换后发到(iAddr:iPort)。限制锥形NAT其特点为:一旦内部主机端口对(iAddr:iPort)被映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);只有 (iAddr:iPort)向特定的外部主机hAddr发送过数据,主机hAddr从任意端口发送到(eAddr:ePort)的报文将会被转发到(iAddr:iPort)。端口限制锥形NAT其特点为:一旦内部主机端口对(iAddr:iPort)被映射到(eAddr:ePort),所有后续的(iAddr:iPort)报文都会被转换为(eAddr:ePort);只有(iAddr:iPort)向特定的外部主机端口对(hAddr:hPort)发送过数据,由 (hAddr:hPort)发送到(eAddr:ePort)的报文将会被转发到(iAddr:iPort)。对称型NAT其特点为:NAT网关会把内部主机“地址端口对”和外部主机“地址端口对”完全相同的报文看作一个连接,在网关上创建一个公网“地址端口对”映射进行转换,只有收到报文的外部主机从对应的端口对发送回应的报文,才能被转换。即使内部主机使用之前用过的地址端口对去连接不同外部主机(或端口)时,NAT网关也会建立新的映射关系。事实上,这些术语的引入是很多混淆的起源。现实中的很多NAT设备是将这些转换方式混合在一起工作的,而不单单使用一种,所以这些术语只适合描述一种工作方式,而不是一个设备。比如,很多NAT设备对内部发出的连接使用对称型NAT方式,而同时支持静态的端口映射,后者可以被看作是全锥型NAT方式。而有些情况下,NAT设备的一个公网地址和端口可以同时映射到内部几个服务器上以实现负载分担,比如一个对外提供WEB服务器的站点可能是有成百上千个服务器在提供HTTP服务,但是对外却表现为一个或少数几个IP地址。NAT的限制与解决方案IP端到端服务模型IP协议的一个重要贡献是把世界变得平等。在理论上,具有IP地址的每个站点在协议层面有相当的获取服务和提供服务的能力,不同的IP地址之间没有差异。人们熟知的服务器和客户机实际是在应用协议层上的角色区分,而在网络层和传输层没有差异。一个具有IP地址的主机既可以是客户机,也可以是服务器,大部分情况下,既是客户机,也是服务器。端到端对等看起来是很平常的事情,而意义并不寻常。但在以往的技术中,很多协议体系下的网络限定了终端的能力。正是IP的这个开放性,使得TCP/IP协议族可以提供丰富的功能,为应用实现提供了广阔平台。因为所有的IP主机都可以服务器的形式出现,所以通讯设计可以更加灵活。使用UNIX/LINUX的系统充分利用了这个特性,使得任何一个主机都可以建立自己的HTTP、SMTP、POP3、DNS、DHCP等服务。与此同时,很多应用也是把客户端和服务器的角色组合起来完成功能。例如在VoIP应用中,用户端向注册服务器登录自己的IP地址和端口信息过程中,主机是客户端;而在呼叫到达时,呼叫处理服务器向用户端发送呼叫请求时,用户端实际工作在服务器模式下。在语音媒体流信道建立过程后,通讯双向发送语音数据,发送端是客户模式,接收端是服务器模式。而在P2P的应用中,一个用户的主机既为下载的客户,同时也向其他客户提供数据,是一种C/S混合的模型。上层应用之所以能这样设计,是因为IP协议栈定义了这样的能力。试想一下,如果IP提供的能力不对等,那么每个通信会话都只能是单方向发起的,这会极大限制通信的能力。细心的读者会发现,前面介绍NAT的一个特性正是这样一种限制。没错,NAT最大的弊端正在于此——破坏了IP端到端通信的能力。NAT的弊端NAT在解决IPv4地址短缺问题上,并非没有副作用,其实存在很多问题。首先,NAT使IP会话的保持时效变短。因为一个会话建立后会在NAT设备上建立一个关联表,在会话静默的这段时间,NAT网关会进行老化操作。这是任何一个NAT网关必须做的事情,因为IP和端口资源有限,通信的需求无限,所以必须在会话结束后回收资源。通常TCP会话通过协商的方式主动关闭连接,NAT网关可以跟踪这些报文,但总是存在例外的情况,要依赖自己的定时器去回收资源。而基于UDP的通信协议很难确定何时通信结束,所以NAT网关主要依赖超时机制回收外部端口。通过定时器老化回收会带来一个问题,如果应用需要维持连接的时间大于NAT网关的设置,通信就会意外中断。因为网关回收相关转换表资源以后,新的数据到达时就找不到相关的转换信息,必须建立新的连接。当这个新数据是由公网侧向私网侧发送时,就会发生无法触发新连接建立,也不能通知到私网侧的主机去重建连接的情况。这时候通信就会中断,不能自动恢复。即使新数据是从私网侧发向公网侧,因为重建的会话表往往使用不同于之前的公网IP和端口地址,公网侧主机也无法对应到之前的通信上,导致用户可感知的连接中断。NAT网关要把回收空闲连接的时间设置到不发生持续的资源流失,又维持大部分连接不被意外中断,是一件比较有难度的事情。在NAT已经普及化的时代,很多应用协议的设计者已经考虑到了这种情况,所以一般会设置一个连接保活的机制,即在一段时间没有数据需要发送时,主动发送一个NAT能感知到而又没有实际数据的保活消息,这么做的主要目的就是重置NAT的会话定时器。其次,NAT在实现上将多个内部主机发出的连接复用到一个IP上,这就使依赖IP进行主机跟踪的机制都失效了。如网络管理中需要的基于网络流量分析的应用无法跟踪到终端用户与流量的具体行为的关系。基于用户行为的日志分析也变得困难,因为一个IP被很多用户共享,如果存在恶意的用户行为,很难定位到发起连接的那个主机。即便有一些机制提供了在NAT网关上进行连接跟踪的方法,但是把这种变换关系接续起来也困难重重。基于IP的用户授权不再可靠,因为拥有一个IP的不等于一个用户或主机。一个服务器也不能简单把同一IP的访问视作同一主机发起的,不能进行关联。有些服务器设置有连接限制,同一时刻只接纳来自一个IP的有限访问(有时是仅一个访问),这会造成不同用户之间的服务抢占和排队。有时服务器端这样做是出于DOS攻击防护的考虑,因为一个用户正常情况下不应该建立大量的连接请求,过度使用服务资源被理解为攻击行为。但是这在NAT存在时不能简单按照连接数判断。总之,因为NAT隐蔽了通信的一端,把简单的事情复杂化了。我们来深入理解NAT一下对IP端到端模型的破坏力。NAT通过修改IP首部的信息变换通信的地址。但是在这个转换过程中只能基于一个会话单位。当一个应用需要保持多个双向连接时,麻烦就很大。NAT不能理解多个会话之间的关联性,无法保证转换符合应用需要的规则。当NAT网关拥有多个公有IP地址时,一组关联会话可能被分配到不同的公网地址,这通常是服务器端无法接受的。更为严重的是,当公网侧的主机要主动向私网侧发送数据时,NAT网关没有转换这个连接需要的关联表,这个数据包无法到达私网侧的主机。这些反方向发送数据的连接总有应用协议的约定或在初始建立的会话中进行过协商。但是因为NAT工作在网络层和传输层,无法理解应用层协议的行为,对这些信息是无知的。NAT希望自己对通信双方是透明的,但是在这些情况下这是一种奢望。此外,NAT工作机制依赖于修改IP包头的信息,这会妨碍一些安全协议的工作。因为NAT篡改了IP地址、传输层端口号和校验和,这会导致认证协议彻底不能工作,因为认证目的就是要保证这些信息在传输过程中没有变化。对于一些隧道协议,NAT的存在也导致了额外的问题,因为隧道协议通常用外层地址标识隧道实体,穿过NAT的隧道会有IP复用关系,在另一端需要小心处理。ICMP是一种网络控制协议,它的工作原理也是在两个主机之间传递差错和控制消息,因为IP的对应关系被重新映射,ICMP也要进行复用和解复用处理,很多情况下因为ICMP报文载荷无法提供足够的信息,解复用会失败。IP分片机制是在信息源端或网络路径上,需要发送的IP报文尺寸大于路径实际能承载最大尺寸时,IP协议层会将一个报文分成多个片断发送,然后在接收端重组这些片断恢复原始报文。IP这样的分片机制会导致传输层的信息只包括在第一个分片中,NAT难以识别后续分片与关联表的对应关系,因此需要特殊处理。NAT穿越技术前面解释了NAT的弊端,为了解决IP端到端应用在NAT环境下遇到的问题,网络协议的设计者们创造了各种武器来进行应对。但遗憾的是,这里每一种方法都不完美,还需要在内部主机、应用程序或者NAT网关上增加额外的处理。应用层网关应用层网关(ALG)是解决NAT对应用层协议无感知的一个最常用方法,已经被NAT设备厂商广泛采用,成为NAT设备的一个必需功能。因为NAT不感知应用协议,所以有必要额外为每个应用协议定制协议分析功能,这样NAT网关就能理解并支持特定的协议。ALG与NAT形成互动关系,在一个NAT网关检测到新的连接请求时,需要判断是否为已知的应用类型,这通常是基于连接的传输层端口信息来识别的。在识别为已知应用时,再调用相应功能对报文的深层内容进行检查,当发现任何形式表达的IP地址和端口时,将会把这些信息同步转换,并且为这个新连接创建一个附加的转换表项。这样,当报文到达公网侧的目的主机时,应用层协议中携带的信息就是NAT网关提供的地址和端口。一旦公网侧主机开始发送数据或建立连接到此端口,NAT网关就可以根据关联表信息进行转换,再把数据转发到私网侧的主机。很多应用层协议实现不限于一个初始连接(通常为信令或控制通道)加一个数据连接,可能是一个初始连接对应很多后续的新连接。比较特别的协议,在一次协商中会产生一组相关连接,比如RTP/RTCP协议规定,一个RTP通道建立后占用连续的两个端口,一个服务于数据,另一个服务于控制消息。此时,就需要ALG分配连续的端口为应用服务。ALG能成功解决大部分协议的NAT穿越需求,但是这个方法也有很大的限制。因为应用协议的数量非常多而且在不断发展变化之中,添加到设备中的ALG功能都是为特定协议的特定规范版本而开发的,协议的创新和演进要求NAT设备制造商必须跟踪这些协议的最近标准,同时兼容旧标准。尽管有如Linux这种开放平台允许动态加载新的ALG特性,但是管理成本仍然很高,网络维护人员也不能随时了解用户都需要什么应用。因此为每个应用协议开发ALG代码并跟踪最新标准是不可行的,ALG只能解决用户最常用的需求。此外,出于安全性需要,有些应用类型报文从源端发出就已经加密,这种报文在网络中间无法进行分析,所以ALG无能为力。探针技术STUN和TURN所谓探针技术,是通过在所有参与通信的实体上安装探测插件,以检测网络中是否存在NAT网关,并对不同NAT模型实施不同穿越方法的一种技术。STUN服务器被部署在公网上,用于接收来自通信实体的探测请求,服务器会记录收到请求的报文地址和端口,并填写到回送的响应报文中。客户端根据接收到的响应消息中记录的地址和端口与本地选择的地址和端口进行比较,就能识别出是否存在NAT网关。如果存在NAT网关,客户端会使用之前的地址和端口向服务器的另外一个IP发起请求,重复前面的探测。然后再比较两次响应返回的结果判断出NAT工作的模式。由前述的一对多转换模型得知,除对称型NAT以外的模型,NAT网关对内部主机地址端口的映射都是相对固定的,所以比较容易实现NAT穿越。而对称型NAT为每个连接提供一个映射,使得转换后的公网地址和端口对不可预测。此时TURN可以与STUN绑定提供穿越NAT的服务,即在公网服务器上提供一个“地址端口对”,所有此“地址端口对”接收到的数据会经由探测建立的连接转发到内网主机上。TURN分配的这个映射“地址端口对”会通过STUN响应发给内部主机,后者将此信息放入建立连接的信令中通知通信的对端。这种探针技术是一种通用方法,不用在NAT设备上为每种应用协议开发功能,相对于ALG方式有一定普遍性。但是TURN中继服务会成为通信瓶颈。而且在客户端中增加探针功能要求每个应用都要增加代码才能支持。中间件技术这也是一种通过开发通用方法解决NAT穿越问题的努力。与前者不同之处是,NAT网关是这一解决方案的参与者。与ALG的不同在于,客户端会参与网关公网映射信息的维护,此时NAT网关只要理解客户端的请求并按照要求去分配转换表,不需要自己去分析客户端的应用层数据。其中UPnP就是这样一种方法。UPnP中文全称为通用即插即用,是一个通用的网络终端与网关的通信协议,具备信息发布和管理控制的能力。其中,网关映射请求可以为客户动态添加映射表项。此时,NAT不再需要理解应用层携带的信息,只转换IP地址和端口信息。而客户端通过控制消息或信令发到公网侧的信息中,直接携带公网映射的IP地址和端口,接收端可以按照此信息建立数据连接。NAT网关在收到数据或连接请求时,按照UPnP建立的表项只转换地址和端口信息,不关心内容,再将数据转发到内网。这种方案需要网关、内部主机和应用程序都支持UPnP技术,且组网允许内部主机和NAT网关之间可以直接交换UPnP信令才能实施。中继代理技术准确说它不是NAT穿越技术,而是NAT旁路技术。简单说,就是在NAT网关所在的位置旁边放置一个应用服务器,这个服务器在内部网络和外部公网分别有自己的网络连接。客户端特定的应用产生网络请求时,将定向发送到应用代理服务器。应用代理服务器根据代理协议解析客户端的请求,再从服务器的公网侧发起一个新的请求,把客户端请求的内容中继到外部网络上,返回的相应反方向中继。这项技术和ALG有很大的相似性,它要求为每个应用类型部署中继代理业务,中间服务器要理解这些请求。特定协议的自穿越技术在所有方法中最复杂也最可靠的就是自己解决自己的问题。比如IKE和IPsec技术,在设计时就考虑了到如何穿越NAT的问题。因为这个协议是一个自加密的协议并且具有报文防修改的鉴别能力,其他通用方法爱莫能助。因为实际应用的NAT网关基本都是NAPT方式,所有通过传输层协议承载的报文可以顺利通过NAT。IKE和IPsec采用的方案就是用UDP在报文外面再加一层封装,而内部的报文就不再受到影响。IKE中还专门增加了NAT网关是否存在的检查能力以及绕开NAT网关检测IKE协议的方法。NAT的应用和实现NAT的应用NAT在当代Internet中被广泛采用,小至家庭网关,大到企业广域网出口甚至运营商业务网络出口。其实NAT在用户身边随处可见,一般家庭宽带接入的ADSL Modem和SOHO路由器都内置了NAT功能,WindowsXP支持网络连接共享,一个用户连接到公网可能会经过多层NAT而对此一无所知。很多企业也为节约IP费用采用NAT接入Internet,但是相比家庭用户有更复杂的需求。NAT多实例应用在VPN网络中,多实例路由意味着一个物理拓扑上承载多个逻辑拓扑,网络终端被分配到相互隔离的逻辑拓扑中,彼此之间没有路由的通路。但在访问Internet或者一些关键服务器资源时,被隔离的网络之间又存在共享资源的需求。NAT的多实例实现就是跨越这种逻辑拓扑的方法,把一个空间的网络地址映射到另一个空间。NAT的高可靠性组网提高网络可靠性是一个广泛的需求,NAT作为私网到公网的关键路径自然也需要高可靠性。当一个设备提供多个公网接口时,在多接口上部署NAT可以提供更高带宽和多ISP就近访问的能力。但是,当部署多个出口时,访问的流量可能会从不匹配的接口返回,这就要求NAT方案有良好的路由规划和部署合适的策略保证这种流量能够正确处理。在多个物理设备承担NAT功能时,不同设备之间的信息备份和流量分担也是一个组网难题。同时转换源和目的地址的应用前面我们介绍的所有NAT应用中,由内网向外网访问过程中,都是将源地址进行转换而目的地址保持不变,报文反方向进入时则处理目的地址。但有一些特殊应用需要在由内向外的IP通路上,替换目的IP地址。通常,这种应用会同时替换源地址和目的地址,在经过NAT网关以后完成两次地址转换。当两个均规划使用私属IP地址范围的网络进行合并时,终端用户都不想调整自己的IP地址方案,又希望开放一些网络资源给彼此访问。这时就可以通过NAT的两次地址转换来解决路由和地址规划无法解决的问题。NAT的设备实现NAT作为一个IP层业务特性,在产品实现中与防火墙、会话管理等特性有紧密联系,这是因为NAT判断一个进入设备的报文是否需要NAT处理,判断报文是否为一个新的连接,都需要通过匹配访问控制列表规则和查询会话关联表进行判断。为了满足不同应用场景的NAT需求, NAT的管理界面可提供用户多种配置策略。按照NAT的具体工作方式,又可以做如下分类。静态一对一地址映射这种工作方式下,NAT把一个私网地址和一个公网地址做静态关联,在从内而外的方向,将源IP匹配的私网IP替换为公网IP,反方向则将目的IP匹配公网IP的报文替换为私网IP。网络层以上的部分不进行替换处理,只修正校验和。静态多对多地址映射这种方式与上一种类似,只是把一段私网地址映射到一段公网地址。工作机制与前述的方式没有差别,只是简化配置工作量。动态端口映射这是最基本的工作方式,即前面多次介绍的将一段内网地址动态翻译为一个或多个公网IP,同时对传输层端口或其他上层协议信息进行转换,以实现IP复用。对由内而外的报文,替换源地址和端口,反向报文替换目的地址和端口。仅以连接公网的接口IP作为NAT转换的公网地址时,这种配置最简化,又被称为EasyIP。当以一段公网IP地址作为NAT转换地址时,需要配置一个地址池,NAT会自动在地址池中选择使用公网IP。动态地址映射(no-pat)这是介于静态多对多地址映射和动态端口映射方式之间的一种工作机制。当有一个私网向公网侧访问到达NAT网关时,NAT网关会检查这个私网IP是否已经有关联的公网IP映射。如果已经存在,则按照转换表直接替换IP,不修改上层协议。如果不存在关联表项,则在空闲的公网IP池中占用一个IP,并写入关联表中,以后按照这个关联关系进行地址转换。当这个私网主机发起的所有对外访问均关闭或超时后,回收公网IP。这种方式可以理解为一组内网主机抢占式地共享一个公网IP地址池。当公网IP地址池用完以后,新连接将无法建立。静态端口映射通过静态配置,把一个固定的私网IP地址和端口关联到一个公网地址和端口上。这种方式等同于前面介绍过的全锥模式,但是不需要内网主机首先发出报文。这种方式适用于在NAT网关上把一个知名服务(如HTTP)映射到一个内部主机上,也称为port forwarding。应用层网关(ALG)在所有NAT产品实现中,ALG是一个必需的功能组件。但在不同实现中,有些产品可以动态加载不同的ALG模块,有些产品可以提供ALG开关控制,有些则不提供任何用户接口。ALG解析上层应用协议的内容,并且根据需要修改IP和端口相关信息,创建和维护附加的关联表项。NAT转换关联表无论哪一种NAT工作方式,都要用到地址转换关联表,在不同产品的实现中,这个关联表的存储结构和在IP转发中调用的方式有很大不同。关联表中会记录源IP、目的IP、连接协议类型、传输层源端口、目的端口,以及转换后的源IP、源端口,目的IP、目的端口信息,这里的源和目的都是对应于从内网到外网的访问方向。依据NAT具体工作方式,这些信息可能全部填充,也可能部分填充。例如只按照IP做静态映射的方式,就不需要填入任何端口相关信息;对于静态端口映射,则只填入源相关的内容,而目的端的信息为空。后IPv4时代的NATNAT是为延缓IPv4地址耗尽而推出的技术。毫无疑问,它已经出色完成了自己的历史使命,IPv4比预期走得更远。作为继任者的IPv6吸取了IPv4的教训,被赋予充足地址空间的同时在各个方面做了优化——安全、高效、简洁。但是IPv6无法平滑地取代IPv4,导致IP升级步伐缓慢。尽管网络协议的分层设计很清晰,大量应用层协议和互联网软件中仍内嵌了IPv4地址的处理,要Internet全网升级到IPv6,必须先完成应用的改造。因为NAT和它的穿越技术结合能够满足大部分用户的需求,所以IPv6时代被不断推迟。随着IPv4地址的濒临耗尽,再经济的模式也无以为继,IPv4必须退出历史舞台。人们自然会认为,NAT作为IPv4的超级补丁技术使命已经完结。实际情况是,IPv4向IPv6过渡的阶段,NAT仍然是一项必不可少的技术手段。因为Internet无法在一日之内完成全网升级,必然是局部升级,逐渐替换。在两套协议并存的时期,用户和服务资源分布在不同网络之间,跨网访问的需求必须得到满足。这正是NAT所擅长的领域,地址替换,因此NAT-PT应运而生。由于IPv4和IPv6之间的差异,NAT要做的事比以往更复杂,有更多的限制和细节。此外,IETF也在制定纯IPv6网络使用的NAT规范。虽然人们还看不到这种应用的强烈需求,但是NAT仍有其独特的作用,比如隐藏内部网络的地址,实现重叠地址网络的合并等。毫不夸张地说,正是有了NAT,以IPv4为基础的Internet才能容纳数十亿的用户终端,成就今日之辉煌。IPv4已至日暮西山,IPv6的黎明尚未来临,Internet比任何时刻都更依赖NAT这项过渡技术。NAT的历史再次证明,翻天覆地的划时代进步不一定有市场,抱残守缺的修修补补未必不会成功。在世代更替之时让我们走近NAT,领略IP领域更多细微但不高深的知识,理解NAT就是理解变换万千的应用世界。

March 17, 2019 · 1 min · jiezi

PHP中的pack和unpack函数

转载请注明文章出处:https://tlanyan.me/php-pack-a…PHP有两个重要的冷门函数:pack和unpack。在网络编程,读写图像文件等场景,这两个函数几乎必不可少。鉴于文件读写/网络编程,或者说字节流处理的重要性,掌握这两个函数是迈向高级PHP编程的基础。本文先介绍字节和字符的区别,说明两个函数存在的必要性和重要性。然后介绍基本用法和使用场景,让读者对其有大体了解,为实际使用中奠定基础。字节和字符PHP的优势是简单易用,熟练运用 字符串 和 数组 相关函数就能抗住一般的需求。日常工作中多用到字符串,所以PHP开发对字符都比较熟悉,稍微资深点基本能也能弄清字符编码。但字符的伴生概念:字节,不少PHP开发并不知晓/熟悉。这不怪他们。PHP世界里极少出现“字节(流)”的概念:没有byte关键字(当然也没有char),官方文档也没提字节;没有原生的数组支持(常用的array其实是hashtable);当然字符串(string)能表达其他语言中的字节数组(Byte Array, byte[])。字节和字符有什么联系和区别呢?简单来说字节是计算机存储和操作的最小单位,字符是人们阅读的最小单位;字节是存储(物理)概念,字符是逻辑概念;字节代表数据(内涵和本质),字符代表其含义;字符由字节组成。举几个例子说明两者区别:“中国”包含2个字符,GBK编码表示需要4个字节,UTF-8编码需要6个字节;数字“1234567890”,包含10个字符,用int32类型表示只需4个字节;下面的图片占用42582个字节,用字符表示是“我老婆”,只占用3个字符:再举一个常用的例子说明字符和字节的区别。开发中我们常用md5算法获取数据的哈希值,算法返回一个128位(bit)的数据(16个字节)。为方便查看其值,人们约定成俗地用十六进制表示,结果就是我们熟知的32位长度的字符串(不区分大小写)。32长度字符串不是md5算法的必然结果,16字节数据才是其本质。如果你愿意,可以用一个小于2^128的数字表示哈希结果,也可以将16字节base64编码后作为其结果。所以常用的32位哈希值与md5返回的16字节关系为:一个是字符表示,另一个则是其本质(字符数组)(PHP的md5函数第二个参数值为true便可得到16字节数据,或hash函数第三个参数为true)。相关概念还有字节序、字符编码等,本文不做展开。感兴趣的读者可参考本人之前的博客“文件和字符编码”或相关材料。引言PHP中专门处理字符串的函数有几十个,加上正则、时间等函数,字符串处理的函数不下百个。相比之下字节处理门庭冷落,相关函数寥寥无几。除了常用的ord/chr,哈希加密函数返回的原始字节、openssl库的openssl_random_pseudo_bytes等函数真正处理或返回 字节外,最重要的两个字节处理函数是pack和unpack。本节从问题引出pack函数的使用。问题考虑一个简单的问题:宇宙的终极答案42在内存中是如何表示的(或者说怎么获取其字节数组)?因为42是一个整数,根据硬件不同,其占用字节大小可能为1, 2, 4, 8等。这里我们限定一个整数占用4个字节,于是问题的等价表述为:怎样将一个整数转换成字节数组(本机序,4个字节)?分析因为是多字节,所以要考虑字节序的问题。42不超过255,只占用一个字节,故而其他三个字节都是0。据此得到结论:如果是大端序(低位字节存放在地址高位),四个字节分别是:0 0 0 42;如果是小端序,结果则是:42 0 0 0。那怎么知道机器的字节序呢?PHP没有提供相关功能,也不能像C语言直接取地址访问字节数据。无所不能的PHP该怎么搞定字节序,或者说完成数据向字节的转换?方案PHP应用层面,数据向字节(数组)的转换是pack的专场,字节(数组)向数据的转换则是unpack的专场。除这两个函数,字节数组(或二进制数据)向数据的转换几无可能(如果有请不吝指教)。现在我们用pack函数获取42在内存中的字节数组。相关代码如下:function intToBytes(int $num) : string { return pack(“l”, $num);}function outputBytes(string $bytes) { echo “bytes: “; for ($i = 0; $i &lt; strlen($bytes); ++ $i) { echo ord($bytes[$i]), " “; } echo PHP_EOL;}outputBytes(intToBytes(42));// 程序输出:bytes: 42 0 0 0本人计算机用的英特尔的CPU,x86架构是小端序,所以程序输出符合预期。延伸一下,怎么判断机器的字节序?有了pack函数,答案非常简单:function bigEndian() : bool { $data = 0x1200; $bytes = pack(“s”, $data); return ord($bytes[0]) === 0x12;}调用函数便返回本机是否大端序。上述是pack函数简单的使用场景,接下来分别介绍pack和unpack函数。pack和unpackpack函数pack是“打包/封包”的意思。如其名,pack函数的工作是将数据按照格式打包成字节数组。函数原型为:pack ( string $format [, mixed $… ] ) : string形式上与printf系列函数相同:第一个参数是格式字符串,其余参数是要格式化的参数。不同之处在于pack函数的格式中不能出现元字符和量词外的其他字符,所以不需要%符号。上文的例子中使用了"l"和"s"两个格式化元字符,pack函数的元字符主要分为三类:字符串:a、A等;将数据转成字符串,功能上与sprintf类似,例如整数32转换成字符串"32”;字节:h和H;对字节进行16进制编码,区别在于低位还是高位在前,功能上与dechex等函数类似;char/short/int/long/float/double六种基本类型:c/s/i/l等;将数据转换成对应类型的字节数组,除char类型外(暂)没有其他函数可替代;注意:char和a/A等的区别是a/A等输入为字符(串),而’s/S’的输入要求是小于256的整数,输入字符会得到0。量词比较简单:数字和"“两种。例如"i2"表示将两个参数按照整数转换,“c"表示后续都按照char类型转换。unpackunpack是pack的反向操作:将字节数组解析成有意义的数据。其函数原型为:unpack ( string $format , string $data [, int $offset = 0 ] ) : arrayunpack函数需要注意的是第一个参数和返回值。返回值好理解,pack函数相当于将除格式化参数外的参数数组(想象成call_user_func_array的参数)变成一个字节数组;unpack做相反的事情:释放数据,得到输入时的参数数组。返回一个数组,其键分别是什么呢?这便是格式化参数($format)在pack和unpack的不同之处:unpack应该对释放出来的数据命名,用”/“分隔各组数据。由于格式化参数允许有非元字符和量词外的字符,为了区分数据,不同数据间的”/“分隔符必不可少。一个例子:$bytes = pack(“iaa*”, 42, “:”, “The answer to life, the universe and everything”);outputBytes($bytes);$result = unpack(“inumber/acolon/aword”, $bytes);print_r($result);// 程序输出:bytes: 42 0 0 0 58 84 104 101 32 97 110 115 119 101 114 32 116 111 32 108 105 102 101 44 32 116 104 101 32 117 110 105 118 101 114 115 101 32 97 110 100 32 101 118 101 114 121 116 104 105 110 103Array( [num] =&gt; 42 [colon] =&gt; : [word] =&gt; The answer to life, the universe and everything)如果不对释放出来的数据命名会怎么样?例如上例中unpack的格式化参数为:“i/a/a",结果是什么呢?其结果为:Array( [1] => The answer to life, the universe and everything)为何?官方文档上如是说:Caution If you do not name an element, numeric indices starting from 1 are used. Be aware that if you have more than one unnamed element, some data is overwritten because the numbering restarts from 1 for each element.翻译过来就是:如果你不对数据命名,默认的1, 2, 3…就用来当作键值。如果有多组数据,每组都用同样的下标,会导致数据覆盖。所以能理解 “i/a/a*” 为何只剩最后一组数据了吧?应用场景读取图像、word/excel文件,解析binlog、二进制ip数据库文件等场合,pack和unpack几乎必不可少。本文举例说一下pack和unpack在网络编程时协议解析的用途。假设我们的tcp包格式为:前四个字节表示包大小,其余字节为数据内容。于是客户(发送)端的send函数可以长这样:public function send($data) { // 这里假设$data已经做了序列化、加密等操作,是字节数组 // 计算报文长度,封装报文 $len = strlen($data); $header = pack(“L”, $len); // 转换成网络(大端)序 $header = xxx // 封包 $binary = $header . $data; // 调用fwrite/socket_send等将数据写入内核缓冲区 …}服务(接收)端根据协议解析接收到的数据流:public function decodable($session, $buffer) { $dataLen = strlen($buffer); // 非法数据包 if ($dataLen &lt; 4) { // 关闭连接、记录ip等 …. return NOT_OK; } // 获取前四个字节 $header = substr($buffer, 0, 4); // 转换成主机序 $header = xxx // 解析数据长度 $len = unpack(“L”, $header); // 单个报文不能超过8M,例如限制上传的图像大小 if ($len &gt; 8 * 1024 * 1024) { // 关闭连接等 return NOT_OK; } // 检查数据包是否满足协议要求 if ($dataLen - 4 &gt;= $len) { return OK; } // 数据未全部到达,继续等待 return NEED_DATA;}通过pack和unpack,我们顺利的处理报文协议和二进制字节流的发送和解析。如果你用\n作为报文分隔符,pack和unpack也许用不到。但在网络通讯中直接传递字符毕竟少数(相当于明文传送),大多数情况下的二进制数据流的解析还是要靠pack和unpack。总结除分配内存,最重要的系统调用莫过于文件读写和网络连接,而两者的本质操作对象都是字节流。pack和unpack为PHP提供了底层字节操作的能力,在二进制数据处理中十分有用。有志于跳出web编程的PHP开发应该都要掌握这两个函数。参考文件和字符编码PHP Manual: packPHP Manual: unpackHandling binary data in PHP with pack() and unpack()PHP: 深入pack/unpack ...

February 24, 2019 · 2 min · jiezi

VRRP虚IP漂移

简介VRRP 是 Virtual Router Redundancy Protocol 的简称,即 虚拟路由冗余协议 。原文地址:https://linux-network-programming.readthedocs.io QQ交流群:Linux网络编程,群号:183196643欢迎关注我们的公众号:小菜学编程 (coding-fan)VRRP 最早被设计来解决网关的高可用问题:我们知道,计算机进行网络通讯时,需要网关来传输网络报文。 每台机器只能配置一个网关地址,这时网关的可靠性就非常重要了。 如果网关不幸故障了,那么使用该网关的所有机器都将受影响——断网了!解决网关单点问题的思路非常直观——部署一个备用网关,在主网关故障时切换过去。然而,由于机器只能配置一个网关地址,因此每次切换网关都需要修改该配置。 这个解决方案没能做到自动化,并不优雅。这时, VRRP 应运而生!接下来,以一个简单的例子介绍 VRRP 是如何工作的:事情是这样的。这个网络部署了两台 路由 进行互备,本网络内其他机器以这两台路由为网关进行网络通讯。 两台路由的 IP 地址分别是: 192.168.1.1 以及 192.168.1.2 。 但路由并不直接通过这些地址提供转发服务,而是使用一个 虚拟地址 192.168.1.253 。 其他计算机,如 192.168.1.3 将网关地址配置为 192.168.1.253 。通过 VRRP ,两台路由互相进行 健康检查 。 当两台路由都是健康的情况下,只有主路由对外提供虚拟地址的 ARP 响应。 这时,发往虚拟地址 192.168.1.253 的流量都由主路由处理。当主路由故障时,备用路由将检测到。 这时,备用路由开始通过 ARP 协议对外通告:虚拟地址 192.168.1.253 对应的 MAC 地址是我, 被我接管了!接下来,发往虚拟地址 192.168.1.253 的流量就开始由备用路由处理了。 这时,虚拟地址 192.168.1.253 看上去就像是 漂移 到备用路由上一样。 换句话讲,网关成功进行切换,而且无需修改其他机器的网关配置!主路由恢复后,将通过类似的手段,重新拿回流量的处理权。 这部分将不再赘述。完整流程如下:两台路由互相进行健康检查;主路由对外响应虚拟地址的 ARP 请求,通告其 MAC 地址;虚拟地址网络流量被主路由处理;备用路由发现主路由故障,开始响应虚拟地址的 ARP 请求,通告其 MAC 地址;虚拟地址网络流量被备用路由处理;主路由恢复,重新响应 ARP 请求,夺回流量;备用路由发现主路由恢复,停止响应 ARP 请求,释放流量处理权;总结起来, VRRP 主要做两件事情:通过 ARP 响应 MAC 地址实现虚 IP 漂移;通过健康检查决定什么时候进行虚 IP 漂移;应用场景本质上, VRRP 是用来实现高可用的,与网关无关。我们可以将其应用于一些网络服务的高可用,如 Web 服务: 服务高可用方案有很多, VRRP 特别适用于以下场景:服务对外只能呈现为单个 IP ;同一时刻只允许一个实例对外服务;此外, VRRP 也可用于实现负载均衡设施的高可用。 应用的高可用通过负载均衡设施解决,那么负载均衡设施如何实现高可用呢? 答案是—— VRRP !下面是一个非常典型的例子:局限性由于 VRRP 依赖 ARP 实现 IP 漂移,因此相关机器必须在同个网络内, 不能跨网段 。订阅更新,获取更多学习资料,请关注我们的 微信公众号 : ...

February 22, 2019 · 1 min · jiezi

物联网高并发编程之网络编程中的线程模型

如需了解更多物联网网络编程知识请点击:物联网云端开发武器库物联网高并发编程之网络编程中的线程模型值得说明的是,具体选择线程还是进程,更多是与平台及编程语言相关。例如 C 语言使用线程和进程都可以(例如 Nginx 使用进程,Memcached 使用线程),Java 语言一般使用线程(例如 Netty),为了描述方便,下面都使用线程来进行描述。线程模型1:传统阻塞 I/O 服务模型特点:1)采用阻塞式 I/O 模型获取输入数据;2)每个连接都需要独立的线程完成数据输入,业务处理,数据返回的完整操作。存在问题:1)当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大;2)连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。线程模型2:Reactor 模式基本介绍针对传统阻塞 I/O 服务模型的 2 个缺点,比较常见的有如下解决方案: 1)基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理;2)基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务。Reactor 模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。 服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式。即 I/O 多了复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。Reactor 模式中有 2 个关键组成:1)Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。 它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;2)Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。根据 Reactor 的数量和处理资源池线程的数量不同,有 3 种典型的实现:1)单 Reactor 单线程;2)单 Reactor 多线程;3)主从 Reactor 多线程。单 Reactor 单线程其中,Select 是前面 I/O 复用模型介绍的标准网络编程 API,可以实现应用程序通过一个阻塞对象监听多路连接请求,其他方案示意图类似。方案说明:1)Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;2)如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后的后续业务处理;3)如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;4)Handler 会完成 Read→业务处理→Send 的完整业务流程。优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成。缺点:性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。可靠性问题,线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。使用场景:客户端的数量有限,业务处理非常快速,比如 Redis,业务处理的时间复杂度 O(1)。单 Reactor 多线程方案说明:1)Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;2)如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后续的各种事件;3)如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;4)Handler 只负责响应事件,不做具体业务处理,通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;5)Worker 线程池会分配独立的线程完成真正的业务处理,将响应结果发给 Handler 进行处理;6)Handler 收到响应结果后通过 Send 将响应结果返回给 Client。优点:可以充分利用多核 CPU 的处理能力。缺点:多线程数据共享和访问比较复杂;Reactor 承担所有事件的监听和响应,在单线程中运行,高并发场景下容易成为性能瓶颈。主从 Reactor 多线程针对单 Reactor 多线程模型中,Reactor 在单线程中运行,高并发场景下容易成为性能瓶颈,可以让 Reactor 在多线程中运行。方案说明:1)Reactor 主线程 MainReactor 对象通过 Select 监控建立连接事件,收到事件后通过 Acceptor 接收,处理建立连接事件;2)Acceptor 处理建立连接事件后,MainReactor 将连接分配 Reactor 子线程给 SubReactor 进行处理;3)SubReactor 将连接加入连接队列进行监听,并创建一个 Handler 用于处理各种连接事件;4)当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应;5)Handler 通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;6)Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理;7)Handler 收到响应结果后通过 Send 将响应结果返回给 Client。优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。这种模型在许多项目中广泛使用,包括 Nginx 主从 Reactor 多进程模型,Memcached 主从多线程,Netty 主从多线程模型的支持。小结3 种模式可以用个比喻来理解:(餐厅常常雇佣接待员负责迎接顾客,当顾客入坐后,侍应生专门为这张桌子服务)1)单 Reactor 单线程,接待员和侍应生是同一个人,全程为顾客服务;2)单 Reactor 多线程,1 个接待员,多个侍应生,接待员只负责接待;3)主从 Reactor 多线程,多个接待员,多个侍应生。Reactor 模式具有如下的优点:1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;3)可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;4)可复用性,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。线程模型2:Proactor 模型在 Reactor 模式中,Reactor 等待某个事件或者可应用或者操作的状态发生(比如文件描述符可读写,或者是 Socket 可读写)。然后把这个事件传给事先注册的 Handler(事件处理函数或者回调函数),由后者来做实际的读写操作。其中的读写操作都需要应用程序同步操作,所以 Reactor 是非阻塞同步网络模型。如果把 I/O 操作改为异步,即交给操作系统来完成就能进一步提升性能,这就是异步网络模型 Proactor。Proactor 是和异步 I/O 相关的,详细方案如下:1)Proactor Initiator 创建 Proactor 和 Handler 对象,并将 Proactor 和 Handler 都通过 AsyOptProcessor(Asynchronous Operation Processor)注册到内核;2)AsyOptProcessor 处理注册请求,并处理 I/O 操作;3)AsyOptProcessor 完成 I/O 操作后通知 Proactor;4)Proactor 根据不同的事件类型回调不同的 Handler 进行业务处理;5)Handler 完成业务处理。可以看出 Proactor 和 Reactor 的区别:1)Reactor 是在事件发生时就通知事先注册的事件(读写在应用程序线程中处理完成);2)Proactor 是在事件发生时基于异步 I/O 完成读写操作(由内核完成),待 I/O 操作完成后才回调应用程序的处理器来进行业务处理。理论上 Proactor 比 Reactor 效率更高,异步 I/O 更加充分发挥 DMA(Direct Memory Access,直接内存存取)的优势。但是Proactor有如下缺点: 1)编程复杂性,由于异步操作流程的事件的初始化和事件完成在时间和空间上都是相互分离的,因此开发异步应用程序更加复杂。应用程序还可能因为反向的流控而变得更加难以 Debug;2)内存使用,缓冲区在读或写操作的时间段内必须保持住,可能造成持续的不确定性,并且每个并发操作都要求有独立的缓存,相比 Reactor 模式,在 Socket 已经准备好读或写前,是不要求开辟缓存的;3)操作系统支持,Windows 下通过 IOCP 实现了真正的异步 I/O,而在 Linux 系统下,Linux 2.6 才引入,目前异步 I/O 还不完善。因此在 Linux 下实现高并发网络编程都是以 Reactor 模型为主。参考:http://www.52im.net/forum.php ...

February 11, 2019 · 2 min · jiezi