求《飞禽走兽鲨鱼机饲养说明》的txt<(ToT)>

高中物理,高一的,这道题,我不知速率在图中怎么表示,就看不出来的意思… 帮帮忙(ToT)/~~_百度知道
高中物理,高一的,这道题,我不知速率在图中怎么表示,就看不出来的意思… 帮帮忙(ToT)/~~
高中物理,高一的,这道题,我不知速率在图中怎么表示,就看不出来的意思…
帮帮忙(ToT)/~~~
从图中可以看出:在t1时刻之前,Xb&Xa,且Vb&Va,所以t1时刻是汽车b追上汽车a,故A错在t2时刻,b的位移在减小,a的位移在增加,故两车运动方向相反,B正确在t1到t2之间,b曲线的斜率(即△s/△t)在顶点前端在减小,故速率减少,顶点后段斜率增大,速率在增加,故C正确因b车的速度在曲线顶点减小到0,故D错。
斜率工式?
斜率和速率关系是什么?
看坐标轴代表的物理意义了本图的斜率k=△s/△t,即单位时间的位移,即为速率
采纳率:66%
来自团队:
速率大小应该看斜率的绝对值
越接近垂直于x轴的方向,斜率的绝对值越大
速率就看图像对应点的切线斜率
划在图上,在发过来
用斜率X/t=V
是不是五年高考三年模拟
其他2条回答
为您推荐:
其他类似问题
高中物理的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。菜鸟求救,请大侠们指示错误原因,谢谢---系统提示(totla=a+b+c;)有问题。。。_百度知道
菜鸟求救,请大侠们指示错误原因,谢谢---系统提示(totla=a+b+c;)有问题。。。
#include &stdio.h&
int a,b,c;
total,average,
total=a+b+c;
average=total/3;
remainder=total%3;
printf(&%d,%d,%...
看不懂啊,是神马语言
采纳率:38%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。跪着搓衣板的我,想请问有没有人是做美容预约员的?(就是打电话约客人去做美容的)&(ToT)&打了好_百度知道
跪着搓衣板的我,想请问有没有人是做美容预约员的?(就是打电话约客人去做美容的)&(ToT)&打了好
跪着搓衣板的我,想请问有没有人是做美容预约员的?(就是打电话约客人去做美容的)&(ToT)&打了好多个电话,老是说了我是谁谁谁就被拒绝,到底要说什么才能才能让客人有听下去的冲动呢,各位大神,能把预约员跟客人应该会说的对话告诉一下小的吗
我有更好的答案
现在骗子太多
试试免费体验为开场白呢 ?
总之要让顾客产生听下去的欲望
换位思考一下
她一听到我姓什么什么,是代表哪家美容中心联系你的,没等我说完就挂了,要么说不需要(┯_┯)
你就说 你老公有外遇了
为您推荐:
其他类似问题
搓衣板的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。求大佬解释一下这个代码_百度知道
求大佬解释一下这个代码
#include &stdio.h&
int fun(int n, int fromPos, int toPos) {
if (n == 0) return 0;
for (t = 1; t &= 3; t++)
if (t != fromPos && t != toPos)
int tot = 0;
tot += fun(n - ...
我有更好的答案
经过分析,这段代码里面的fromPos和toPos完全没起作用。t也没有起作用。所以化简后的代码是int&fun(int&n)&{&&&&if&(n&==&0)&&&&&&&&return&0;&&&&int&tot&=&0;&&&&tot&+=&fun(n&-&1);&&&&tot++;&&&&tot&+=&fun(n&-&1);&&&&return&}再把冗余的操作合并一下,得到int&fun(int&n)&{&&&&if&(n&==&0)&&&&&&&&return&0;&&&&return&2&*&fun(n&-&1)&+&1;}这下简洁明了了。这其实就是在算一个数列。这个数列的a(0)=0,然后a(n) = 2*a(n-1) + 1
采纳率:80%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。&figure&&img src=&https://pic3.zhimg.com/v2-ccf622e6f8c3188a74cdde47_b.jpg& data-rawwidth=&1155& data-rawheight=&275& class=&origin_image zh-lightbox-thumb& width=&1155& data-original=&https://pic3.zhimg.com/v2-ccf622e6f8c3188a74cdde47_r.jpg&&&/figure&&p&本篇探讨TCP连接管理的初步过程即常规的三次握手过程,从TCP报文格式入手,深入研究在原理层面上的连接建立过程,并辅以实验演示加深理解。&/p&&p&&br&&/p&&p&一、概述&/p&&p&TCP协议在RFC793(&a href=&http://link.zhihu.com/?target=https%3A//www.rfc-editor.org/rfc/rfc793.txt& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&rfc-editor.org/rfc/rfc7&/span&&span class=&invisible&&93.txt&/span&&span class=&ellipsis&&&/span&&/a&)中进行了初步定义,用于在网络层之上、应用层之下提供一种可靠的、点到点面向连接的、协议无关的传输层字节流服务。TCP运行于通信协议中的层次如下:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-79b5ecc4bc8fb60c0c649f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&376& data-rawheight=&316& class=&content_image& width=&376&&&/figure&&p&在一个TCP连接中仅有两方进行彼此通信,因此广播和组播均不能用于TCP。TCP使用如下方式提供可靠性:&/p&&ol&&li&数据传输在连接建立后开始,并在连接断开前结束。若存在单向数据传输,可使用半关闭(half-close)特性节省某一端的连接池资源,该特性将在后续文章中说明。&/li&&li&数据被分割为TCP认为最合适的数据段(segment)交给IP进行传输,后续文章将说明TCP如何确定报文段长度。&/li&&li&TCP在发送一个报文段后即启动一个定时器,若在定时器超时前未收到目的端对这个报文段的确认(Acknowledgement),将重发这个报文段;而接受端在收到一个报文段后将推迟一定时间发送确认。后续文章将说明TCP协议中自适应的超时及重传策略。&/li&&li&TCP使用一个端到端的校验和来保证数据在传输过程中没有发生任何变化,若收到报文的校验和出错,TCP将直接丢弃这个报文段,不会向发送端发起该段的任何确认;发送端定时器超时后将重传该报文段,并继续等待接受端确认。&/li&&li&若报文段失序或发生重复,TCP将对收到的数据进行重新排序或丢弃重复的报文段。&/li&&li&TCP提供传输层的流量控制机制,接收端只允许发送端发送缓冲区能容纳的数据,这将防止较快主机使较慢主机的缓冲区溢出。&/li&&/ol&&p&TCP对字节流的内容不作任何解释,不知道传输的数据是二进制数据、ASCII字符、EBCDIC字符还是其他类型数据。对字节流的解释交由两端应用层完成。&/p&&p&&br&&/p&&p&二、首部格式&/p&&p&TCP数据可被封装在一个标准的IP数据报中,若不计选项字段一般为20字节。格式如下:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-6d89ef84efb3c6b625a8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&742& data-rawheight=&396& class=&origin_image zh-lightbox-thumb& width=&742& data-original=&https://pic1.zhimg.com/v2-6d89ef84efb3c6b625a8_r.jpg&&&/figure&&ul&&li&Source/Destination Port:每个报文段包含源端和目的端的端口号,用于寻找发起端和接收端的应用程序。源/目的IP+源/目的端口号可唯一确定一个TCP连接,称为一个“接口”或“套接字”(Socket)。&/li&&li&Sequence Number:序列号用于标识发送端向接收端发送的报文,是这个报文段中的第一个数据字节。TCP使用序列号对每个报文段进行计数,该字段是一个32位无符号数,到达 后从0开始重新计数。&/li&&li&Acknowledgement Number:确认序列号用于对上一个发送的数据进行确认,同时包含希望收到的下一个报文段的序列号。只有ACK Flag为1时该字段才有效。TCP为应用层提供全双工服务,数据可在两个方向上独立传输,因此连接的每一端必须独立保持每个方向上的传输序列号。&/li&&li&DataOffset:因为TCP首部存在选项字段,首部长度是可变的(最长60字节),所以需要数据偏移字段标识数据的开始字节,也可将该字段看作“首部长度”字段。该字段表示数据字节开始前32bit(8bytes)的个数。&/li&&li&TCP首部中有6个标志比特(Flag bit),此处简单介绍它们的用法:&/li&&/ul&&ol&&li&URG:紧急指针字段有效&/li&&li&ACK:确认序号字段有效&/li&&li&PSH:接收方需尽快把该报文段交给应用层&/li&&li&RST:重置连接&/li&&li&SYN:同步序号,用于发起一个连接&/li&&li&FIN:发送端完成发送任务&/li&&/ol&&ul&&li&Window:TCP流量控制由连接的每一端通过声明窗口大小提供,后续文章中将详细说明该字段在流量控制中的用法。&/li&&li&Checksum:校验和字段包含了整个报文段(TCP首部+TCP数据),是一个强制性的校验字段,后续文章中将说明该字段对报文的验证方法。&/li&&li&UrgentPointer:当URG标志为1时紧急指针生效,和Sequence Number字段值相加表示紧急数据的最后一个字节的序列号。很少有应用使用紧急指针特性。&/li&&li&Padding:填充字段,用于将TCP头部填充为32bit的整数倍。&/li&&/ul&&p&&br&&/p&&p&三、连接建立&/p&&p&在unix终端中输入如下命令可建立与域名“&a href=&http://link.zhihu.com/?target=http%3A//dmmjy9.top/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dmmjy9.top&/a&&的80端口的TCP连接:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-83f0b1e6d723c7ee906e844c08feab43_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&436& data-rawheight=&202& class=&origin_image zh-lightbox-thumb& width=&436& data-original=&https://pic4.zhimg.com/v2-83f0b1e6d723c7ee906e844c08feab43_r.jpg&&&/figure&&p&在Wireshark中显示报文交换过程如下:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-1c49cfe6ede_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&62& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic3.zhimg.com/v2-1c49cfe6ede_r.jpg&&&/figure&&p&从第一个报文段开始分析:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-6fc001ab6a635e1e0d820edfa4c7e4e4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&462& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic1.zhimg.com/v2-6fc001ab6a635e1e0d820edfa4c7e4e4_r.jpg&&&/figure&&p&首先关注Flags字段,客户端发起建立连接请求时会将第一个报文段的SYN Flag置为1,表示这是第一个连接请求(SYN位置1的报文也称为SYN报文);同时设置一个Sequence Number:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-5cea8c2feaa327_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&564& data-rawheight=&44& class=&origin_image zh-lightbox-thumb& width=&564& data-original=&https://pic4.zhimg.com/v2-5cea8c2feaa327_r.jpg&&&/figure&&p&值得注意的是,wireshark中Sequence Number默认显示相对序列号(relative sequence number),实际的序列号为一个特殊变量,该变量每0.5秒增加64000并每隔9.5小时后回到0,需要对wireshark进行设置或使用tcpdump获得这个序列号:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2b2ea0d0ae790b6e212648_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&164& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic1.zhimg.com/v2-2b2ea0d0ae790b6e212648_r.jpg&&&/figure&&p&上图可知此次连接的Sequence Number为“”,该序列号也称为“初识序列号”(ISN,此处记为ISNa)。连接的发起端将源端口设为本地某一随机端口,目的端口设为想要建立连接的服务器端口(该端口在服务器上处于LISTEN状态),发送第一个SYN的一端将执行主动打开(active open),并进入“SYN SENT”状态;收到这个SYN报文并发送下一个SYN+ACK的一端执行被动打开(passive open)并进入“SYN RCVD”状态。此处有一种两端都执行主动打开的机制,将在后续文章中介绍。&/p&&p&收到SYN报文后,服务器将对该连接请求进行验证,若为合法的连接将回复SYN和ACK Flag置为1的报文,该报文在wireshark显示如下:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fada0a282ecbf3621dcead7c5cbf0e2c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&474& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic1.zhimg.com/v2-fada0a282ecbf3621dcead7c5cbf0e2c_r.jpg&&&/figure&&p&如图可知,该报文Flags字段中SYN和ACK Flag都置为1,同时sequence number和acknowledgement number字段都可用。为清楚显示各序列号的关系,使用tcpdump获取序列号值:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-40bf5b44e2e06b7db5f669f7ff82c08e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&888& data-rawheight=&78& class=&origin_image zh-lightbox-thumb& width=&888& data-original=&https://pic3.zhimg.com/v2-40bf5b44e2e06b7db5f669f7ff82c08e_r.jpg&&&/figure&&p&分析上图可知,该报文中的sequence number字段为服务器生成的ISN(此处记为ISNb),同时acknowledgement number设为ISNa+1,用于对上一个SYN报文进行确认。该报文发送后服务器TCP状态进入“SYN RCVD”,并挂起该连接线程等待确认。&/p&&p&客户端收到服务器发送的SYN+ACK报文,将对该报文的acknowledgement number、checksum进行验证,若为合法报文则回复ACK置1的报文,该报文在wireshark中显示如下:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-bb1f879ed489a6b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&490& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic2.zhimg.com/v2-bb1f879ed489a6b_r.jpg&&&/figure&&p&在tcpdump中显示如下:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-dd1d7bbfe3d73e11b2fa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&52& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic3.zhimg.com/v2-dd1d7bbfe3d73e11b2fa_r.jpg&&&/figure&&p&需要注意的是,tcpdump将此处的ack number重置为1,即tcpdump认为连接建立时的最后一个ack就是数据传输的第一个报文,实际值应为ISNb+1。该现象在wireshark中可得到印证:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2d567bbca667d929badd_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&60& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic1.zhimg.com/v2-2d567bbca667d929badd_r.jpg&&&/figure&&p&上图为一个新连接的完整建立过程,可见第三个ack报文的acknowledgement number即为上一个SYN+ACK报文的sequence number + 1。客户端在收到SYN+ACK并发出ACK后将该连接状态置为ESTABLISH,服务端收到ACK后也将该连接状态置为ESTABLISH。至此三次连接建立完成,双方可以进行下一步的数据通信。&/p&&p&&br&&/p&&p&四、连接终止&/p&&p&既然TCP连接是全双工的,数据在两个方向上同时传递,因此每个方向必须单独地进行关闭。当一端收到一个FIN,它必须通知应用层另一端已经终止了向本端的数据传送,但只意味着在这一方向上没有数据流动,因此原则上需要使用四次交换过程来终止TCP连接。一个TCP连接在收到FIN后仍能发送数据,这对于利用半关闭的应用是可能的,尽管现实中很少有TCP应用程序使用这种特性。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-21bb1a8f182fbdf9debdf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&36& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic4.zhimg.com/v2-21bb1a8f182fbdf9debdf_r.jpg&&&/figure&&p&从第一个报文开始分析:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-dae1fa1236_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&488& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic3.zhimg.com/v2-dae1fa1236_r.jpg&&&/figure&&p&如上图,该报文的FIN和ACK置位,其中的acknowledgement number用于客户端对最后一个收到的报文进行确认,其值为最后一个数据报文的sequence number+1;该报文的sequence number与上一个发送报文的相同。&/p&&p&下面是第二个报文:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-e282eb1dea63ec26a3efd_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&502& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic2.zhimg.com/v2-e282eb1dea63ec26a3efd_r.jpg&&&/figure&&p&此报文的FIN与ACK同时置位,并不同于理论上的ACK置位确认上一个FIN报文,其原因是该应用没有使用半关闭特性,客户端发起关闭后服务器也没有继续发送数据的需求,因此服务器将应该回复的ACK报文中的FIN同时置位,用以在服务器 -& 客户端方向同时发起终止连接请求并节约一部分连接池资源。&/p&&p&下面分析最后一个报文:&/p&&figure&&img src=&https://pic4.zhimg.com/v2-6fd450b229c63cd1c8403b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&902& data-rawheight=&486& class=&origin_image zh-lightbox-thumb& width=&902& data-original=&https://pic4.zhimg.com/v2-6fd450b229c63cd1c8403b_r.jpg&&&/figure&&p&该报文的ACK置位,acknowledgement number为上一个收到报文的sequence number+1,服务器收到该报文后即关闭连接的双向数据传输,释放连接池资源。&/p&&p&&br&&/p&&p&五、总结&/p&&p&至此,一个连接从建立到断开的完整过程演示结束,RFC793中的TCP连接状态机如下图:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-4efc2facbe59daebb41d41_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&630& data-rawheight=&712& class=&origin_image zh-lightbox-thumb& width=&630& data-original=&https://pic2.zhimg.com/v2-4efc2facbe59daebb41d41_r.jpg&&&/figure&&p&TCP连接的断开是一个相对复杂的过程,其中涉及多个等待时间、MSL、平静时间等概念,将在后续文章中进行详细说明。&/p&&hr&&p&欢迎各位关注微信公众号:IE进化论,与我们的小团队(一共5人)亲密接触。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-e3f1f2ceeeca22f3bed623_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1063& data-rawheight=&1017& class=&origin_image zh-lightbox-thumb& width=&1063& data-original=&https://pic4.zhimg.com/v2-e3f1f2ceeeca22f3bed623_r.jpg&&&/figure&&p&&/p&
本篇探讨TCP连接管理的初步过程即常规的三次握手过程,从TCP报文格式入手,深入研究在原理层面上的连接建立过程,并辅以实验演示加深理解。 一、概述TCP协议在RFC793()中进行了初步定义,用于在网络层之上、应用层之下提供一种可靠的…
&figure&&img src=&https://pic3.zhimg.com/v2-6b46b9c1f47fab1c527d45bfd58e2489_b.jpg& data-rawwidth=&510& data-rawheight=&340& class=&origin_image zh-lightbox-thumb& width=&510& data-original=&https://pic3.zhimg.com/v2-6b46b9c1f47fab1c527d45bfd58e2489_r.jpg&&&/figure&&p&在我的“&a href=&http://link.zhihu.com/?target=https%3A//coding.imooc.com/class/189.htmlmc_marking%3Df11dd18ecca05d02753fb%26mc_channel%3Dzh& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&系统学习Docker,践行DevOps理念-慕课网实战&/a&”课程里,对于新手,我曾经说过,在玩docker的时候,尽量不要在自己电脑上(Mac或者windows)上直接安装docker和使用他,而是找一个虚拟机。Docker本身如果我们用的时间长了,会占用系统不少硬盘空间,特别是学习期间,今天拉一个image下来,明天又拉一个,今天建一个容器,明天建一个,久而久之,我们的电脑硬盘就吃紧了。如果是在虚拟机(vmware或者virtualbox),我们可以直接删除虚机,但是如果我们不想删除虚机,那如何清理docker所占的硬盘空间呢,本文我们一起来看看吧。&/p&&p&首先,我们先准备一台docker host,比如下面,我们通过df命令先看看系统当前的硬盘空间。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker version
18.05.0-ce
API version:
Go version:
Git commit:
9 22:14:54 2018
linux/amd64
Experimental: false
Orchestrator: swarm
18.05.0-ce
API version:
1.37 (minimum version 1.12)
Go version:
Git commit:
9 22:18:36 2018
linux/amd64
Experimental: false
[vagrant@localhost ~]$ df -h
Filesystem
Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
0% /dev/shm
0% /sys/fs/cgroup
0% /run/user/1000
0% /run/user/0
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&系统现在用了1.3G空间,还有37G可用空间。&/p&&p&首先我们先介绍一个命令,叫 &code&docker system df&/code& ,我们看到目前我们没有任何镜像,容器,存储和cache。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker system df
RECLAIMABLE
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&我们拉一个image看看&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker pull alpine
Using default tag: latest
latest: Pulling from library/alpine
ff3a5c916c92: Pull complete
Digest: sha256:7df6db5aa61aeb3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0
Status: Downloaded newer image for alpine:latest
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
4.148MB (100%)
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&创建一个容器,退出,我们看到其实这个容器本身并不占空间&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker run -d alpine
8b7f9b1e11b85c6dc303cf500f2a19cccd57864fb1eeceb4021a5d
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
Containers
Local Volumes
Build Cache
&/code&&/pre&&/div&&p&下面我们用Dockerfile基于alpine制作一个image,往这个image写入一个1G大小的文件,然后build完,我们看到系统空间多了1G,这个1G后面括号显示100%, 这个100%意思是,这个空间可以100%回收,怎么回收?把这个docker image删了就回收了。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ more Dockerfile
FROM alpine
RUN dd if=/dev/zero of=1g3.img bs=1G count=1
[vagrant@localhost ~]$ docker build -t test1 .
Sending build context to Docker daemon
Step 1/2 : FROM alpine
---& 3fd9065eaf02
Step 2/2 : RUN dd if=/dev/zero of=1g3.img bs=1G count=1
---& Running in 6d9e95f54e26
1+0 records in
1+0 records out
Removing intermediate container 6d9e95f54e26
---& 4ebfe90ead11
Successfully built 4ebfe90ead11
Successfully tagged test1:latest
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
1.078GB (100%)
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&我们再修改下dockerfile,改成写2个1G的文件,然后重新build,我们看到系统的空间变成了之前的两倍,并没有变成3G,也就是它用了之前的image作为cache&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker image ls
REPOSITORY
4ebfe90ead11
3 minutes ago
3fd9065eaf02
4 months ago
[vagrant@localhost ~]$ more Dockerfile
FROM alpine
RUN dd if=/dev/zero of=1g3.img bs=1G count=1
RUN dd if=/dev/zero of=1g3.img bs=1G count=1
[vagrant@localhost ~]$ docker build -t test1 .
Sending build context to Docker daemon
Step 1/3 : FROM alpine
---& 3fd9065eaf02
Step 2/3 : RUN dd if=/dev/zero of=1g3.img bs=1G count=1
---& Using cache
---& 4ebfe90ead11
Step 3/3 : RUN dd if=/dev/zero of=1g3.img bs=1G count=1
---& Running in ce
1+0 records in
1+0 records out
Removing intermediate container ce
---& 9fbb2427fc1d
Successfully built 9fbb2427fc1d
Successfully tagged test1:latest
[vagrant@localhost ~]$ docker image ls
REPOSITORY
9fbb2427fc1d
5 seconds ago
3fd9065eaf02
4 months ago
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
2.152GB (100%)
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&但是有时候我们并不会这么幸运,假如我们的Dockerfile变成&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ more Dockerfile
FROM alpine
RUN echo test
RUN dd if=/dev/zero of=1g3.img bs=1G count=1
RUN dd if=/dev/zero of=1g3.img bs=1G count=1
&/code&&/pre&&/div&&p&RUN echo test 的位置导致docker build image时候不会去使用之前的cache,那么灾难就来了。我们的image变成了3个,我们的系统空间占用变成了4G,之前的test1变成了一个&none&, 这个僵尸image叫dangling images, 这时候怎么办呢?&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker image ls
REPOSITORY
45 seconds ago
9fbb2427fc1d
5 minutes ago
3fd9065eaf02
4 months ago
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
4.299GB (100%)
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&这时候,其实我们手动通过docker image rm可以删除这两个容器,从而释放空间。但是有点麻烦对吧。这时候我们可以试试一个命令&/p&&p&docker system prune&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all build cache
Are you sure you want to continue? [y/N] y
Deleted Containers:
8b7f9b1e11b85c6dc303cf500f2a19cccd57864fb1eeceb4021a5d
Deleted Images:
deleted: sha256:9fbb2427fc1dbaba37fd67a81f25ea128aa06bcc60a
deleted: sha256:63f58c3cb1d917e2f01b0caa4c8899cbf3b27f0d716
deleted: sha256:4ebfe90ead11af51fd590e55e1bd1e5b
deleted: sha256:45f5bb8bb2aa4ab2d392582cbe89bba99d2e3a3dd22c
Total reclaimed space: 2.147GB
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
2.152GB (100%)
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&docker system prune会清理所有已停止的容器,没有被用的network,所有的僵尸image,还是build cache。能够迅速帮我们清理空间。&/p&&p&当然docker system prune 我们可以加一个 &code&-a&/code& 参数,这个就厉害了,除了删除之前docker system prune能删除的东西以外,他还会删除所有没有容器使用的image,比如&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&[vagrant@localhost ~]$ docker system prune -a
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all images without at least one container associated to them
- all build cache
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: alpine:latest
untagged: alpine@sha256:7df6db5aa61aeb3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0
untagged: test1:latest
deleted: sha256:8ca1bdd9cc0bdba9b0bb6e9f3c52e139c62de166b24ac3b2abddab
deleted: sha256:cf8eec9e8e0dfdb48a628e284a8bce27b5d6968e94baacc16ca47ef9d667dc82
deleted: sha256:91e956dd9cf9f736e9b0ee7a8ad746d3b1cfda575c04
deleted: sha256:eedae8fd5d1d7eb00b28aec
deleted: sha256:8bbc26e497f57eb0caef4a26aab0d8faec2d477436e
deleted: sha256:3fd9065eaf02feaf94d6c53cf98353
deleted: sha256:cdcabd804a17f9ae5b42ae02b6215
Total reclaimed space: 2.152GB
[vagrant@localhost ~]$ docker system df
RECLAIMABLE
Containers
Local Volumes
Build Cache
[vagrant@localhost ~]$
&/code&&/pre&&/div&&p&test1这个好的image也被删了,因为没有容器使用它,所以 -a 参数要小心使用。&/p&&p&好的,希望本文能帮助到大家。&/p&&p&&br&&/p&&p&作者:麦兜搞IT&/p&&p&链接:&a href=&http://link.zhihu.com/?target=http%3A//www.imooc.com/article/29611& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&imooc.com/article/29611&/span&&span class=&invisible&&&/span&&/a&&/p&&p&来源:慕课网&/p&&p&本文原创发布于慕课网 ,转载请注明出处,谢谢合作&/p&&hr&&p&&b&推荐阅读:&/b&&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//www.imooc.com/article/24589& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【重磅】认证作者招募 | 打造个人品牌 so easy !&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&有奖征文003期|程序员进阶路上,哪本书你认为很不错,对你帮助很大?&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&如何基于区块链技术开发应用&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&公司内网搭建代理DNS使用内网域名代替ip地址&/a&&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&【Kotlin中使用Dagger2】进阶提升篇(一)&/a&&/p&&p&&/p&&p&&/p&
在我的“”课程里,对于新手,我曾经说过,在玩docker的时候,尽量不要在自己电脑上(Mac或者windows)上直接安装docker和使用他,而是找一个虚拟机。Docker本身如果我们用的时间长了,会占用系统不少硬盘空间,特…
&p&&b&首先我们需要定义一下卡是什么卡,通常来讲,卡顿一般有2种&/b&&/p&&p&&br&&/p&&p&&b&第一种、&/b&由于fps不高所导致的画面不连贯,我们看到的游戏画面实际上是由无数张静态的图像连续播放而来的,通过人眼的视觉暂留效应让你的大脑误以为是一个动画,而每一张静态画面我们称之为一帧,一秒钟显卡渲染出多少帧我们就称之为帧数,帧数的单位是fps,也就是屏幕每秒闪过60张画面=60帧/秒=60fps。那么问题显而易见,帧数越高,你的画面衔接越顺畅,动作越丝滑。帧数如果过低,那么你的画面势必会出现不连贯的卡顿现象。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-937e09e36ce0dd696d6a1bb442d8994b_b.jpg& data-rawwidth=&2350& data-rawheight=&1115& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&2350& data-original=&https://pic2.zhimg.com/50/v2-937e09e36ce0dd696d6a1bb442d8994b_r.jpg&&&figcaption&该图片来自Bilibili极客湾关于游戏帧数的视频&/figcaption&&/figure&&p&&br&&/p&&p&&b&第二种、&/b&由于网络延迟高导致的卡顿,网络延迟在游戏里被称为ping,ping高出现的卡顿最直观的就是人物瞬移,人物失控,操作的东西需要过几秒才能有反应,或者根本没有反应,ping值指的就是你与游戏服务器之间的数据传输时间,比如你在你家下达了一个释放Q技能,这个指令传送到服务器花了1秒,服务器确定你释放了Q,反馈给你的电脑,又要花1秒传给你,你的电脑受到了这个信息后,在你的屏幕上表现出来技能Q的效果和结果。那么,你这个Q从按下到显示到屏幕,花费了2秒,这时候你自然就会觉得卡,这种卡是源于网络。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-a835eb333d51bf1ab8610b_b.jpg& data-rawwidth=&1120& data-rawheight=&672& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&1120& data-original=&https://pic2.zhimg.com/50/v2-a835eb333d51bf1ab8610b_r.jpg&&&figcaption&该图片来自百度&/figcaption&&/figure&&p&&br&&/p&&p&上面我们讨论了卡顿的类型,下面我们就开始讨论这些卡顿究竟是什么东西引起的了,答主所问的是硬件瓶颈,那么我们就将所有的软件导致的卡顿排除,比如驱动程序,系统这一类的。&/p&&p&&br&&/p&&p&这里给大家推荐一个非常好用的软件“游戏加加”,他可以非常直观的在你的屏幕顶端显示一个状态栏,你可以自定义显示的内容,其中有fps,显卡占用,内存占用,CPU占用,还有各种温度等情况,通过游戏加加我们能非常方便的判读出你的硬件是哪一部分出现了瓶颈。在游戏结束后他还能帮你生成各种曲线的表格,非常方便。&b&(这里要注意的是,假如你没有对fps进行上限规定,那么显卡就会全力输出帧数直到满载)&/b&&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-2b1c103ef15dc133cb054_b.jpg& data-rawwidth=&568& data-rawheight=&368& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&568& data-original=&https://pic4.zhimg.com/50/v2-2b1c103ef15dc133cb054_r.jpg&&&figcaption&游戏加加软件界面&/figcaption&&/figure&&p&&br&&/p&&p&&b&第一种:由于fps所导致的画面流畅度&/b& &/p&&p&现在我们切入正题,既然FPS就是影响画面流畅度的,那么我们只需要知道哪些硬件会影响FPS就行了,主要能直观影响FPS主要就2个部件,CPU,显卡。&/p&&p&这里我们先了解一下CPU和显卡工作的分配情况,我们在电脑内部生成一个大的三维空间,让一个小球自由下落,它落到地面后会弹起来然后再次落下弹起,直到停止。&/p&&p&那么这里面CPU的作用就是计算小球受到的重力加速度,下落速度,空气阻力,落到地面动能的转变,并根据各自参数去计算小球的运行轨迹。&/p&&p&那显卡的作用是什么呢,显卡在这里面需要把这个三维图像建立出来,他需要给空间附着颜色,还需要给小球也附着颜色,这个部分我们称之为“贴图”,除了贴图外,显卡还需要让这个贴图跟着小球质点运动的轨迹一块运动,最后还需要把三维的图像二维化并输出到屏幕上去。&/p&&p&这里答案就显而易见了,CPU主要负责逻辑运算部分,而显卡的作用就是图形化。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-887c0ba9e4dc5fc2aa48729_b.jpg& data-rawwidth=&500& data-rawheight=&231& data-caption=&& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&https://pic1.zhimg.com/50/v2-887c0ba9e4dc5fc2aa48729_r.jpg&&&/figure&&p&那么,游戏元素少的,画面精美的游戏,就对于显卡的要求比较高,而画面一般但是游戏元素多的,他就吃CPU。&/p&&p&这里就拿孤岛危机来举例,孤岛危机就属于那种画面很好,但游戏元素不多的,一般来讲,场景主要就是环境构成,他不需要CPU进行多少运算,反而是需要显卡去进行复杂的贴图工作。那么这类游戏,基本硬件瓶颈就出在显卡上面了。&/p&&p&而战地1这种,64人一张地图,各种爆炸物飞溅,子弹飞行,下坠,碎片乱飞,各种场景破坏,这就需要大量的CPU运算,同时,战地1的画面也可以算非常好了,所以战地一对于显卡和CPU的要求都很高,尤其是64人征服,尤其吃CPU,不少I7都能轻松满载。&/p&&p&另外一个游戏就是坎巴拉太空计划,这是一个给你部件让你造火箭的游戏,他的画面不算好,但是物理系统非常出色,你想一下几百个组件的火箭在发射的时候,各种空气阻力,气动模型,重力,分分钟把你的CPU吃满,这时候显卡除了给火箭贴上几乎是色块这么简单的贴图外就没什么工作了,所以类似这样的“我的世界”这个游戏,他们都是对于CPU要求比显卡要求高。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-d4abfc927bf5f66b70e05f_b.jpg& data-rawwidth=&579& data-rawheight=&325& data-caption=&& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&579& data-original=&https://pic3.zhimg.com/50/v2-d4abfc927bf5f66b70e05f_r.jpg&&&/figure&&p&&br&&/p&&p&那么我们就很容易就能判读到底是CPU瓶颈还是显卡瓶颈了:&/p&&p&元素多画面差的,吃CPU;&/p&&p&元素少画面好的,吃显卡;&/p&&p&元素也多画面也好的,CPU显卡都吃;&/p&&p&&br&&/p&&p&除了显卡CPU这种性能级部件外,内存容量与显存也是不能忽视的,&b&如果你的游戏画面帧数很高,但是经常出现顿卡或者间歇性掉帧的现象,那么很大一部分是由于你的显存或者内存爆满导致的&/b&,显卡和显存就好比CPU和内存,所以游戏元素主要吃内存,而画面精细程度主要吃显存。这里判断谁瓶颈了只需要监视一下后台看看内存和显存的占用情况就能非常清楚的知道是谁瓶颈了。&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-0e526e65afa64dcec59acb77_b.jpg& data-rawwidth=&680& data-rawheight=&600& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&680& data-original=&https://pic3.zhimg.com/50/v2-0e526e65afa64dcec59acb77_r.jpg&&&/figure&&p&&br&&/p&&p&除了画面流畅,加载的流畅度也是另外一方面,我们游戏在loading的过程实际上就是在将硬盘里的数据转移到内存里,就好像你吃菜之前需要把菜先夹到碗里一样,CPU算数之前也需要先把数据从硬盘转移到内存中,&b&而内存的速度是非常快的,所以我们不需要考虑内存速度带来的瓶颈&/b&,&b&内存出现瓶颈大多都是上面所说的容量&/b&,&b&而loading瓶颈多半出在硬盘上&/b&,我们传统的机械硬盘速度非常慢,尤其是随机读写部分,因此,使用机械硬盘的同学开机速度通常不会很快,而且游戏的loading也会很慢,这里绝地求生就很明显,你落地后如果房子都是和豆腐一样,糊一片的,那就是你的硬盘或者内存不够快,不能及时把数据传送给显卡还有CPU,这时候只需要把你的吃鸡放到固态里去就好了。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-e05cf0c70bea6d702c02cf9fa10f839b_b.jpg& data-rawwidth=&471& data-rawheight=&310& data-caption=&& data-size=&normal& class=&origin_image zh-lightbox-thumb& width=&471& data-original=&https://pic1.zhimg.com/50/v2-e05cf0c70bea6d702c02cf9fa10f839b_r.jpg&&&/figure&&p&&br&&/p&&p&&b&第二种:网络延迟所导致的卡顿现象&/b&&/p&&p&最后说说网络卡顿的情况,如果你是这几年刚换的电脑,那么你的主板有线网卡基本不会构成网络瓶颈,你只需要注意你的网线质量如何就行,而使用wifi的,那么无线网卡与无线天线的质量很大一部分程度上会影响到你的ping值,另外就是wifi本身属于无线信号,他会受到各种条件干扰,所以玩游戏非常不推荐使用无线网络。&/p&&p&另外作为家庭网络的入口,路由器也是不容忽视的,好的路由器允许多台设备同时连接还不出现分包不均的情况,而差一点的路由器稍微设备一多就分包不过来导致卡顿。&/p&&p&最后是运营商那边,假如运营商本身的网络就有问题,那你家里再怎么弄都无济于事,你只能去投诉运营商来解决了。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-71bba0eed5a0fe2cc17d9f34e324a435_b.jpg& data-rawwidth=&400& data-rawheight=&300& data-caption=&& data-size=&normal& class=&content_image& width=&400&&&/figure&&hr&&h2&如果你觉得答主回答的不错,那就点一波关注吧,你的关注是对我最大的支持!!!&/h2&
首先我们需要定义一下卡是什么卡,通常来讲,卡顿一般有2种 第一种、由于fps不高所导致的画面不连贯,我们看到的游戏画面实际上是由无数张静态的图像连续播放而来的,通过人眼的视觉暂留效应让你的大脑误以为是一个动画,而每一张静态画面我们称之为一帧,…
更新:由于此文陆陆续续收到赞同,而且其中有些地方并不完全正确,特在本文最后予以订正&br&&br&我不了解楼主的层次,我必须从很多基础的概念开始构建这个答案,并且可能引申到很多别的问题。&br&&br&首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作的内核对象。&br&不管是文件,还是套接字,还是管道,我们都可以把他们看作流。&br&之后我们来讨论I/O的操作,通过read,我们可以从流中读入数据;通过write,我们可以往流写入数据。现在假定一个情形,我们需要从流中读数据,&b&但是流中还没有数据&/b&,(典型的例子为,客户端要从socket读如数据,但是服务器还没有把数据传回来),这时候该怎么办?&br&&ul&&li&阻塞。阻塞是个什么概念呢?比如某个时候你在等快递,但是你不知道快递什么时候过来,而且你没有别的事可以干(或者说接下来的事要等快递来了才能做);那么你可以去睡觉了,因为你知道快递把货送来时一定会给你打个电话(假定一定能叫醒你)。&/li&&li&非阻塞&b&忙&/b&轮询。接着上面等快递的例子,如果用忙轮询的方法,那么你需要知道快递员的手机号,然后每分钟给他挂个电话:“你到了没?”&/li&&/ul&很明显一般人不会用第二种做法,不仅显很无脑,浪费话费不说,还占用了快递员大量的时间。&br&大部分程序也不会用第二种做法,因为第一种方法经济而简单,经济是指消耗很少的CPU时间,如果线程睡眠了,就掉出了系统的调度队列,暂时不会去瓜分CPU宝贵的时间片了。&br&&br&为了了解阻塞是如何进行的,我们来讨论缓冲区,以及内核缓冲区,最终把I/O事件解释清楚。缓冲区的引入是为了减少频繁I/O操作而引起频繁的系统调用(你知道它很慢的),当你操作一个流时,更多的是以缓冲区为单位进行操作,这是相对于用户空间而言。对于内核来说,也需要缓冲区。&br&假设有一个管道,进程A为管道的写入方,B为管道的读出方。&br&&ol&&li&假设一开始内核缓冲区是空的,B作为读出方,被阻塞着。然后首先A往管道写入,这时候内核缓冲区由空的状态变到非空状态,内核就会产生一个事件告诉B该醒来了,这个事件姑且称之为“缓冲区非空”。&/li&&li&但是“缓冲区非空”事件通知B后,B却还没有读出数据;且内核许诺了不能把写入管道中的数据丢掉这个时候,A写入的数据会滞留在内核缓冲区中,如果内核也缓冲区满了,B仍未开始读数据,最终内核缓冲区会被填满,这个时候会产生一个I/O事件,告诉进程A,你该等等(阻塞)了,我们把这个事件定义为“缓冲区满”。&/li&&li&假设后来B终于开始读数据了,于是内核的缓冲区空了出来,这时候内核会告诉A,内核缓冲区有空位了,你可以从长眠中醒来了,继续写数据了,我们把这个事件叫做“缓冲区非满”&/li&&li&也许事件Y1已经通知了A,但是A也没有数据写入了,而B继续读出数据,知道内核缓冲区空了。这个时候内核就告诉B,你需要阻塞了!,我们把这个时间定为“缓冲区空”。&/li&&/ol&这四个情形涵盖了四个I/O事件,缓冲区满,缓冲区空,缓冲区非空,缓冲区非满(注都是说的内核缓冲区,且这四个术语都是我生造的,仅为解释其原理而造)。这四个I/O事件是进行阻塞同步的根本。(如果不能理解“同步”是什么概念,请学习操作系统的锁,信号量,条件变量等任务同步方面的相关知识)。&br&&br&然后我们来说说阻塞I/O的缺点。但是阻塞I/O模式下,一个线程只能处理一个流的I/O事件。如果想要同时处理多个流,要么多进程(fork),要么多线程(pthread_create),很不幸这两种方法效率都不高。&br&于是再来考虑非阻塞忙轮询的I/O方式,我们发现我们可以同时处理多个流了(把一个流从阻塞模式切换到非阻塞模式再此不予讨论):&br&while true {&br&
for i in stream[]; {&br&
if i has data&br&
read until unavailable&br&}&br&}&br&我们只要不停的把所有流从头到尾问一遍,又从头开始。这样就可以处理多个流了,但这样的做法显然不好,因为如果所有的流都没有数据,那么只会白白浪费CPU。这里要补充一点,阻塞模式下,内核对于I/O事件的处理是阻塞或者唤醒,而非阻塞模式下则把I/O事件交给其他对象(后文介绍的select以及epoll)处理甚至直接忽略。&br&&br&为了避免CPU空转,可以引进了一个代理(一开始有一位叫做select的代理,后来又有一位叫做poll的代理,不过两者的本质是一样的)。这个代理比较厉害,可以同时观察许多流的I/O事件,在空闲的时候,&b&会把当前线程阻塞掉&/b&,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流(于是我们可以把“忙”字去掉了)。代码长这样:&br&while true {&br&
select(streams[])&br&
for i in streams[] {&br&
if i has data&br&
read until unavailable&br&}&br&}&br&于是,如果没有I/O事件产生,我们的程序就会阻塞在select处。但是依然有个问题,我们从select那里仅仅知道了,有I/O事件发生了,但却并不知道是那几个流(可能有一个,多个,甚至全部),我们只能&b&无差别轮询&/b&所有流,找出能读出数据,或者写入数据的流,对他们进行操作。&br&但是使用select,我们有O(n)的无差别轮询复杂度,同时处理的流越多,每一次无差别轮询时间就越长。再次&br&&b&说了这么多,终于能好好解释epoll了&/b&&br&epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。(复杂度降低到了O(k),k为产生I/O事件的流的个数,也有认为O(1)的[更新 1])&br&在讨论epoll的实现细节之前,先把epoll的相关操作列出[更新 2]:&br&&ul&&li&epoll_create 创建一个epoll对象,一般epollfd = epoll_create()&br&&/li&&li&epoll_ctl (epoll_add/epoll_del的合体),往epoll对象中增加/删除某一个流的某一个事件&br&比如&br&epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//有缓冲区内有数据时epoll_wait返回&br&epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//缓冲区可写入时epoll_wait返回&/li&&li&epoll_wait(epollfd,...)等待直到注册的事件发生&br&&/li&&/ul&(注:当对一个非阻塞流的读写发生缓冲区满或缓冲区空,write/read会返回-1,并设置errno=EAGAIN。而epoll只关心缓冲区非满和缓冲区非空事件)。&br&一个epoll模式的代码大概的样子是:&br&while true {&br&
active_stream[] = epoll_wait(epollfd)&br&
for i in active_stream[] {&br&
read or write till unavailable&br&}&br&}&br&限于篇幅,我只说这么多,以揭示原理性的东西,至于epoll的使用细节,请参考man和google,实现细节,请参阅linux kernel source。&br&======================================&br&[更新1]: 原文为O(1),但实际上O(k)更为准确&br&[更新2]: 原文所列第二点说法让人产生EPOLLIN/EPOLLOUT等同于“缓冲区非空”和“缓冲区非满”的事件,但并非如此,详细可以Google关于epoll的边缘触发和水平触发。
更新:由于此文陆陆续续收到赞同,而且其中有些地方并不完全正确,特在本文最后予以订正 我不了解楼主的层次,我必须从很多基础的概念开始构建这个答案,并且可能引申到很多别的问题。 首先我们来定义流的概念,一个流可以是文件,socket,pipe等…
&p&回答这个问题之前,先要了解在哪些情况下TCP的一方会发送RST(Reset)给另外一方。&/p&&p&&br&&/p&&p&学习TCP的很多读者,会知道一个TCP连接在数据传输完毕,通常会关闭连接,以释放通信双方的资源,如内存、端口号,以便于其它程序使用,这种正常释放连接的过程,通常使用FIN(Final)状态位来完成。&/p&&p&&br&&/p&&p&但FIN状态位不能用来处理异常情况。&/p&&p&&br&&/p&&p&异常情况一:&/p&&p&客户端、服务器端TCP连接一切正常,TCP连接由于没有数据传输而出于空闲(Idle)状态。&/p&&p&&br&&/p&&p&突然服务器掉电,当服务器重新启动完毕,与客户端的TCP连接状态由于掉电而完全消失。&/p&&p&&br&&/p&&p&之后,客户端发给服务器任何消息,都会触发服务器发RST作为回应。&/p&&p&&br&&/p&&p&服务器之所以发RST,是因为连接不存在,通过Reset状态位,间接告诉客户端异常情况的存在。&/p&&p&&br&&/p&&p&如果Reset顺利到达客户端,客户端意识到异常发生了,会立马释放该TCP连接所占用的内存资源(状态、数据)、以及端口号。&/p&&p&&br&&/p&&p&客户端TCP会通知数据的主人(应用程序),由于TCP连接被对方Reset,数据发送失败。&/p&&p&&br&&/p&&p&客户端无需超时等待,立即使用原有端口号,重新发起一个TCP连接,双方状态再一次同步,进入正常通信状态。&/p&&p&&br&&/p&&p&这种情况是由于外界因素影响,使得双方状态不同步,一方为“established”,另一方为“closed”, 重置(Reset)连接状态是最好的方法!&/p&&p&&br&&/p&&p&有读者会问,如果客户端一直没有消息发给服务器端,那双方状态的不同步是否会保持到天长地久?&/p&&p&会的!&/p&&p&但是考虑到当前的网络状况,这种可能性是比较小的,因为目前的网络NAT无处不在,为了克服NAT表项没有流量刷新而删除NAT表项,进而影响客户端、服务器端通信,如今的TCP实现会在几十秒发送一次Keepalive,这样即使没有用户流量,Keepalive也会刷新NAT表项,从而避免NAT设备删表操作。&/p&&p&所以双方通信不同步状态,在当今的TCP实现上会很快监测到、并予以纠正。&/p&&p&更详细内容请关注微信公众号:&b&车小胖谈网络&/b&&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/oF4m39qkUBg1ylQMxomZRQ& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&mp.weixin.qq.com/s/oF4m&/span&&span class=&invisible&&39qkUBg1ylQMxomZRQ&/span&&span class=&ellipsis&&&/span&&/a&&/p&
回答这个问题之前,先要了解在哪些情况下TCP的一方会发送RST(Reset)给另外一方。 学习TCP的很多读者,会知道一个TCP连接在数据传输完毕,通常会关闭连接,以释放通信双方的资源,如内存、端口号,以便于其它程序使用,这种正常释放连接的过程,通常使用FI…
&figure&&img src=&https://pic2.zhimg.com/v2-f1cc32a8c6975b9bc474_b.jpg& data-rawwidth=&910& data-rawheight=&510& class=&origin_image zh-lightbox-thumb& width=&910& data-original=&https://pic2.zhimg.com/v2-f1cc32a8c6975b9bc474_r.jpg&&&/figure&&p&(之前的 gdb 系列文章:&a href=&http://link.zhihu.com/?target=https%3A//linux.cn/article-9491-1.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&gdb 如何工作(2016)&/a& 和&a href=&http://link.zhihu.com/?target=https%3A//linux.cn/article-9276-1.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&三步上手 gdb(2014)&/a&)&/p&&p&在这周,我发现我可以从 gdb 上调用 C 函数。这看起来很酷,因为在过去我认为 gdb 最多只是一个只读调试工具。&/p&&p&我对 gdb 能够调用函数感到很吃惊。正如往常所做的那样,我在 &a href=&http://link.zhihu.com/?target=https%3A//twitter.com/b0rk/status/765248& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Twitter&/a& 上询问这是如何工作的。我得到了大量的有用答案。我最喜欢的答案是 &a href=&http://link.zhihu.com/?target=https%3A//github.com/eklitzke/ptrace-call-userspace/blob/master/call_fprintf.c& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Evan Klitzke 的示例 C 代码&/a&,它展示了 gdb 如何调用函数。代码能够运行,这很令人激动!&/p&&p&我(通过一些跟踪和实验)认为那个示例 C 代码和 gdb 实际上如何调用函数不同。因此,在这篇文章中,我将会阐述 gdb 是如何调用函数的,以及我是如何知道的。&/p&&p&关于 gdb 如何调用函数,还有许多我不知道的事情,并且,在这儿我写的内容有可能是错误的。&/p&&h2&&b&从 gdb 中调用 C 函数意味着什么?&/b&&/h2&&p&在开始讲解这是如何工作之前,我先快速的谈论一下我是如何发现这件令人惊讶的事情的。&/p&&p&假如,你已经在运行一个 C 程序(目标程序)。你可以运行程序中的一个函数,只需要像下面这样做:&/p&&ul&&li&暂停程序(因为它已经在运行中)&/li&&li&找到你想调用的函数的地址(使用符号表)&/li&&li&使程序(目标程序)跳转到那个地址&/li&&li&当函数返回时,恢复之前的指令指针和寄存器&/li&&/ul&&p&通过符号表来找到想要调用的函数的地址非常容易。下面是一段非常简单但能够工作的代码,我在 Linux 上使用这段代码作为例子来讲解如何找到地址。这段代码使用 &a href=&http://link.zhihu.com/?target=https%3A//cole14.github.io/rust-elf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&elf crate&/a&。如果我想找到 PID 为 2345 的进程中的 &code&foo&/code& 函数的地址,那么我可以运行 &code&elf_symbol_value(&/proc/2345/exe&, &foo&)&/code&。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&fn elf_symbol_value(file_name: &str, symbol_name: &str) -& Result&u64, Box&std::error::Error&& {
// 打开 ELF 文件
let file = elf::File::open_path(file_name).ok().ok_or(&parse error&)?;
// 在所有的段 & 符号中循环,直到找到正确的那个
let sections = &file.
for s in sections {
for sym in file.get_symbols(&s).ok().ok_or(&parse error&)? {
if sym.name == symbol_name {
return Ok(sym.value);
None.ok_or(&No symbol found&)?
&/code&&/pre&&/div&&p&这并不能够真的发挥作用,你还需要找到文件的内存映射,并将符号偏移量加到文件映射的起始位置。找到内存映射并不困难,它位于 &code&/proc/PID/maps&/code& 中。&/p&&p&总之,找到想要调用的函数地址对我来说很直接,但是其余部分(改变指令指针,恢复寄存器等)看起来就不这么明显了。&/p&&h2&&b&你不能仅仅进行跳转&/b&&/h2&&p&我已经说过,你不能够仅仅找到你想要运行的那个函数地址,然后跳转到那儿。我在 gdb 中尝试过那样做(&code&jump foo&/code&),然后程序出现了段错误。毫无意义。&/p&&h2&&b&如何从 gdb 中调用 C 函数&/b&&/h2&&p&首先,这是可能的。我写了一个非常简洁的 C 程序,它所做的事只有 &code&sleep&/code& 1000 秒,把这个文件命名为 &code&test.c&/code& :&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#include &unistd.h&
int foo() {
int main() {
sleep(1000);
&/code&&/pre&&/div&&p&接下来,编译并运行它:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$ gcc -o test
&/code&&/pre&&/div&&p&最后,我们使用 gdb 来跟踪 &code&test&/code& 这一程序:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$ sudo gdb -p $(pgrep -f test)
(gdb) p foo()
(gdb) quit
&/code&&/pre&&/div&&p&我运行 &code&p foo()&/code& 然后它运行了这个函数!这非常有趣。&/p&&h2&&b&这有什么用?&/b&&/h2&&p&下面是一些可能的用途:&/p&&ul&&li&它使得你可以把 gdb 当成一个 C 应答式程序(REPL),这很有趣,我想对开发也会有用&/li&&li&在 gdb 中进行调试的时候展示/浏览复杂数据结构的功能函数(感谢 &a href=&http://link.zhihu.com/?target=https%3A//twitter.com/invalidop/status/781440& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&@invalidop&/a&)&/li&&li&&a href=&http://link.zhihu.com/?target=https%3A//github.com/baloo/setns/blob/master/setns.c& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&在进程运行时设置一个任意的名字空间&/a&(我的同事 &a href=&http://link.zhihu.com/?target=https%3A//github.com/nelhage& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&nelhage&/a& 对此非常惊讶)&/li&&li&可能还有许多我所不知道的用途&/li&&/ul&&h2&&b&它是如何工作的&/b&&/h2&&p&当我在 Twitter 上询问从 gdb 中调用函数是如何工作的时,我得到了大量有用的回答。许多答案是“你从符号表中得到了函数的地址”,但这并不是完整的答案。&/p&&p&有个人告诉了我两篇关于 gdb 如何工作的系列文章:&a href=&http://link.zhihu.com/?target=https%3A//www.cl.cam.ac.uk/%7Esrk31/blog//%23native-debugging-part-1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原生调试:第一部分&/a&,&a href=&http://link.zhihu.com/?target=https%3A//www.cl.cam.ac.uk/%7Esrk31/blog//%23native-debugging-part-2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原生调试:第二部分&/a&。第一部分讲述了 gdb 是如何调用函数的(指出了 gdb 实际上完成这件事并不简单,但是我将会尽力)。&/p&&p&步骤列举如下:&/p&&ol&&li&停止进程&/li&&li&创建一个新的栈框(远离真实栈)&/li&&li&保存所有寄存器&/li&&li&设置你想要调用的函数的寄存器参数&/li&&li&设置栈指针指向新的 &i&栈框(stack frame)&/i&&/li&&li&在内存中某个位置放置一条陷阱指令&/li&&li&为陷阱指令设置返回地址&/li&&li&设置指令寄存器的值为你想要调用的函数地址&/li&&li&再次运行进程!&/li&&/ol&&p&(LCTT 译注:如果将这个调用的函数看成一个单独的线程,gdb 实际上所做的事情就是一个简单的线程上下文切换)&/p&&p&我不知道 gdb 是如何完成这些所有事情的,但是今天晚上,我学到了这些所有事情中的其中几件。&/p&&h2&&code&创建一个栈框&/code&&/h2&&p&如果你想要运行一个 C 函数,那么你需要一个栈来存储变量。你肯定不想继续使用当前的栈。准确来说,在 gdb 调用函数之前(通过设置函数指针并跳转),它需要设置栈指针到某个地方。&/p&&p&这儿是 Twitter 上一些关于它如何工作的猜测:&/p&&blockquote&我认为它在当前栈的栈顶上构造了一个新的栈框来进行调用!&/blockquote&&p&以及&/p&&blockquote&你确定是这样吗?它应该是分配一个伪栈,然后临时将 sp (栈指针寄存器)的值改为那个栈的地址。你可以试一试,你可以在那儿设置一个断点,然后看一看栈指针寄存器的值,它是否和当前程序寄存器的值相近?&/blockquote&&p&我通过 gdb 做了一个试验:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&(gdb) p $rsp
$7 = (void *) 0x7ffea3d0bca8
(gdb) break foo
Breakpoint 1 at 0x40052a
(gdb) p foo()
Breakpoint 1, 0x052a in foo ()
(gdb) p $rsp
$8 = (void *) 0x7ffea3d0bc00
&/code&&/pre&&/div&&p&这看起来符合“gdb 在当前栈的栈顶构造了一个新的栈框”这一理论。因为栈指针(&code&$rsp&/code&)从 &code&0x7ffea3d0bca8&/code& 变成了 &code&0x7ffea3d0bc00&/code& —— 栈指针从高地址往低地址长。所以 &code&0x7ffea3d0bca8&/code& 在 &code&0x7ffea3d0bc00&/code& 的后面。真是有趣!&/p&&p&所以,看起来 gdb 只是在当前栈所在位置创建了一个新的栈框。这令我很惊讶!&/p&&h2&&code&改变指令指针&/code&&/h2&&p&让我们来看一看 gdb 是如何改变指令指针的!&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&(gdb) p $rip
$1 = (void (*)()) 0x7fae7d29a2f0 &__nanosleep_nocancel+7&
(gdb) b foo
Breakpoint 1 at 0x40052a
(gdb) p foo()
Breakpoint 1, 0x052a in foo ()
(gdb) p $rip
$3 = (void (*)()) 0x40052a &foo+4&
&/code&&/pre&&/div&&p&的确是!指令指针从 &code&0x7fae7d29a2f0&/code& 变为了 &code&0x40052a&/code&(&code&foo&/code& 函数的地址)。&/p&&p&我盯着输出看了很久,但仍然不理解它是如何改变指令指针的,但这并不影响什么。&/p&&h2&&code&如何设置断点&/code&&/h2&&p&上面我写到 &code&break foo&/code& 。我跟踪 gdb 运行程序的过程,但是没有任何发现。&/p&&p&下面是 gdb 用来设置断点的一些系统调用。它们非常简单。它把一条指令用 &code&cc&/code& 代替了(这告诉我们 &code&int3&/code& 意味着 &code&send SIGTRAP&/code& &a href=&http://link.zhihu.com/?target=https%3A//defuse.ca/online-x86-assembler.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&https://defuse.ca/online-x86-assembler.html&/a&),并且一旦程序被打断了,它就把指令恢复为原先的样子。&/p&&p&我在函数 &code&foo&/code& 那儿设置了一个断点,地址为 &code&0x400528&/code& 。&/p&&p&&code&PTRACE_POKEDATA&/code& 展示了 gdb 如何改变正在运行的程序。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 改变 0x400528 处的指令
25622 ptrace(PTRACE_PEEKTEXT, 2528, [0x5de589]) = 0
25622 ptrace(PTRACE_POKEDATA, 2528, 0x5dcce589) = 0
// 开始运行程序
25622 ptrace(PTRACE_CONT, 2, SIG_0) = 0
// 当到达断点时获取一个信号
25622 ptrace(PTRACE_GETSIGINFO, 25618, NULL, {si_signo=SIGTRAP, si_code=SI_KERNEL, si_value={int=-, ptr=0x7ffda9bd3f00}}) = 0
// 将 0x400528 处的指令更改为之前的样子
25622 ptrace(PTRACE_PEEKTEXT, 2528, [0x5dcce589]) = 0
25622 ptrace(PTRACE_POKEDATA, 2528, 0x5de589) = 0
&/code&&/pre&&/div&&h2&&code&在某处放置一条陷阱指令&/code&&/h2&&p&当 gdb 运行一个函数的时候,它也会在某个地方放置一条陷阱指令。这是其中一条。它基本上是用 &code&cc&/code&来替换一条指令(&code&int3&/code&)。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&5908
ptrace(PTRACE_PEEKTEXT, f6fa7c0b260, [0x48f389fd]) = 0
ptrace(PTRACE_PEEKTEXT, f6fa7c0b260, [0x48f389fd]) = 0
5908 ptrace(PTRACE_POKEDATA, f6fa7c0b260, 0x48f389fd894853cc) = 0
&/code&&/pre&&/div&&p&&code&0x7f6fa7c0b260&/code& 是什么?我查看了进程的内存映射,发现它位于 &code&/lib/x86_64-linux-gnu/libc-2.23.so&/code& 中的某个位置。这很奇怪,为什么 gdb 将陷阱指令放在 libc 中?&/p&&p&让我们看一看里面的函数是什么,它是 &code&__libc_siglongjmp&/code& 。其他 gdb 放置陷阱指令的地方的函数是 &code&__longjmp&/code& 、&code&___longjmp_chk&/code& 、&code&dl_main&/code& 和 &code&_dl_close_worker&/code& 。&/p&&p&为什么?我不知道!也许出于某种原因,当函数 &code&foo()&/code& 返回时,它调用 &code&longjmp&/code& ,从而 gdb 能够进行返回控制。我不确定。&/p&&h2&&b&gdb 如何调用函数是很复杂的!&/b&&/h2&&p&我将要在这儿停止了(现在已经凌晨 1 点),但是我知道的多一些了!&/p&&p&看起来“gdb 如何调用函数”这一问题的答案并不简单。我发现这很有趣并且努力找出其中一些答案,希望你也能够找到。&/p&&p&我依旧有很多未回答的问题,关于 gdb 是如何完成这些所有事的,但是可以了。我不需要真的知道关于 gdb 是如何工作的所有细节,但是我很开心,我有了一些进一步的理解。&/p&&hr&&p&via: &a href=&http://link.zhihu.com/?target=https%3A//jvns.ca/blog//how-does-gdb-call-functions/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&jvns.ca/blog/&/span&&span class=&invisible&&/how-does-gdb-call-functions/&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&作者:&a href=&http://link.zhihu.com/?target=https%3A//jvns.ca/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Julia Evans&/a& 译者:&a href=&http://link.zhihu.com/?target=https%3A//github.com/ucasFL& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ucasFL&/a& 校对:&a href=&http://link.zhihu.com/?target=https%3A//github.com/wxy& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&wxy&/a&&/p&&p&本文由 &a href=&http://link.zhihu.com/?target=https%3A//github.com/LCTT/TranslateProject& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LCTT&/a& 原创编译,&a href=&http://link.zhihu.com/?target=https%3A//linux.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux中国&/a& 荣誉推出&/p&
(之前的 gdb 系列文章: 和)在这周,我发现我可以从 gdb 上调用 C 函数。这看起来很酷,因为在过去我认为 gdb 最多只是一个只读调试工具。我对 gdb 能够调用函数感到很吃惊。正如往常所做的那样,我在
&figure&&img src=&https://pic2.zhimg.com/v2-fcec8c707e07f0b3976f2e_b.jpg& data-rawwidth=&909& data-rawheight=&509& class=&origin_image zh-lightbox-thumb& width=&909& data-original=&https://pic2.zhimg.com/v2-fcec8c707e07f0b3976f2e_r.jpg&&&/figure&&p&如果你加入了一家新公司,要为开发团队安装所需的软件并重启服务,这个时候首先要弄清楚它们运行在什么发行版以及哪个版本的系统上,你才能正确完成后续的工作。作为系统管理员,充分了解系统信息是首要的任务。&/p&&p&查看 Linux 发行版名称和版本号有很多种方法。你可能会问,为什么要去了解这些基本信息呢?&/p&&p&因为对于诸如 RHEL、Debian、openSUSE、Arch Linux 这几种主流发行版来说,它们各自拥有不同的包管理器来管理系统上的软件包,如果不知道所使用的是哪一个发行版的系统,在软件包安装的时候就会无从下手,而且由于大多数发行版都是用 systemd 命令而不是 SysVinit 脚本,在重启服务的时候也难以执行正确的命令。&/p&&p&下面来看看可以使用那些基本命令来查看 Linux 发行版名称和版本号。&/p&&h2&&b&方法总览&/b&&/h2&&ul&&li&&code&lsb_release&/code& 命令&/li&&li&&code&/etc/*-release&/code& 文件&/li&&li&&code&uname&/code& 命令&/li&&li&&code&/proc/version&/code& 文件&/li&&li&&code&dmesg&/code& 命令&/li&&li&YUM 或 DNF 命令&/li&&li&RPM 命令&/li&&li&APT-GET 命令&/li&&/ul&&h2&&b&方法 1: lsb_release 命令&/b&&/h2&&p&LSB( &i&Linux 标准库(Linux Standard Base)&/i&)能够打印发行版的具体信息,包括发行版名称、版本号、代号等。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.3 LTS
Release: 16.04
Codename: xenial
&/code&&/pre&&/div&&h2&&b&方法 2: /etc/*-release 文件&/b&&/h2&&p&release 文件通常被视为操作系统的标识。在 &code&/etc&/code& 目录下放置了很多记录着发行版各种信息的文件,每个发行版都各自有一套这样记录着相关信息的文件。下面是一组在 Ubuntu/Debian 系统上显示出来的文件内容。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# cat /etc/issue
Ubuntu 16.04.3 LTS \n \l
# cat /etc/issue.net
Ubuntu 16.04.3 LTS
# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION=&Ubuntu 16.04.3 LTS&
# cat /etc/os-release
NAME=&Ubuntu&
VERSION=&16.04.3 LTS (Xenial Xerus)&
ID_LIKE=debian
PRETTY_NAME=&Ubuntu 16.04.3 LTS&
VERSION_ID=&16.04&
HOME_URL=&http://www.ubuntu.com/&
SUPPORT_URL=&http://help.ubuntu.com/&
BUG_REPORT_URL=&http://bugs.launchpad.net/ubuntu/&
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
# cat /etc/debian_version
&/code&&/pre&&/div&&p&下面这一组是在 RHEL/CentOS/Fedora 系统上显示出来的文件内容。其中 &code&/etc/redhat-release&/code&和 &code&/etc/system-release&/code& 文件是指向 &code&/etc/[发行版名称]-release&/code& 文件的一个连接。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# cat /etc/centos-release
CentOS release 6.9 (Final)
# cat /etc/fedora-release
Fedora release 27 (Twenty Seven)
# cat /etc/os-release
NAME=Fedora
VERSION=&27 (Twenty Seven)&
VERSION_ID=27
PRETTY_NAME=&Fedora 27 (Twenty Seven)&
ANSI_COLOR=&0;34&
CPE_NAME=&cpe:/o:fedoraproject:fedora:27&
HOME_URL=&https://fedoraproject.org/&
SUPPORT_URL=&https://fedoraproject.org/wiki/Communicating_and_getting_help&
BUG_REPORT_URL=&https://bugzilla.redhat.com/&
REDHAT_BUGZILLA_PRODUCT=&Fedora&
REDHAT_BUGZILLA_PRODUCT_VERSION=27
REDHAT_SUPPORT_PRODUCT=&Fedora&
REDHAT_SUPPORT_PRODUCT_VERSION=27
PRIVACY_POLICY_URL=&https://fedoraproject.org/wiki/Legal:PrivacyPolicy&
# cat /etc/redhat-release
Fedora release 27 (Twenty Seven)
# cat /etc/system-release
Fedora release 27 (Twenty Seven)
&/code&&/pre&&/div&&h2&&b&方法 3: uname 命令&/b&&/h2&&p&uname(unix name 的意思) 是一个打印系统信息的工具,包括内核名称、版本号、系统详细信息以及所运行的操作系统等等。&/p&&ul&&li&&b&建议阅读:&/b& &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/check-find-determine-running-installed-linux-kernel-version/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&6种查看系统 Linux 内核的方法&/a&&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# uname -a
Linux localhost.localdomain 4.12.14-300.fc26.x86_64 #1 SMP Wed Sep 20 16:28:07 UTC
x86_64 x86_64 GNU/Linux
&/code&&/pre&&/div&&p&以上运行结果说明使用的操作系统版本是 Fedora 26。&/p&&h2&&b&方法 4: /proc/version 文件&/b&&/h2&&p&这个文件记录了 Linux 内核的版本、用于编译内核的 gcc 的版本、内核编译的时间,以及内核编译者的用户名。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# cat /proc/version
Linux version 4.12.14-300.fc26.x86_64 ([email protected]) (gcc version 7.2.1
(Red Hat 7.2.1-2) (GCC) ) #1 SMP Wed Sep 20 16:28:07 UTC 2017
&/code&&/pre&&/div&&h2&&b&方法 5: dmesg 命令&/b&&/h2&&p&dmesg( &i&展示信息(display message)&/i& 或 &i&驱动程序信息(driver message)&/i&)是大多数类 Unix 操作系统上的一个命令,用于打印内核的消息缓冲区的信息。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# dmesg | grep &Linux&
[ 0.000000] Linux version 4.12.14-300.fc26.x86_64 ([email protected]) (gcc version 7.2.1
(Red Hat 7.2.1-2) (GCC) ) #1 SMP Wed Sep 20 16:28:07 UTC 2017
[ 0.001000] SELinux: Initializing.
[ 0.001000] SELinux: Starting in permissive mode
[ 0.470288] SELinux: Registering netfilter hooks
[ 0.616351] Linux agpgart interface v0.103
[ 0.630063] usb usb1: Manufacturer: Linux 4.12.14-300.fc26.x86_64 ehci_hcd
[ 0.688949] usb usb2: Manufacturer: Linux 4.12.14-300.fc26.x86_64 ohci_hcd
[ 2.564554] SELinux: Disabled at runtime.
[ 2.564584] SELinux: Unregistering netfilter hooks
&/code&&/pre&&/div&&h2&&b&方法 6: Yum/Dnf 命令&/b&&/h2&&p&Yum( &i&Yellowdog 更新器修改版(Yellowdog Updater Modified)&/i&)是 Linux 操作系统上的一个包管理工具,而 &code&yum&/code& 命令被用于一些基于 RedHat 的 Linux 发行版上安装、更新、查找、删除软件包。&/p&&ul&&li&&b&建议阅读:&/b& &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&在 RHEL/CentOS 系统上使用 yum 命令管理软件包&/a&&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# yum info nano
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
* base: centos.zswap.net
* extras: mirror2.evolution-host.com
* updates: centos.zswap.net
Available Packages
Name : nano
Arch : x86_64
Version : 2.3.1
Release : 10.el7
Size : 440 k
Repo : base/7/x86_64
Summary : A small text editor
URL : http://www.nano-editor.org
License : GPLv3+
Description : GNU nano is a small and friendly text editor.
&/code&&/pre&&/div&&p&下面的 &code&yum repolist&/code& 命令执行后显示了 yum 的基础源仓库、额外源仓库、更新源仓库都来自 CentOS 7 仓库。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# yum repolist
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
* base: centos.zswap.net
* extras: mirror2.evolution-host.com
* updates: centos.zswap.net
repo id repo name status
base/7/x86_64 CentOS-7 - Base 9591
extras/7/x86_64 CentOS-7 - Extras 388
updates/7/x86_64 CentOS-7 - Updates 1929
repolist: 11908
&/code&&/pre&&/div&&p&使用 &code&dnf&/code& 命令也同样可以查看发行版名称和版本号。&/p&&ul&&li&&b&建议阅读:&/b& &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&在 Fedora 系统上使用 DNF(YUM 的一个分支)命令管理软件包&/a&&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# dnf info nano
Last metadata expiration check: 0:01:25 ago on Thu Feb 15 01:59:31 2018.
Installed Packages
Name : nano
Version : 2.8.7
Release : 1.fc27
Arch : x86_64
Size : 2.1 M
Source : nano-2.8.7-1.fc27.src.rpm
Repo : @System
From repo : fedora
Summary : A small text editor
URL : https://www.nano-editor.org
License : GPLv3+
Description : GNU nano is a small and friendly text editor.
&/code&&/pre&&/div&&h2&&b&方法 7: RPM 命令&/b&&/h2&&p&RPM( &i&红帽包管理器(RedHat Package Manager)&/i&)是在 CentOS、Oracle Linux、Fedora 这些基于 RedHat 的操作系统上的一个强大的命令行包管理工具,同样也可以帮助我们查看系统的版本信息。&/p&&ul&&li&&b&建议阅读:&/b& &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/rpm-command-examples/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&在基于 RHEL 的系统上使用 RPM 命令管理软件包&/a&&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# rpm -q nano
nano-2.8.7-1.fc27.x86_64
&/code&&/pre&&/div&&h2&&b&方法 8: APT-GET 命令&/b&&/h2&&p&Apt-Get( &i&高级打包工具(Advanced Packaging Tool)&/i&)是一个强大的命令行工具,可以自动下载安装新软件包、更新已有的软件包、更新软件包列表索引,甚至更新整个 Debian 系统。&/p&&ul&&li&&b&建议阅读:&/b& &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&在基于 Debian 的系统上使用 Apt-Get 和 Apt-Cache 命令管理软件包&/a&&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# apt-cache policy nano
Installed: 2.5.3-2ubuntu2
Candidate: 2.5.3-2ubuntu2
Version table:
* 2.5.3-2ubuntu2 500
500 http://nova.clouds.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages
100 /var/lib/dpkg/status
2.5.3-2 500
500 http://nova.clouds.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
&/code&&/pre&&/div&&hr&&p&via: &a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/check-find-linux-distribution-name-and-version/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&2daygeek.com/check-find&/span&&span class=&invisible&&-linux-distribution-name-and-version/&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&作者:&a href=&http://link.zhihu.com/?target=https%3A//www.2daygeek.com/author/magesh/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Magesh Maruthamuthu&/a& 译者:&a href=&http://link.zhihu.com/?target=https%3A//github.com/HankChow& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HankChow&/a& 校对:&a href=&http://link.zhihu.com/?target=https%3A//github.com/wxy& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&wxy&/a&&/p&&p&本文由 &a href=&http://link.zhihu.com/?target=https%3A//github.com/LCTT/TranslateProject& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LCTT&/a& 原创编译,&a href=&http://link.zhihu.com/?target=https%3A//linux.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux中国&/a& 荣誉推出&/p&
如果你加入了一家新公司,要为开发团队安装所需的软件并重启服务,这个时候首先要弄清楚它们运行在什么发行版以及哪个版本的系统上,你才能正确完成后续的工作。作为系统管理员,充分了解系统信息是首要的任务。查看 Linux 发行版名称和版本号有很多种方法…
&p&微信的大部分功能,如果只有100以内的并发用户,基本上100-200万就可以开发出来。&/p&&p&如果有1000个并发用户,基本上要500-1000万左右&/p&&p&如果有1万个并发用户,基本上要2000万以上的成本&/p&&p&如果有100万个并发用户,基本上要以10亿计的开发成本&/p&&p&如果有1000万个并发用户,基本上要以50亿计的开发成本&/p&&p&(我认为微信峰值大概也就是几千万的并发量)&/p&&p&如果有1个亿的并发用户,基本上要以2000亿计的开发成本&/p&&p&如果有10个亿的并发用户,抱歉,这个不是钱的问提,这个我觉得是神迹,估计目前搞不出来!&/p&&p&IT技术随着并发用户的增加,开发成本呈几何增长。&/p&&p&跑100米,在地球上能跑进12秒的,估计有上千万人,跑进11秒的估计几百万人,跑进10秒的估计有几十人,能跑进9秒的,估计就只有几十人了,能跑进8秒,现在人类还做不到,可以预计的未来也没有希望跑到。&/p&&p&IT技术也是这样的,实际上微信的并发支持能力,可以说是神迹,技术水平可能比造高铁更高,更复杂。&/p&&p&对了,相应的硬件设入,只会比软件投入高,不会低。&/p&&ol&&li&还有短信系统也是这个量级啊。&/li&&/ol&&p&回复:短信的解决方案是最传统的,就是靠增加服务器数量来解决问题,比如说A地发短信到B地,如果A的服务器处理能力不够,那么就增加A的地服务器就可以了,基本上就是靠数量解决问题。这种方案只适用A地和B地的数据没有交互,像微信可以搞6个人电话视频会议,这个就涉及到多地的数据同步问题,无法单靠数量解决,必须要有好的优化方案,同时微信步及到语音、视频、银行,图片,游戏等等交互模式,跟短信的差距就相当于自行车和飞机一样,完全不是一个概念。像这种能做出优化方案的人,收入最低也是千万一年的,人类世界能搞懂并且能搞出优化方案的,我个人估计不一定有100人&/p&&p&2. 这个架构肯定比微信差远了,但大概就是这个思路,理论上我们的爬虫可以爬取无限单位的2数据,只需要不断增加服务器和数据管理层。&/p&&p&回复:你这只是理论值,理论上一台式机也可支持10亿的人并发,只要你等得起。对于IT人员,如果是复杂应用,能搞出来支持500人的并发,性能非常好,基本上就可以属于大牛了,随便找份工作都是年薪50-80万了,2000人的并发就}

我要回帖

更多关于 飞禽饲养说明txt微盘 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信