qq空间权限破解网站限制访问破解

自己动手写分布式KV存储引擎(三):网络框架中的客户端实现原理
自己动手写分布式KV存储引擎系列文章的目标是记录基于LevelDB(RockDB)构建一个分布式KV存储引擎实现过程,此系列文章对应的源码在
本文主要分析了网络框架中客户端的实现原理,全文分为如下两部分
客户端功能需求
客户端实现
本系列的其他文章还包括:
客户端功能需求
在分布式系统中,一台服务器在与其他服务器交互的过程中,既扮演server端,也扮演client端,因此,网络框架中client端的实现也是至关重要的,一般地,网络框架中client端至少提供以下接口:
connect: 连接其他服务器,因为是服务端程序,需要高性能,因此,此操作必须是非阻塞的
read: 读server端发来的数据
write: 往server端写数据
客户端实现
针对网络框架中的客户端需要的各种接口,本节讨论其功能实现。
先来看看阻塞方式的connect,一般其用法如下
int ret = connect(fd, server_addr, server_len);
send(fd, data);
recv(fd, data);
阻塞的connect函数调用如下,其TCP状态转换如下图:
如上图所示,整个流程如下:
client端调用阻塞式connect,操作系统会向server端发送SYN数据包,并且client端的TCP状态会变成SYNC_SENT
server端调用accept接受connect请求,首先设置其TCP状态为SYNC_RCVD,然后会发送对server端的SYN包的确认包
client端接收到server端的确认包,操作系统将TCP状态设置成ESTABLISHED,这时候阻塞的connect函数返回,并且,操作系统会向服务端发送确认包
服务端在收到客户端的确认包之后,操作系统将TCP连接状态设置成ESTABLISHED,接着,服务端的accept调用返回
从上述调用流程可以看出,阻塞式的connect会等待收到服务端的确认包之后,才会返回,这中间的等待时间是一次网络包的往返时间,对于服务端程序来讲,阻塞在等待连接建立上是不能接受的,因此,必须采用非阻塞的connect。
非阻塞的connect的调用如下,其TCP状态转换如下图:
如上图所示,整个流程如下:
client端调用非阻塞的connect,操作系统会向server端发送SYN数据包,并且client端的TCP状态会变成SYNC_SENT,然后client端返回
server端调用accept接受connect请求,其首先设置其TCP状态为SYNC,发送对client端的SYN包的确认包,接着accept函数返回
client端收到server端的确认包之后,操作系统将其状态设置成ESTABLISHED,然后,向server端发送确认包
server端收到确认包之后,操作系统将其状态设置成ESTABLISHED
对于非阻塞的connect,没有了等待server端回确认包的过程,但是,网络框架需要处理的是,连接真正建立的时候需要通知应用程序来处理。
根据linux mannual文档,说明如下
EINPROGRESS
The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for
writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed success‐
fully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
如上说明,非阻塞connect之后,如果返回值是EINPROGRESS,那么需要用select或者epoll监听可写事件,然后,使用getsockopt来获取是否有错误,如果没有错误,说明连接建立成功,否则,连接建立失败。当然,如果返回值是0,说明在非阻塞的connect返回时,连接已经建立成功,这时候,跟处理阻塞式的connect是一样的。
整个非阻塞connect的实现在
,其中非阻塞connect调用是connect中完成。
read的实现与server端的read一致,这里就不再赘述了。
write的实现与server端的不同,需要根据不同情况来做不同的处理:
如果连接是处于连接中的状态,那么收到可写事件时,需要通过getsockopt函数来检查连接是否正确建立,并设置连接为已连接状态
如果连接是已连接的状态,那么收到可写事件时,则会尝试调用write往内核buffer中写数据
自己动手写分布式KV存储引擎的前三篇描述了如何设计和实现网络框架,接下来的文章将会关注如何基于网络框架设计和实现RPC库,敬请期待。
本博客更新会在第一时间推送到微信公众号,欢迎大家关注。2015年10月荣获微软MVP称号2014年10月荣获微软MVP称号2013年10月 荣获微软MVP称号2012年10月 荣获微软MVP称号2011年10月 荣获微软MVP称号2009年10月 荣获微软MVP称号2010年10月 荣获微软MVP称号2005年9月 荣获微软MVP称号2008年10月 荣获微软MVP称号2007年10月 荣获微软MVP称号2006年10月 荣获微软MVP称号
2016年9月 Windows专区大版内专家分月排行榜第一2014年4月 Windows专区大版内专家分月排行榜第一2013年8月 Windows专区大版内专家分月排行榜第一2013年7月 Windows专区大版内专家分月排行榜第一2013年5月 Windows专区大版内专家分月排行榜第一2013年4月 Windows专区大版内专家分月排行榜第一
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。什么是阻塞式和非阻塞io流 -
什么是阻塞式和非阻塞io流
Java中的阻塞和非阻塞IO包各自的优劣思考&
NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式。&反应器(Reactor):用于事件多路分离和分派的体系结构模式&通常的,对一个文件描述符指定的文件或设备, 有两种工作方式: 阻塞 与非阻塞 。所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待 状态, 直到有东西可读或者可写为止。而对于非阻塞状态, 如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等待 。&一种常用做法是:每建立一个Socket连接时,同时创建一个新线程对该Socket进行单独通信(采用阻塞的方式通信)。这种方式具有很高的响应速度,并且控制起来也很简单,在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。&另一种较高效的做法是:服务器端保存一个Socket连接列表,然后对这个列表进行轮询,如果发现某个Socket端口上有数据可读时(读就绪),则调用该socket连接的相应读操作;如果发现某个 Socket端口上有数据可写时(写就绪),则调用该socket连接的相应写操作;如果某个端口的Socket连接已经中断,则调用相应的析构方法关闭该端口。这样能充分利用服务器资源,效率得到了很大提高。&传统的阻塞式IO,每个连接必须要开一个线程来处理,并且没处理完线程不能退出。&非阻塞式IO,由于基于反应器模式,用于事件多路分离和分派的体系结构模式,所以可以利用线程池来处理。事件来了就处理,处理完了就把线程归还。而传统阻塞方式不能使用线程池来处理,假设当前有10000个连接,非阻塞方式可能用1000个线程的线程池就搞定了,而传统阻塞方式就需要开10000个来处理。如果连接数较多将会出现资源不足的情况。非阻塞的核心优势就在这里。&为什么会这样,下面就对他们做进一步细致具体的分析:&首先,我们来分析传统阻塞式IO的瓶颈在哪里。在连接数不多的情况下,传统IO编写容易方便使用。但是随着连接数的增多,问题传统IO就不行了。因为前面说过,传统IO处理每个连接都要消耗 一个线程,而程序的效率当线程数不多时是随着线程数的增加而增加,但是到一定的数量之后,是随着线程数的增加而减少。这里我们得出结论,传统阻塞式IO的瓶颈在于不能处理过多的连接。&然后,非阻塞式IO的出现的目的就是为了解决这个瓶颈。而非阻塞式IO是怎么实现的呢?非阻塞IO处理连接的线程数和连接数没有联系,也就是说处理10000个连接非阻塞IO不需要10000个线程,你可以用1000个也可以用2000个线程来处理。因为非阻塞IO处理连接是异步的。当某个连接发送请求到服务器,服务器把这个连接请求当作一个请求"事件",并把这个"事件"分配给相应的函数处理。我们可以把这个处理函数放到线程中去执行,执行完就把线程归还。这样一个线程就可以异步的处理多个事件。而阻塞式IO的线程的大部分时间都浪费在等待请求上了。&[b]引用自:
阻塞式IO就是在进行读写的时候调用了某个方法,如read()或write()方法&在该方法执行完之前,会一直等待,直到该方法执行完毕。所谓阻塞式IO流,就是指在从数据流当中读写数据的的时候,阻塞当前线程,直到IO流可以重新使用为止,你也可以使用流的avaliableBytes()函数看看当前流当中有多少字节可以读取,这样就不会再阻塞了。
Java codeimport&java.io.IOEimport&java.io.InputSimport&java.nio.ByteBimport&java.nio.channels.ReadableByteCpublic&class&ChannelInputStream&extends&InputStream {&&&private&ReadableByteC&&&public&ChannelInputStream(ReadableByteChannel channel)&throws&IllegalArgumentException {&&&&&if&(channel&==&null) {&&&&&&&throw&new&IllegalArgumentException("The readable byte channel is null");&&&& }&&&&&this.channel&=&&& }&&&public&int&read()&throws&IOException {&&&& ByteBuffer buffer&=&ByteBuffer.allocate(1);&&&&&int&result&=&channel.read(buffer);&&&&&if&(result&!=&-1) {&&&&&& buffer.flip();&&&&&& result&=&(int) buffer.get();&&&&&& buffer.clear();&&&& }&&&&&return&&& }&&&public&int&read(byte&b[])&throws&IOException {&&&& ByteBuffer buffer&=&ByteBuffer.allocate(b.length);&&&&&int&result&=&channel.read(buffer);&&&&&if&(result&!=&-1) {&&&&&& buffer.flip();&&&&&& buffer.get(b,&0, result);&&&&&& buffer.clear();&&&& }&&&&&return&&& }&&&public&int&read(byte&b[],&int&off,&int&len)&throws&IOException {&&&& ByteBuffer buffer&=&ByteBuffer.allocate(b.length);&&&&&int&result&=&channel.read(buffer);&&&&&if&(result&!=&-1) {&&&&&& buffer.flip();&&&&&& buffer.get(b, off, len&&&result&?&result : len);&&&&&& buffer.clear();&&&& }&&&&&return&&& }&&&public&void&close()&throws&IOException {&&&& channel.close();&& }}
更多相关文章
linux C socket编程 - 阻塞式与非阻塞式 阻塞和非阻塞 阻塞函数在完成其指定的任务以前不允许程序调用另一个函数.例如,程序执行一个读数据的函数调用时,在此函数完成读操作以前将不会执行下一程序语句.当服务器运行到accept语句时,而没有客户连接服务请求到来,服务器就会停止在accept ...
我们拿最常用的send和recv两个函数来说吧... 比如你调用send函数发送一定的Byte在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区它执行成功并不代表数据已经成功的发送出去了如果TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话 ...
同步和异步:与消息的通知机制有关. 本质区别 现实例子 同步模式 由处理消息者自己去等待消息是否被触发 我去银行办理业务,选择排队等,排到头了就办理. 异步模式 由触发机制来通知处理消息者 我去银行办理业务,取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务. 阻塞与非阻 ...
转自:/content/13/14.shtml 同步和异步:与消息的通知机制有关.
本质区别 现实例子 同步模式 由处理消息者自己去等待消息是否被触发 我去银行办理业务,选择排队等,排到头了就办理. 异步 ...
在Verilog中有两种类型的赋值语句:阻塞赋值语句(“=”)和非阻塞赋值语句(“&=”).正确地使用这两种赋值语句对于Verilog的设计和仿真非常重要. Verilog语言中讲的阻塞赋值与非阻塞赋值,但从字面意思来看,阻塞就是执行的时候在某个地方卡住了,等这个操作执行完在继续执行下面的语句 ...
(1)创建布局代码如下: &RelativeLayout xmlns:android ...
本篇实现基于ffmpeg动态库用测试程序播放本地文件和RTSP视频流. 参考文章:http ...
业务流程专家社区(Business Process Expert, BPX)的发展.因为成为业务流程专家的企业信息系统关键用户才是设计和创新的主体力量.
另外,在这个例子里,也可以体会到标准很重要.标准化是麦当 ...
关于为人处事 很多工作了很多年的人往往会对即将工作的年轻人说这么一句话&少说话,多 做事&.当时有很多人给我说过,我没有在意,到今天才真正知道这句话的分量! 很多初出茅庐的毕业生,新到单位,豪气凛 ...
有一个5*5的网格,其中恰好有一个格子是空的,其他格子各有一个字母.一共有4种指 令:A, ...
友情链接:
管理员邮箱:info@12.Tornado TCPServer类的设计解读 (副标题: 一个通用的server框架_Python_第七城市
12.Tornado TCPServer类的设计解读
(副标题: 一个通用的server框架
前文已经说过,HTTPServer是派生自TCPServer,从协议层次上讲,这再自然不过。
从TCPServer的实现上看,它是一个通用的server框架,基本是按照BSD socket的思想设计的。create-bind-listen三段式一个都不少。
从helloworld.py往下追,可以看到: helloworld.py中的main函数创建了HTTPServer. HTTPServer继承自TCPServer,在HTTPServer的构造函数中直接调用了TCPServer的构造函数。
接下来我们就去看看TCPServer这个类的实现,它的代码放在tornado/tcpserver.py中。tcpserver.py只有两百多行,不算多。所有代码都是在实现TCPServer这个类。TCPServer
在TCPServer类的注释中,首先强调了它是一个non-blocking, single-threaded TCP Server。
怎么理解呢?
non-blocking,就是说,这个服务器没有使用阻塞式API。
什么是阻塞式设计?举个例子,在BSD Socket里,recv函数默认是阻塞式的。使用recv读取客户端数据时,如果对方并未发送数据,则这个API就会一直阻塞那里不返回。这样服务器的设计不得不使用多线程或者多进程方式,避免因为一个API的阻塞导致服务器没法做其它事。阻塞式API是很常见的,我们可以简单认为,阻塞式设计就是“不管有没有数据,服务器都派API去读,读不到,API就不会回来交差”。
而非阻塞,对recv来说,区别在于没有数据可读时,它不会在那死等,它直接就返回了。你可能会认为这办法比阻塞式还要矬,因为服务器无法预知有没有数据可读,不得不反复派recv函数去读。这不是浪费大量的CPU资源么?
当然不会这么傻。tornado这里说的非阻塞要高级得多,基本上是另一种思路:服务器并不主动读取数据,它和操作系统合作,实现了一种“监视器”,TCP连接就是它的监视对象。当某个连接上有数据到来时,操作系统会按事先的约定通知服务器:某某号连接上有数据到来,你去处理一下。服务器这时候才派API去取数据。服务器不用创建大量线程来阻塞式的处理每个连接,也不用不停派API去检查连接上有没有数据,它只需要坐那里等操作系统的通知,这保证了recv API出手就不会落空。
tornado另一个被强调的特征是single-threaded,这是因为我们的“监视器”非常高效,可以在一个线程里监视成千上万个连接的状态,基本上不需要再动用线程来分流。实测表明,它比阻塞式多线程或者多进程设计更加高效——当然,这依赖于操作系统的大力配合,现在主流操作系统都提供了非常高端大气上档次的“监视器”机制,比如epoll、kqueue。
作者提到这个类一般不直接被实例化,而是由它派生出子类,再用子类实例化。
为了强化这个设计思想,作者定义了一个未直接实现的接口,叫handle_stream()。 这倒是个不错的技巧,强制让子类覆盖本方法,不然就报错给你看!
TCPServer是支持SSL的。由于Python的强大,支持SSL一点都不费事。要启动一个支持SSL的TCPServer,只需要告诉它你的certifile和keyfile就行。
关于这两个文件的来龙去脉,可以去Google“数字证书原理”这篇文章。TCPServer的三种形式
TCPServer的初始化有三种形式。
1. 单进程形式 我们在helloworld.py中看到的就是这种用法,不再赘述。
2. 多进程形式。 区别主要在server.start(0)这里。后面分析listen()与start()两个成员函数时,就会看到它们是怎么跟进程结合的。
注意:这种模式启动时,不能把IOLoop对象传递给TCPServer的构造函数,这样会导致TCPServer直接按单进程启动。
3. 高级多进程形式。
高级意味着复杂。从上面代码看,虽然只多了一两行,实际里面的流程有比较大的差别。
这种方式的主要优点就是 tornado.process.fork_processes(0)这句,它为进程的创建提供了更多的灵活性。当然现在说了也是糊涂,后面钻进这些代码后,我们再来验证这里的说法。
以上内容都是TCPServer类的doc string中提到的。后面小节开始看code。
最新教程周点击榜
微信扫一扫}

我要回帖

更多关于 qq空间访问密码破解 的文章

更多推荐

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

点击添加站长微信