精华内容
下载资源
问答
  • I/O多路复用

    2019-07-27 19:07:36
    为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象,为此,咱们来理解下复用在通信领域的使用,在通信领域中为了充分利用网络连接的物理介质,往往在同一条网络链路上采用...

    IO复用概念

    • IO复用:为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象,为此,咱们来理解下复用在通信领域的使用,在通信领域中为了充分利用网络连接的物理介质,往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义,即公用某个“介质”来尽可能多的做同一类(性质)的事,那IO复用的“介质”是什么呢?为此我们首先来看看服务器编程的模型,客户端发来的请求服务端会产生一个进程来对其进行服务,每当来一个客户请求就产生一个进程来服务,然而进程不可能无限制的产生,因此为了解决大量客户端访问的问题,引入了IO复用技术,即:一个进程可以同时对多个客户请求进行服务。也就是说IO复用的“介质”是进程(准确的说复用的是select和poll,因为进程也是靠调用select和poll来实现的),复用一个进程(select和poll)来对多个IO进行服务,虽然客户端发来的IO是并发的但是IO所需的读写数据多数情况下是没有准备好的,因此就可以利用一个函数(select和poll)来监听IO所需的这些数据的状态,一旦IO有数据可以进行读写了,进程就来对这样的IO进行服务。

    • 理解完IO复用后,我们在来看下实现IO复用中的三个API(select、poll和epoll)的区别和联系

    • select,poll,epoll都是IO多路复用的机制,I/O多路复用就是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知应用程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。三者的原型如下所示:

    1. int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

    2. int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    3. int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

    select

    select的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件,所以每次调用select前都需要重新初始化fdset。timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。

    select的调用步骤如下:

    (1)使用copy_from_user从用户空间拷贝fdset到内核空间

    (2)注册回调函数__pollwait

    (3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)

    (4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。

    (5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll 来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数 据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。

    (6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。

    (7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是 current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout 指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。

    (8)把fd_set从内核空间拷贝到用户空间。

    总结下select的几大缺点:

    (1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

    (2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

    (3)select支持的文件描述符数量太小了,默认是1024

    poll

    poll与select不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次。

    poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。poll返回后,需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。

    epoll

    直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

    epoll既然是对select和poll的改进,就应该能避免上述的三个缺点。那epoll都是怎么解决的呢?在此之前,我们先看一下epoll 和select和poll的调用接口上的不同,select和poll都只提供了一个函数——select或者poll函数。而epoll提供了三个函 数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注 册要监听的事件类型;epoll_wait则是等待事件的产生。

    对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定 EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝 一次。

    对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在 epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调 函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用 schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。

    对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子, 在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

    总结:

    (1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在 epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间,这就是回调机制带来的性能提升。

    (2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内 部定义的等待队列),这也能节省不少的开销。

    selectors选着IO多路复用

    #服务端
    from socket import *
    import selectors
    
    sel=selectors.DefaultSelector()
    def accept(server_fileobj,mask):
        conn,addr=server_fileobj.accept()
        sel.register(conn,selectors.EVENT_READ,read)
    
    def read(conn,mask):
        try:
            data=conn.recv(1024)
            if not data:
                print('closing',conn)
                sel.unregister(conn)
                conn.close()
                return
            conn.send(data.upper()+b'_SB')
        except Exception:
            print('closing', conn)
            sel.unregister(conn)
            conn.close()
    
    
    
    server_fileobj=socket(AF_INET,SOCK_STREAM)
    server_fileobj.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    server_fileobj.bind(('127.0.0.1',8088))
    server_fileobj.listen(5)
    server_fileobj.setblocking(False) #设置socket的接口为非阻塞
    sel.register(server_fileobj,selectors.EVENT_READ,accept) #相当于网select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept
    
    while True:
        events=sel.select() #检测所有的fileobj,是否有完成wait data的
        for sel_obj,mask in events:
            callback=sel_obj.data #callback=accpet
            callback(sel_obj.fileobj,mask) #accpet(server_fileobj,1)
    
    #客户端
    from socket import *
    c=socket(AF_INET,SOCK_STREAM)
    c.connect(('127.0.0.1',8088))
    
    while True:
        msg=input('>>: ')
        if not msg:continue
        c.send(msg.encode('utf-8'))
        data=c.recv(1024)
        print(data.decode('utf-8'))```
    
    
    展开全文
  • 题目里那些乱七八糟的名词都能在图里找到自己的位置了。 下面就是解释一下这张图了。 从IO开始讲吧,先简单解释一下IO。其实IO这个概念真的很杂容易混淆,我理解的IO是分两个大概念的,即网络IO和磁盘IO。网络IO...

    题目看上去真的很乱,写之前先贴一张写之前理出来的思路图:

    题目里那些乱七八糟的名词都能在图里找到自己的位置了。 下面就是解释一下这张图了。

    从IO开始讲吧,先简单解释一下IO。其实IO这个概念真的很杂容易混淆,我理解的IO是分两个大概念的,即网络IO和磁盘IO。网络IO就是socket网络数据传输,磁盘IO就是磁盘文件读写这些。上图中的IO理论思想在网络IO和磁盘IO中都可以适用的,因为这两个有很多共同之处。

    为什么有共同之处呢?可以这么理解。磁盘IO就是文件读写嘛,文件是在磁盘上的要读到内存中,必然会涉及用户态和内核态,这里就不解释用户态和内核态了,理解起来就是用户态问内核态要数据,那用户态就是调用方,内核态就是被调用方。而网络IO也很相似啊,网络IO最简单的理解就是一个接口被调用了,总之会有一个socket连接过来,让被调用的服务去干嘛干嘛,就可以理解为这个socket连接是调用方,被调用的服务当然就是被调用方了。画了一张图总结一下:

    我们所说的IO通常意义上是指磁盘IO的输入/输出流,即I/O流。其实在磁盘IO体系中不止有流式部分,还有非流式部分,贴两张网上的图:

     

    所以,这么一顿分析下来,一般我们打交道比较多的就是磁盘IO流式部分了,而这么长的名字平时我们只说IO,有点搞混的。当然网络IO和磁盘IO的区分界限也没有那么清楚,比如字节流字符流用于文件读写没有问题,但是网络IO中也避免不了使用字节流啊,这就看个人理解了。

    上面是理了一下IO,接下来解释一下同步/异步和阻塞/非阻塞。

    还是看上面调用方和被调用方那张图,记住关键的一点,同步/异步是描述调用方是否等待调用结果返回的,阻塞/非阻塞是描述被调用方线程状态的。

    拿磁盘IO举例:

    同步阻塞IO就是用户态的线程发起read()/write()调用后,会一直等待调用结果返回,而在内核态,要去读一个磁盘文件,数据不一定立马就能准备好啊,同步阻塞IO就是内核态的线程会一直能数据准备好再去读。盗张图贴一下:

    同步非阻塞IO同理用户态发起read()/write()调用后,也会一直等待调用结果返回,但是在内核态,如果数据没有准备好,内核态的线程可不会等着,就直接干别的去了,那就需要用户态的线程一直去询问数据有没有处理好啊,一直问一直问这个就叫轮询。再贴一张图:

     那什么是IO多路复用呢?可以看出同步非阻塞IO是需要用户态要有一个线程不停地去轮询的,这就很消耗CPU资源啊,用户态就很不乐意了,就在想能不能这个轮询的让内核态自己去做就好了,这就是IO多路复用了。所以IO多路复用是在同步非阻塞IO基础上的一次演进,即IO多路复用也必然是同步非阻塞IO。这个轮询的活是就是select、poll和或者epoll这三个机制来完成的,也就是select、poll和或者epoll这三个是内核态的系统调用,三种不同的方式去找到准备好的数据。需要注意的是select和poll是轮询的方式去找到准备好的数据,epoll已经不用轮询了,这个后面会说。既然都是在内核态找到准备好的数据了,更接近OS底层的调用性能也必然是比在用户态的时候好,既然这样,那何必只去找用户态某一个线程需要的数据呢,那就替用户态所有干等着的线程找准备好的数据吧,这就是多路复用这个词的来源。

    上面是在磁盘IO理解了同步阻塞IO、同步非阻塞IO和多路复用IO,那么在网络IO怎么理解呢?

    对于网络IO,同步阻塞IO不用说了,一个socket连接过来了,里面的数据并不一定准备好了,如果被调用服务的线程在干等着socket中的数据准备好,那就是同步阻塞IO。如果这个服务线程不等呢?而是去询问其他socket连接中的数据有没有准备好,那这就是同步非阻塞IO。

    网络IO和磁盘IO的同步非阻塞IO的理解还是有点区别的,磁盘IO的同步非阻塞的轮询操作是由调用方去做的,而且轮询的是被调用方,但是网络IO的同步非阻塞总不能让调用方去轮询吧,难不成还一遍一遍的socket连接过来?所以只能被调用方去轮询,而且轮询的是调用方即一组socket连接,所以网络IO的同步非阻塞IO也可以成为是IO多路复用,即是被调用方在轮询又有多路复用这个概念在里面啊。

    JAVA NIO是NIO思想在JAVA领域的实现,所以很多人说JAVA NIO是多路复用IO也没什么问题。既然是NIO思想在JAVA领域的实现,必然在网络IO和磁盘IO都是可用的。在网络IO应用的关键词就是Selector,即一组socket连接注册到上面。在磁盘IO的应用关键字就是FileChannel文件通道和Buffer缓冲区,也是用了select、poll或者epoll这一套。

    理清了上面这些概念,然后就可以了解一下select、poll和epoll。

    1.select

    select函数就是上面说的,做了遍历轮询的活,不止替一个用户态线程找准备好的数据,而是把很多个文件描述符fd放进一个set集合中遍历,就是替多个用户态线程找准备好的数据。当然,既然是set集合那就有数量上限,32位机器上默认是1024个,64位机器上默认是2048个。贴一张图:

    时间复杂度:O(n)

    select的缺点:

    (1)单进程可以打开fd有限制;

    (2)对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低;

    (3)用户空间和内核空间的复制非常消耗资源;

    2.poll

    其实poll调用过程和select一样,只不过采用链表的方式替换select的set集合去存储fd,这样连接数就没有限制了。时间复杂度同样为O(n)。

    3.epoll

    应用示例:Nginx。

    epoll就不像前面两个把fd放进一个集合里去遍历了,而是采用注册回调函数,在文件描述就绪的时候网卡驱动会去触发这个回调函数,通知说这个fd的数据已经准备好了,这就很nice了。贴一下图:

    这样就既没有连接数限制,又不用去遍历轮询消耗CPU。而且时间复杂度为O(1)。 

    epoll有两种工作方式:1.水平触发(LT)2.边缘触发(ET) 
    LT模式:若就绪的事件一次没有处理完要做的事件,就会一直去处理。即就会将没有处理完的事件继续放回到就绪队列之中(即那个内核中的链表),一直进行处理。 
    ET模式:就绪的事件只能处理一次,若没有处理完会在下次的其它事件就绪时再进行处理。而若以后再也没有就绪的事件,那么剩余的那部分数据也会随之而丢失。 
    由此可见:ET模式的效率比LT模式的效率要高很多。只是如果使用ET模式,就要保证每次进行数据处理时,要将其处理完,不能造成数据丢失,这样对编写代码的人要求就比较高。 
    需要注意的是,ET模式只支持非阻塞的读写:为了保证数据的完整性。

    到这里IO的同步模型就梳理得差不多了,还有一个异步模型。

    按刚刚的理解,异步模型是需要调用方发起调用动作后就不等了,去干别的事。而我们平常的编程,代码是一行一行写下来,运行的时候也是一个线程一行一行的执行下来,这行的结果没出来呢线程也不会去干别的事,所以我们日常的编程都是同步编程,是做不到真正的异步IO的。顾名思义异步IO需要特殊的异步编程语法,现在有的就是协程,这已经涉及我的知识盲区了,就不继续写了。

    展开全文
  • 题目看上去真的很乱,写之前先贴一张写之前理出来的思路图: 题目里那些乱七八糟的名词都能在图里找到自己的位置了。 下面就是解释一下这张图了。从IO开始讲吧,先简单解释一下IO。其实IO这个概念真的很杂容易混淆,...

    题目看上去真的很乱,写之前先贴一张写之前理出来的思路图:

    2e658669c5a766a6992789069331a2df.png

    题目里那些乱七八糟的名词都能在图里找到自己的位置了。 下面就是解释一下这张图了。

    从IO开始讲吧,先简单解释一下IO。其实IO这个概念真的很杂容易混淆,我理解的IO是分两个大概念的,即网络IO和磁盘IO。网络IO就是socket网络数据传输,磁盘IO就是磁盘文件读写这些。上图中的IO理论思想在网络IO和磁盘IO中都可以适用的,因为这两个有很多共同之处。

    为什么有共同之处呢?可以这么理解。磁盘IO就是文件读写嘛,文件是在磁盘上的要读到内存中,必然会涉及用户态和内核态,这里就不解释用户态和内核态了,理解起来就是用户态问内核态要数据,那用户态就是调用方,内核态就是被调用方。而网络IO也很相似啊,网络IO最简单的理解就是一个接口被调用了,总之会有一个socket连接过来,让被调用的服务去干嘛干嘛,就可以理解为这个socket连接是调用方,被调用的服务当然就是被调用方了。画了一张图总结一下:

    0ce8e59924876bcdd7fb83ae7b16b6fc.png

    我们所说的IO通常意义上是指磁盘IO的输入/输出流,即I/O流。其实在磁盘IO体系中不止有流式部分,还有非流式部分,贴两张网上的图:

    f7748d65978d351d500daf98198758d2.png

    f099cb3510303414d010453ec48da107.png

    所以,这么一顿分析下来,一般我们打交道比较多的就是磁盘IO流式部分了,而这么长的名字平时我们只说IO,有点搞混的。当然网络IO和磁盘IO的区分界限也没有那么清楚,比如字节流字符流用于文件读写没有问题,但是网络IO中也避免不了使用字节流啊,这就看个人理解了。

    上面是理了一下IO,接下来解释一下同步/异步和阻塞/非阻塞。

    还是看上面调用方和被调用方那张图,记住关键的一点,同步/异步是描述调用方是否等待调用结果返回的,阻塞/非阻塞是描述被调用方线程状态的。

    拿磁盘IO举例:

    同步阻塞IO就是用户态的线程发起read()/write()调用后,会一直等待调用结果返回,而在内核态,要去读一个磁盘文件,数据不一定立马就能准备好啊,同步阻塞IO就是内核态的线程会一直能数据准备好再去读。盗张图贴一下:

    f9362a4f63423ed53647a3cd80e65e1e.png

    同步非阻塞IO同理用户态发起read()/write()调用后,也会一直等待调用结果返回,但是在内核态,如果数据没有准备好,内核态的线程可不会等着,就直接干别的去了,那就需要用户态的线程一直去询问数据有没有处理好啊,一直问一直问这个就叫轮询。再贴一张图:

    752f5d261cbd7790da14af41152159ba.png

    那什么是IO多路复用呢?可以看出同步非阻塞IO是需要用户态要有一个线程不停地去轮询的,这就很消耗CPU资源啊,用户态就很不乐意了,就在想能不能这个轮询的让内核态自己去做就好了,这就是IO多路复用了。所以IO多路复用是在同步非阻塞IO基础上的一次演进,即IO多路复用也必然是同步非阻塞IO。这个轮询的活是就是select、poll和或者epoll这三个机制来完成的,也就是select、poll和或者epoll这三个是内核态的系统调用,三种不同的方式去找到准备好的数据。需要注意的是select和poll是轮询的方式去找到准备好的数据,epoll已经不用轮询了,这个后面会说。既然都是在内核态找到准备好的数据了,更接近OS底层的调用性能也必然是比在用户态的时候好,既然这样,那何必只去找用户态某一个线程需要的数据呢,那就替用户态所有干等着的线程找准备好的数据吧,这就是多路复用这个词的来源。

    上面是在磁盘IO理解了同步阻塞IO、同步非阻塞IO和多路复用IO,那么在网络IO怎么理解呢?

    对于网络IO,同步阻塞IO不用说了,一个socket连接过来了,里面的数据并不一定准备好了,如果被调用服务的线程在干等着socket中的数据准备好,那就是同步阻塞IO。如果这个服务线程不等呢?而是去询问其他socket连接中的数据有没有准备好,那这就是同步非阻塞IO。

    网络IO和磁盘IO的同步非阻塞IO的理解还是有点区别的,磁盘IO的同步非阻塞的轮询操作是由调用方去做的,而且轮询的是被调用方,但是网络IO的同步非阻塞总不能让调用方去轮询吧,难不成还一遍一遍的socket连接过来?所以只能被调用方去轮询,而且轮询的是调用方即一组socket连接,所以网络IO的同步非阻塞IO也可以成为是IO多路复用,即是被调用方在轮询又有多路复用这个概念在里面啊。

    JAVA NIO是NIO思想在JAVA领域的实现,所以很多人说JAVA NIO是多路复用IO也没什么问题。既然是NIO思想在JAVA领域的实现,必然在网络IO和磁盘IO都是可用的。在网络IO应用的关键词就是Selector,即一组socket连接注册到上面。在磁盘IO的应用关键字就是FileChannel文件通道和Buffer缓冲区,也是用了select、poll或者epoll这一套。

    理清了上面这些概念,然后就可以了解一下select、poll和epoll。

    1.select

    select函数就是上面说的,做了遍历轮询的活,不止替一个用户态线程找准备好的数据,而是把很多个文件描述符fd放进一个set集合中遍历,就是替多个用户态线程找准备好的数据。当然,既然是set集合那就有数量上限,32位机器上默认是1024个,64位机器上默认是2048个。贴一张图:

    8e0543c4b46095fae6553e9d988aebaf.png

    时间复杂度:O(n)

    select的缺点:

    (1)单进程可以打开fd有限制;

    (2)对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低;

    (3)用户空间和内核空间的复制非常消耗资源;

    2.poll

    其实poll调用过程和select一样,只不过采用链表的方式替换select的set集合去存储fd,这样连接数就没有限制了。时间复杂度同样为O(n)。

    3.epoll

    epoll就不像前面两个把fd放进一个集合里去遍历了,而是采用注册回调函数,在文件描述就绪的时候网卡驱动会去触发这个回调函数,通知说这个fd的数据已经准备好了,这就很nice了。贴一下图:

    04f711d1cc5067b18b13ad92a72da6b1.png

    这样就既没有连接数限制,又不用去遍历轮询消耗CPU。而且时间复杂度为O(1)。

    epoll有两种工作方式:1.水平触发(LT)2.边缘触发(ET)

    LT模式:若就绪的事件一次没有处理完要做的事件,就会一直去处理。即就会将没有处理完的事件继续放回到就绪队列之中(即那个内核中的链表),一直进行处理。

    ET模式:就绪的事件只能处理一次,若没有处理完会在下次的其它事件就绪时再进行处理。而若以后再也没有就绪的事件,那么剩余的那部分数据也会随之而丢失。

    由此可见:ET模式的效率比LT模式的效率要高很多。只是如果使用ET模式,就要保证每次进行数据处理时,要将其处理完,不能造成数据丢失,这样对编写代码的人要求就比较高。

    需要注意的是,ET模式只支持非阻塞的读写:为了保证数据的完整性。

    到这里IO的同步模型就梳理得差不多了,还有一个异步模型。

    按刚刚的理解,异步模型是需要调用方发起调用动作后就不等了,去干别的事。而我们平常的编程,代码是一行一行写下来,运行的时候也是一个线程一行一行的执行下来,这行的结果没出来呢线程也不会去干别的事,所以我们日常的编程都是同步编程,是做不到真正的异步IO的。顾名思义异步IO需要特殊的异步编程语法,现在有的就是协程,这已经涉及我的知识盲区了,就不继续写了。

    展开全文
  • 3、表1与表2名词解释 二、通讯信息传输过程 1.1地址码 1.2功能码 1.3数据区 三、MODBUS功能码 3.1功能码“02”:读1路或多路开关量输入状态 3.2功能码“01”:读1路或多路开关量输出状态 3.3功能码“03”:...
    目录:
    一、简介
    1、简介
    2、简单理解MODBUS通信协议
    3、表1与表2名词解释
    二、通讯信息传输过程
    1.1 地址码
    1.2 功能码
    1.3 数据区
    三、MODBUS功能码
    3.1 功能码“02”:读1路或多路开关量输入状态
    3.2 功能码“01”:读1路或多路开关量输出状态
    3.3 功能码“03”:读多路寄存器输入
    3.4 功能码“05”:写1路开关量输出(遥控)
    3.5 功能码“06”:写单路寄存器
    3.6 功能码“10”:写多路寄存器
    3.7 功能码“03”:读事件记录
    四、错误校验码(CRC校验)
    五、通讯错误信息及数据的处理
    -------------------------------------------------------
    相关参考搜索我的百度网盘“Modbus-国家标准-完整版、ModBus_RTU通讯自定义范例和Modbus TCP_IP协议规范”。
     
    --------------------------------------------------------------------------------------------------------------
    一、简介
    1、简介
    ModBus通讯规约允许PDM系列仪表/变送器与施耐德、西门子、AB、GE等多个国际著名品牌的可编程顺序控制器(PLC)、RTU、SCADA系统、DCS或与第三方具有ModBus兼容的监控系统之间进行信息交换和数据传送。
    PDM系列仪表/变送器只要简单地增加一套基于计算机(或工控机)的监控软件(如:组态王、Intouch、FIX、synall等)就可以构成一套电力监控系统。
    ModBus通讯规约有两种传送方式:RTU和ASCII
    ModBus TCP/IP是RTU模式的延伸:基于ModBus以太网
     
    ----------------------------
    广泛的系统集成:
    PDM系列仪表/变送器提供了标准的RS-485/422通讯接口及ModBus通讯协议,这个通讯协议已广泛被国内外电力行业及工控行业作为系统集成的标准。
    ----------------------------
    通讯数据的类型及格式:
     ●信息传输为异步方式,并以字节为单位。在主站和从站之间传递的通讯信息是11位的字格式:
     
    字格式(串行数据)
    11位二进制
    起始位
    1位
    数据位
    8位
    奇偶校验位
    1位:有奇偶校验位/无:无奇偶校验位
    停止位
    1位:有奇偶校验位/2位:无奇偶校验位
     
     ● 通讯数据(信息帧)格式
     
    数据格式:
    地址码
    功能码
    数据区
    错误校检
     
    数据长度:
    1字节
    1字节
    N字节
    16位CRC码(冗余循环码)
     
    ★ 注:1)1个字节由8位二进制数组成(既8 bit)
       2)ModBus是Modicon公司的注册商标
       3)“从机”在本文件中既为PDM
    ----------------------------
     
    判断Modbus一帧数据结束的方法:在RTU方式下,ModBus协议是根据3.5个字符时间内有没有接收数据来判断是否接受完成。
     
    串行数据一般采用11位的字格式,那么3.5个字符就是3.5*11=38.5位。如果没有校验位,采用10位的字格式,那么3.5个字符就是
     
    3.5*10=35位。
     
    波特率是每秒传输的二进制位的个数,比如9600bps,即每1秒传输9600位,那么传输38.5个二进制位需要的时间:
     
    38.5/9.6=4.0104167mS,Modbus_RTU要求一帧数据起始到结束至少要不小于3.5个字符时间。
     
    先给定时器定时大概3.5个字符(更大点也可以),然后在串口的接收中断服务程序中,先将定时器的计数寄存器清零,然后重新开
     
    始定时,如果接收的不是最后一个字节,那么在下个字节来的时候定时器就会又从零开始计数,如果后面再没有数据进来的话,定
     
    时器就会因为定时时间到而进入定时器中断,就表示数据接收结束了。
     
    -------------------------------------------------------
    2、简单理解MODBUS通信协议
    对于01 16 1000 1234 ABCD这段代码的含义说明如下:
     
    向地址 01的控制器1000地址处写入1234 。
     
    地址域:就是指 从站的地址,比如一个仪表,这个地址就是它的通讯地址;
     
    功能码:就是你要做的事情,通讯的目的 就是读写数据,所以 ModBus 功能码虽然很多,但是只有两个是我们常用的,就是读和
     
    写。读的功能码是03,写的功能码是16。注意,这里的读写都是一次性写16个位,也就是一个WORD(包含数据地址与数据)
     
    功能码如表2。
    ----------------------------
    表1、ModBus功能码
    功能码 名称 作用
    1 0x01 读取线圈状态 取得一组逻辑线圈的当前状态(ON/OFF)
    2 0x02 读取输入状态 取得一组开关输入的当前状态(ON/OFF)
    3 0x03 读取保持寄存器 在一个或多个保持寄存器中取得当前的二进制值
    4 0x04 读取输入寄存器 在一个或多个输入寄存器中取得当前的二进制值
    5 0x05 强置单线圈 强置一个逻辑线圈的通断状态
    6 0x06 预置单寄存器 把具体二进值装入一个保持寄存器
    7 0x07 读取异常状态 取得8个内部线圈的通断状态,这8个线圈的地址由控制器决定,用户逻辑可以将这些线圈定义,以说明从机状态,短报文适宜于迅速读取状态。
    8 0x08 回送诊断校验 把诊断校验报文送从机,以对通信处理进行评鉴。
    9 0x09 编程(只用于484) 使主机模拟编程器作用,修改PC从机逻辑。
    10 0x0A 控询(只用于484) 可使主机与一台正在执行长程序任务从机通信,探询该从机是否已完成其操作任务,仅在含有功能码9的报文发送后,本功能码才发送。
    11 0x0B 读取事件计数 可使主机发出单询问,并随即判定操作是否成功,尤其是该命令或其他应答产生通信错误时。
    12 0x0C 读取通信事件记录 可是主机检索每台从机的ModBus事务处理通信事件记录(比如传送53条报文)。如果某项事务处理完成,记录会给出有关错误。
    13 0x0D 编程(184/384 484 584) 可使主机模拟编程器功能修改PC从机逻辑
    14 0x0E 探询(184/384 484 584) 可使主机与正在执行任务的从机通信,定期控询该从机是否已完成其程序操作,仅在含有功能13的报文发送后,本功能码才得发送。
    15 0x0F 强置多线圈 强置一串连续逻辑线圈的通断。
    16 0x10 预置多寄存器 把具体的二进制值装入一串连续的保持寄存器。
    17 0x11 报告从机标识 可使主机判断编址从机的类型及该从机运行指示灯的状态。
    18 0x12 (884和MICRO 84) 可使主机模拟编程功能,修改PC状态逻辑。
    19 0x13 重置通信链路 发生非可修改错误后,是从机复位于已知状态,可重置顺序字节。
    20 0x14 读取通用参数(584L) 显示扩展存储器文件中的数据信息。
    21 0x15 写入通用参数(584L) 把通用参数写入扩展存储文件,或修改之。
    22~64 保留作扩展功能备用  
    65~72 保留以备用户功能所用 留作用户功能的扩展编码
    73~119 非法功能  
    120~127 保留 留作内部作用
    128~255 保留 用于异常应答
    ----------------------------
    表2、ModBus功能码与数据类型对应表
    代码 功能 数据类型
    1
    2
    3 整型、字符型状态字浮点型
    4 整型、状态字、浮点型
    5
    6 整型、字符型、状态字、浮点型
    8 N/A 重复“回路反馈”信息
    15
    16 整型、字符型、状态字、浮点型
    ----------------------------
    表3、Modbus寄存器
    寄存器种类 说明 PLC类比 举例说明
    离散输入
    状态DI
    输入端口。通过外部设定改变输入状态,可读但不可写 DI数字量输入 面板上的按键、开关状态,电机的故障状态
    线圈状态DO 输出端口。可设定端口的输出状态,也可以读取该位的输出状态,可分为两种不同的执行状态,例如保持型或边沿触发型 DO数字量
    输出
    电磁阀输出、电机的启停控制信号、
    LED显示等
    保持
    寄存器AO
    输出参数或保持参数,控制器运行时被设定的某些参数。
    可读可写
    AO模拟量 模拟量输出设定值,PID运行参数
     
     
    输入
    寄存器AI
    输入参数。控制器运行时从外部设备获得的参数。
    可读但不可写
    AI模拟量输入 模拟量输入
    Modbus协议定义了4种基本数据类型:只读位数据DI可读写位数据DO只读16位数据AI可读写16位数据AO这些数据分别被称为输入状态线圈状态输入寄存器保持寄存器
    DI 数字输入,离散输入,一个地址一个数据位,用户只能读取它的状态,不能修改。
    比如面板上的按键、开关状态,电机的故障状态
    DO 数字输出,线圈输出,一个地址一个数据位,用户可以置位、复位,可以回读状态。
    比如电磁阀输出,电机的启停控制信号、LED显示等
    AI 模拟输入,输入寄存器,一个地址16位数据,用户只能读,不能修改,比如一个电压值的读数
    AO 模拟输出,保持寄存器,一个地址16位数据,用户可以写,也可以回读,比如一个控制变频器的电流值
     
    无论这些东西被叫做什么名字,其内容不外乎这几种,输入的信号用户只能看不能改,输出的信号用户控制,并可以回读。离散的
    数据只有一位,模拟的数据有16位。
     
    ----------------------------
     
    数据 就是我们传递的消息,这个对于我们来说才是最终目的。 1000 1234 就是我们传递的消息,是我们要告诉从站的内容,它又
     
    分两部分:地址和内容。如果把从站比喻成一个大楼地址域就是大楼的门牌号,而数据里的地址就是大楼的房间号,换成变频器也
     
    就是变频器的参数地址。所以这段帧 就是这样理解:告诉01大楼的1000房间,1234 往01变频器的1000参数写1234。差错校验:
     
    是为了防止出错而做的保护,就是双方约定的各种计算方法,也就是我们在实际应用中的偶校验、奇校验、停止位等等。 这里的
     
    ABCD 是随便写的,没任何意义。
     
    -------------------------------------------------------
    3、表1与表2名词解释
    1)功能码含义
    读:
    01_DI:  读内部比特量输出状态,如告警、变位、故障、异常等。
    02_DO:读外部开关量输入状态,如光耦输入、继电器输入等。
    03_AO:读内部输出量的寄存器,如一些配置参数、定值的读取等。
    04_AI:  读外部输入量的寄存器,如外部电压电流模拟量,温湿度等。
    功能码01、02读到的位满8个组合成一个字节,可以用功能码04读取;线圈可以直接定义成一个位变量或者直接置某变量的某一位
     
    写:
    功能码05:写内部单个开关量状态;如光耦输出、继电器输出等。
    功能码06:写内部单个寄存器的值;如更改配置参数、定值等。
    功能码15:写内部多个开关量状态;如同05。
    功能码16:写内部多个寄存器的值;如同06;对时是写多个寄存器,用此功能码。
     
    11:通信超时或错误时询问用
    12:询问从机检测到的各种故障、异常事件
    ----------------------------
    2)关于实现
    先定义一个变量区如: uint modbus_data [50],再定义那些保持寄存器和输入寄存器,如下:
    保持寄存器:M30001-M300022  // 存放设置的参数,用 03读,16写
    输入寄存器:M40001-M40028  // 存放实时数据,如启动、运行、停止、待机以及错误代码 ,用04读

    #define M30001  modbus_data[0]
     
    #define M30002  modbus_data[1]

    …………

    #define M30021  modbus_data[20]

    #define M30022  modbus_data[21]

    #define M40001  modbus_data[22]

    #define M40002  modbus_data[23]

    …………

    #define M400021  modbus_data[48]
     
    #define M400028  modbus_data[49]
     
     
    --------------------------------------------------------------------------------------------------------------
    二、通讯信息传输过程
     
    当通讯命令由发送设备(主机)发送至接收设备(从机)时,符合相应地址码的从机接收通讯命令,并根据功能码及相关要求读取信息,如果CRC校验无误,则执行相应的任务,然后把执行结果(数据)返送给主机。返回的信息中包括地址码、功能码、执行后的数据以及CRC校验码,如果CRC校验出错就不返回任何信息。
     
    1.1 地址码
     
           地址码是每次通讯信息帧的第一字节(8位),从0到255。这个字节表明由用户设置地址的从机将接收由主机发送来的信息。每个从机都必须有唯一的地址码,并且只有符合地址码的从机才能响应回送信息。当从机回送信息时,回送数据均以各自的地址码开始。主机发送的地址码表明将发送到的从机地址,而从机返回的地址码表明回送的从机地址。相应的地址码表明该信息来自于何处。
    -------------------------------------------------------
     
    1.2 功能码
     
           功能码是每次通讯信息帧传送的第二个字节。ModBus通讯规约可定义的功能码为1到127。PDM系列仪表/变送器仅用到其中的一部分功能码。作为主机请求发送,通过功能码告诉从机应执行什么动作。作为从机响应,从机返回的功能码与从主机发送来的功能码一样,并表明从机已响应主机并且已进行相关的操作。
     
    表1 Modbus部分功能码
     
    功能码
    定 义
    操 作(二进制)
    0x02
    读开关量输入
    读取一路或多路开关量状态输入数据
    0x01
    读开关量输出
    读取一路或多路开关量输出状态数据
    0x03
    读寄存器数据
    读取一个或多个寄存器的数据
    0x05
    写开关量输出
    控制一路继电器“合/分”输出
    0x06
    写单路寄存器
    把一组二进制数据写入单个寄存器
    0x10
    写多路寄存器
    把多组二进制数据写入多个寄存器
     
    -------------------------------------------------------
    1.3 数据区
     
    数据区包括需要由从机返送何种信息或执行什么动作。这些信息可以是数据(如:开关量输入/输出、模拟量输入/输出、寄存器等等)、参考地址等。例如,主机通过功能码03告诉从机返回寄存器的值(包含要读取寄存器的起始地址及读取寄存器的长度),则返回的数据包括寄存器的数据长度及数据内容。对于不同的从机,地址和数据信息都不相同(应给出通讯信息表)。
     
    PDM 系列仪表/变送器采用Modbus通讯规约,主机(PLC、RTU、PC机、DCS等)利用通讯命令(功能码03),可以任意读取其数据寄存器(其数据信息表详见附录)。PDM系列仪表/变送器的数据寄存器存储的电量多达几百个(如:电流、电压、功率、0~31次谐波分量等),并且都是16位(2字节)的二进制数据,并且高位在前;一次最多可读取寄存器数(既各种电量的数量)是50个。
     
    PDM响应的命令格式是从机地址、功能码、数据区及CRC码。数据区的数据都是两个字节,并且高位在前(电能量除外)。
     
    注:1PDM-820AC/ACM/ACRPDM-800AC/ACM具有“03”、“06”、“10”功能码;
           2、如果PDM采用MODBUS ASCII通讯协议,其通讯数据格式为;7个数据位,1停止位,偶校验。
     
    --------------------------------------------------------------------------------------------------------------
    三、MODBUS功能码
     
    3.1 功能码“02:读1路或多路开关量输入状态
     
    例如:主机要读取地址为01,开关量DI1—DI4的输入状态。读取告警、变位、故障、异常等。
    从机(PDM)数据寄存器的地址和数据为:
    起始位地址
    DI寄存器数据(16进制)
    备 注
    0000
    0B
    DI1/DI2/DI4状态为“1”,DI3状态为
    “0”
     
    主机发送的报文格式为:
    主机发送
    字节数
    发送的信息
    备 注
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    02   
    读开关量输入状态
    起始BIT位
    2
    0000 
    起始BIT位地址为0000
    读数据长度
    2
    0004 
    读取4路开关量输入状态位
    CRC码
    2
    79C9
    由主机计算得到CRC码
     
     
    从机(PDM)响应返回的报文格式:
     
    从机响应
    字节数
    返回的信息
    备 注
    从机地址
    1
    01  
    来自从机01
    功能码
    1
    02   
    读开关量输入状态
    数据长度
    1
    01   
    1个字节(8个BIT位)
    DI状态数据
    1
    0B
    DI寄存器内容
    CRC码
    2
    E04F 
    由从机计算得到CRC码
    -------------------------------------------------------
    3.2 功能码“01:读1路或多路开关量输出状态
     
    例如:主机要读取地址为01,开关量DO1,DO2的输出状态。读取电磁阀输出、电机的启停控制信LED显示等
    从机(PDM)数据寄存器的地址和数据为:
     
    起始位地址
    DO寄存器数据(16进制)
    备 注
    0000
    02
    DO2输出状态为“1”,DO1输出状态为“0”
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送的信息
    备 注
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    01   
    读开关量输出状态
    起始BIT位
    2
    0000 
    起始BIT位地址为0000
    读数据长度
    2
    0002 
    读取2路继电器输出状态位
    CRC码
    2
    BDCB
    由主机计算得到CRC码
     
    从机(PDM)响应返回的报文格式:
     
    从机响应
    字节数
    返回的信息
    备 注
    从机地址
    1
    01  
    来自从机01
    功能码
    1
    01   
    读开关量输出状态
    数据长度
    1
    01   
    1个字节(8个BIT位)
    DO状态数据
    1
    02
    DO寄存器内容
    CRC码
    2
    D049 
    由从机计算得到CRC码
    -------------------------------------------------------
    3.3 功能码“03:读多路寄存器输入
     
    例如:主机要读取地址为01,起始地址为0116的3个从机寄存器数据。读取多路定值,比如模拟量输出设定值,PID运行参数
    从机(PDM)数据寄存器的地址和数据为:
     
    寄存器地址
    寄存器数据(16进制)
    对应PDM电量
    0116
    1784
    UA
    0117
    1780
    UB
    0118
    178A
    UC
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送的信息
    备 注
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    03   
    读取寄存器
    起始地址
    2
    0116 
    起始地址为0116
    数据长度
    3
    0003 
    读取3个寄存器(共6个字节)
    CRC码
    2
    E5F3
    由主机计算得到CRC码
     
    从机(PDM)响应返回的报文格式:
     
     
    从机响应
    字节数
    返回的信息
    备 注
    从机地址
    1
    01  
    来自从机01
    功能码
    1
    03   
    读取寄存器
    读取字
    1
    06   
    3个寄存器共6个字节
    寄存器数据1
    2
    1784
    地址为0116内存的内容
    寄存器数据2
    2
    1780
    地址为0117内存的内容
    寄存器数据3
    2
    178A 
    地址为0118内存的内容
    CRC码
    2
    5847  
    由从机计算得到CRC码
     
    -------------------------------------------------------
    3.4 功能码“05:写1路开关量输出(遥控)
     
    例1:开关量输出点DO1,其当前状态为“分”,主机要控制该路继电器“合”。强置一个逻辑线圈的通断状态
    控制命令为:
    “FF00”为控制继电器“合”;“0000”为控制继电器“分”;
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送的信息
    备 注
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    05   
    写开关量输出状态
    输出BIT位
    2
    0000 
    对应输出继电器BIT位(DO1)
    控制命令
    2
    FF00 
    控制该路继电器输出为“合”状态位
    CRC码
    2
    8C3A
    由主机计算得到CRC码
     
     从机(PDM)响应返回的报文格式:
     
     与主机发送的报文格式及数据内容完全相同。
    例2:开关量输出点DO2,其当前状态为“合”,主机要控制该路继电器“分”。
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送的信息
    备 注
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    05   
    写开关量输出状态
    输出BIT位
    2
    0001 
    对应输出继电器BIT位(DO2)
    控制命令
    2
    0000 
    控制该路继电器输出为“合”状态位
    CRC码
    2
    9C0A
    由主机计算得到CRC码
     
    从机(PDM)响应返回的报文格式:与主机发送的报文格式及数据内容完全相同。
    -------------------------------------------------------
    3.5 功能码“06:写单路寄存器
     
    例如:主机要把数据07D0,保存到地址为002C的从机寄存器中去(从机地址码为01)。通讯数据保存结束后,地址为002C的PDM表原存储信息为:
     
    地址
    原来存储数据(16进制)
    002C
    04B0
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送的信息
    举 例
    从机地址
    1
    01   
    发送至地址为01的从机
    功能码
    1
    06   
    写单路寄存器
    起始地址
    2
    002C 
    要写入的寄存器地址
    写入数据
    2
    07D0 
    对应的新数据
    CRC码
    2
    4BAF
    由主机计算得到的CRC码
     从机(PDM)响应返回的报文格式: 与主机发送的报文格式及数据内容完全相同。
    -------------------------------------------------------
    3.6 功能码“10:写多路寄存器
    主机利用这个功能码把多个数据保存到PDM表的数据存储器中去。Modbus通讯规约中的寄存器指的是16位(即2字节),并且高位在前。这样PDM的存储器都是二个字节。由于Modbus通讯规约允许每次最多保存60个寄存器,因此PDM一次也最多允许保存60个数据寄存器。比如对时
       例如:主机要把0064,0010保存到地址为002C,002D的从机寄存器中去(从机地址码为01)。通讯数据保存结束后,地址为002C/002D的PDM表内存储信息为:
     
    地址
    原来存储数据(16进制)
    002C
    04B0
    002D
    1388
     
    主机发送的报文格式:
     
    主机发送
    字节数
    发送信息
    举 例
    从机地址
    1
    01
    发送至从机01
    功能码
    1
    10
    写多路寄存器
    起始地址
    2
    002C
    要写入的寄存器的起始地址
    保存数据字长度
    2
    0002
    保存数据的字长度(共2字)
    保存数据字节长
    1
    04
    保存数据的字节长度(共4字节)
    保存数据1
    2
    04B0
    数据地址002C
    保存数据2
    2
    1388
    数据地址002D
    CRC码
    2
    FC63
    由主机计算得到的CRC码
     
     从机(PDM)响应返回的报文格式:
    从机响应
    字节数
    字节数
    举 例
    从机地址
    1
    01
    来自从机01
    功能码
    1
    10
    写多路寄存器
    起始地址
    2
    002C
    起始地址为002C
    保存数据字长度
    2
    0002
    保存2个字长度的数据
    CRC码
    2
    8001
    由从机计算得到的CRC码
    -------------------------------------------------------
    3.7 功能码“03”:读事件记录
    采用功能码03H向保持寄存器地址0x0001,读一个字,产生读一个事件记录的作用。
    主站发送: 从机地址 功能码 事件记录地址H 事件记录地址L 事件记录个数H 事件记录个数L CRC码H CRC码L 01 03 00 01 00 01 D5 CA 子站响应: 从机地址 功能码 字节数 事件条目数H 事件条目数L 事件代码H
    (事件组号) 事件代码L
    (事件代码) 动作值
    02:合; 01:分 01 03 0C 00 01 04 09 02 毫秒L 毫秒H 分钟 小时 日 月份 年份 CRC码H CRC码L A5 4D 19 12 17 01 07 2F EB

     
    --------------------------------------------------------------------------------------------------------------
    四、错误校验码(CRC校验)
    主机或从机可用校验码进行判别接收信息是否正确。由于电子噪声或一些其它干扰,信息在传输过程中有时会发生错误,错误校验码(CRC)可以检验主机或从机在通讯数据传送过程中的信息是否有误,错误的数据可以放弃(无论是发送还是接收),这样增加了系统的安全和效率。
    MODBUS通讯协议的CRC(冗余循环码)包含2个字节,即16位二进制数。CRC码由发送设备(主机)计算,放置于发送信息帧的尾部。接收信息的设备(从机)再重新计算接收到信息的CRC,比较计算得到的CRC是否与接收到的相符,如果两者不相符,则表明出错。
     
    在进行CRC计算时只用8个数据位,起始位及停止位,如有奇偶校验位也包括奇偶校验位,都不参与CRC计算。
    ● CRC码的计算方法是:
    1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;
    2.把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;
    3.把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
    4.如果移出位为0:重复第3步(再次右移一位);
         如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
    5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
    6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
    7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
    8.最后得到的CRC寄存器内容即为:CRC码。
     
    --------------------------------------------------------------------------------------------------------------
    五、通讯错误信息及数据的处理
           当PDM表检测到除了CRC码出错以外的错误时,必须向主机回送信息,功能码的最高位置为1,即从机返送给主机的功能码是在主机发送的功能码的基础上加128 。以下的这些代码表明有意外的错误发生。PDM从主机接收到的信息如有CRC错误,则将被PDM表忽略。
     
         PDM返送的错误码的格式如下(CRC码除外):
            地址码: 1字节
            功能码: 1字节(最高位为1)
            错误码: 1字节
            CRC码: 2字节
     
         PDM响应回送如下错误码:
            81.非法的功能码。
              接收到的功能码PDM表不支持。
            82.非法的数据位置。
              指定的数据位置超出PDM表的范围。
            83.非法的数据值。
              接收到主机发送的数据值超出PDM相应地址的数据范围。
     
    --------------------------------------------------------------------------------------------------------------
    展开全文
  • 最近在写一个专利,关于wifi探针。 具体论文会在论文申请成功之后放出来。 最近积累了一点。...CSMA(Carrier Sense Multiple Access)被称为载波侦听多路访问方法: 三种csma模式: 1-persiste...
  • 应用层2.表示层3.会话层4.传输层5.网络层6.数据链层7.物理层2.TCP/IP五层模型3.通信连接1....三次握手(连接的建立)1.1 名词解释1.1.1 Seq序号1.1.2.Ack确认号1.1.3.Flags标志位1.2 三次握手步骤1.2.0 详细
  • 一、名词解释: 集线器:(Hub)是指将条以太网双绞线或光纤集合连接在同一段物理介质下的设备。集线器发生在物理层。 交换机:(Switch)是一种用于电(光)信号转发的网络设备。它可以为接入交换机的任意两个...
  • selectors模块

    2019-10-08 04:37:00
     复用在通信领域的使用,在通信领域中为了充分利用网络连接的物理介质, 往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号。  复用的含义: 即公用某个“介质”来尽可能多的做同...
  • select,poll,epoll

    2019-10-08 02:53:59
    一 了解select,poll,epoll ...往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义, 即公用某个“介质”来尽可能多的做同...
  • 一 了解select,poll,epoll ...往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义, 即公用某个“介质”来尽可能多的做同一类(性质...
  • 5-7、selectors模块

    2019-02-16 18:39:29
    一 了解select,poll,epoll ...往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义, 即公用某个“介质”来尽可能多的做同一类(性质)的...
  • 一 了解select,poll,epoll ...往往在同一条网络链路上采用时分复用或频分复用的技术使其在同一链路上传输多路信号,到这里我们就基本上理解了复用的含义, 即公用某个“介质”来尽可能多的做同一类(性质...
  • 10 select、poll以及epoll

    2019-06-27 10:11:00
    为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象,为此,咱们来理解下复用在通信领域的使用, 在通信领域中为了充分利用网络连接的物理介质,往往在同一条网络链路上采用...
  • 复用io selectors模块

    2019-05-08 20:01:00
    为了解释这个名词,首先来理解下复用这个概念,复用也就是共用的意思,这样理解还是有些抽象,为此,咱们来理解下复用在通信领域的使用,在通信领域中为了充分利用网络连接的物理介质,往往在同一条网络链路上采用...
  • 由于上传限制,分为两个分卷上传. 《移动通信(第二版 中文版)》 作 者: JOCHEN SCHILLER 出 版 社: 高等教育出版社 目 录: 第一章 绪论 1.1应用 1.1.1车辆 1.1.2应急通信 ...附录2 名词解释 英汉对照表
  • 移动通信(第二版)中文版

    热门讨论 2011-03-29 09:00:07
    附录2 名词解释 英汉对照表 简 介: 本书是移动通信领域的导论,主要讨论数字数据传输。适用于选修计算机网络或通信课程的电子工程或计算机专业的学生。本书从计算机科学的角度涵盖移动通信的各个方面,还指出了...
  • 最近在复习计网,发现里面有一些设备名词不容易记忆与1区分,特此写此博文,留作回忆, 术语解释 路由器:(Router)是连接因特网中各局域网、广域网的设备。在路由器中记录着路由表,它会根据信道的情况自动选择和...
  • 名词解释: 1. 计算机网络 2.网络体系结构 3.高速以太网 4.静态路由选择 5. 动态路由选择 6.子网掩码 8.动态主机配置协议 9.套接字 10.客户/服务器模型(C/S模型) 11.域名系统(DNS) 12.光纤分布式数据接口...
  • 问题3-3:既然现在因特网使用得最多的数据链层协议并不保证可靠传输,那么为什么我们在数据链层一章中还要讲授保证可靠传输的停止等待协议呢? 问题3-4:通过普通的电话用户线拨号上网时(使用调制解调器),...
  • 问题3-3:为什么旧的版本教材在数据链层一章中讲授可靠传输,但现在新的版本教材则取消了可靠传输? 问题3-4:通过普通的电话用户线拨号上网时(使用调制解调器),试问一对用户线可容许多少个用户同时上网? ...
  • 一些房产的基本名词有助于看懂规划图 1.用地性质  用地性质对照表 类别代称 类别名称 内容 大类 中类 小类 R 居住用地     居住用地 住宅和相应服务设施的用地 R1   一类居住用地 设施...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

多路传输名词解释