精华内容
下载资源
问答
  • 硬件交互之命令交互

    千次阅读 2018-03-20 14:05:42
    转载自:http://blog.csdn.net/Suma_sun/article/details/51388816...数据包协议(数据收发协议)命令协议(命令交互)类型转换为什么需要数据包协议呢,如果没有对应的协议,你们将无法沟通成功,牛头不对马嘴的在交互...

    转载自:http://blog.csdn.net/Suma_sun/article/details/51388816

    在智能家居公司混了这么久,都没怎么发些有营养的东西,最近感觉不能再这么懒下去了。准备写几篇有关的文章,就当记录下免得忘记了,也方便其他人少走弯路。

    • 数据包协议(数据收发协议)
    • 命令协议(命令交互)
    • 类型转换

    为什么需要数据包协议呢,如果没有对应的协议,你们将无法沟通成功,牛头不对马嘴的在交互,都完全不知道对方说的是什么。 
    首先硬件嵌入式多是用c/c++开发的所以想要与之交互需要使用它所能读懂的数据结构——结构体。 
    c/c++和java不同数据类型是不同的,所以通讯的时候要使用通用的数据类型——字节流(byte[])。PS:java、c/c++数据类型各占几个字节就请自行百度吧。

    数据包协议 
    搞清楚了交互的数据类型,就该弄清楚接收到的数据的内容,因为都是以字节来表示,所以你需要知道某个属性或者说是描述的字节长度,否者强行转型也都是乱码(字符串)或错误的值。接下来就来定义一个结构体作为协议的内容。

    	typedef struct { 
    		int cmd;//命令标识码 
    		SMsgContent content;//实际内容
    	}SMsg

    结构体已经给出了,也都有注释不难看出其中意义。cmd是交互命令的唯一标识码,就像Handler的what一样,用于选择对应的解析与操作。

    下面给出是cmd的写法

    
    public static final int IOCONTROL_GET_ALL_PARAMS_REQ = 0x03D8;
    
    public static final int IOCONTROL_GET_ALL_PARAMS_RESP = 0x03D9;

    命令协议 
    命令协议就是写在数据包协议里的content的。用作cmd对应的交互用数据,比如该设备是个音响,给其设置声音,那么可能就有音量、低音炮、音频之类的值,把这些命令拆开成几个包分开发送就会增加代码量与交互次数,相应的耗电就提高,业务处理也麻烦。

    typedef struct{
    int version;
    unsigned int reserved[3];
    }SMsgGetAllParamsReq

    version为了让大家了解写法而加上去的一个参数,也可以用作请求api的版本号,reserved[3]保留位置,用于方便以后添加新参数可用

    typedef struct {
     int id;//设备id
     char device_name[32];//设备名称
     char soft_ver[32];//软件版本号
     char firm_ver[32];//硬件版本号
     unsigned int reserved[3];
    }SMsgGetAllParamsResp

    接下来就是关键代码了,将命令转换为byte[]用于命令交互

    public class SMsgGetAllParamsReq{
        public static byte[] gen(int version){
            byte[] data = new byte[16];
        System.arraycopy(Packet.intToByteArray_Little(version, 0), 0,
                        arrayOfByte, 0, 4);
            return data;
            }
        }

    首先为什么要这样实现呢? 
    估计大家都有疑问为什么要设置数组长度为16呢?那是因为int类型占4个字节(java、c/c++一样),byte类型占一个字节(1字节 = 8位,1024字节 = 1KB)。 
    System.arraycopy这个系统函数是用于拷贝数组在内指定容到另一个数组的指定位置。Packet稍后会给大家做介绍。

    public class SMsgGetAllParamsResp{
        public static final COUNT = 3;
        public int id;
        public String device_name;
        public String soft_ver;
        public String firm_ver;
        public int[] reserved = new int[COUNT];
    
        public static SMsgGetAllParamsResp parse(byte[] data){
            SMsgGetAllParamsResp  resp = new SMsgGetAllParamsResp ();
            resp.id = Packet.byteArrayToInt_Little(data,0);
            resp.device_name = new String(data, 4, 32).trim();
            resp.soft_ver = new String(data, 36, 32).trim();
            resp.firm_ver= new String(data, 68, 32).trim();
            int index = 100;
            for(int i=0;i<COUNT;i++){
                resp.reserved[0] = Packet.byteArrayToInt_Little(data,index);
                index += 4;
                }
            return resp;
            }
    
        }

    new String(bytes, offset, length)这个函数相信大家都很熟悉我就不介绍了,里面的值也就是偏移量也是一眼就明了的。

    到目前为止命令的解析生成就介绍完毕了。

    类型转换 
    数据类型转换不必说大家想必也是很清楚的,最简单的(int)100L,Long类型强转int类型,文中为什么不使用呢?因为效率的原因,直接使用位运算符操作效率会高很多。

    public static final int byteArrayToInt_Little(byte byt[], int nBeginPos) {
            return (0xff & byt[nBeginPos]) | (0xff & byt[nBeginPos + 1]) << 8 | (0xff & byt[nBeginPos + 2]) << 16 | (0xff & byt[nBeginPos + 3]) << 24;
        }
    
    public static final byte[] intToByteArray_Little(int value) {
            return new byte[] { (byte) value, (byte) (value >>> 8), (byte) (value >>> 16), (byte) (value >>> 24) };
        }

    至于其他类型的转换请各位自行百度吧,相信你们可以找到,要善用搜索引擎。

    捣鼓了几个晚上终于写完了,虽然因为公司要加班晚上写文章的时间很少,虽然时间长也算是写完了。楼主笔风粗俗还望各位海涵,有任何有问题、错误的地方请随时留言。

    下一篇准备结合nio写命令的发送接收,把今天的内容整合到一块。

    补充内容

    类型转换还有些小坑的地方补充下。 
    一个请求的结构体

    typedef struct {
     char type;// 设置类型那个
     int  operate;//操作类型 0:打开 1:关闭
     unsigned int reserved[3];
    }

    type占一个字节,operate应该从索引1开始4的长度。正常来说是这样没错, 
    但是c/c+是会补位的,也就是说虽然type只占一个字节,但是为了后面的operate(4字节)存放,会直接补位补三位0,当时和同事调接口的时候死活传错参数,后面才知道他读取operate是从4开始的而不是从1开始。

    所以遇到类似情况请先和设备端同事沟通,或者看看协议规范。

    java后台的同事问我这样传有什么优点,之前还真没仔细考虑过。 
    目前总结几点,也请各大神帮我补充

    1. 字节流传输跨平台,兼容性好,效率高(底层都是转为字节流传输的)
    2. 使用结构体,方便嵌入式直接转换为指针对象,就像java的序列化一样,减少了嵌入式代码量(嵌入式一般受硬件条件约束,空间有限,尽量缩减代码)

    展开全文
  • 主要介绍了python文件读写操作与linux shell变量命令交互执行的方法,涉及对文件操作及Linux shell交互的技巧,需要的朋友可以参考下
  • 是一款交互式的文件传输程序,sftp命令的运行和使用方式与ftp命令相似,但是,sftp命令对传输的所有信息使用ssh加密,它还支持公钥认证和压缩等功能。 语法格式: sftp [参数] [IP或主机名] 常用参数: -B 指定...
  • python和linux命令交互方式总结

    千次阅读 2014-01-09 10:11:33
    python和linux命令交互有两种方式: 1. 直接使用os执行命令 os.system("armory -leg %s"%(host)) 这种方式的问题在于命令直接输出到console中了,无法定制。   2.使用pexpect import pexpect ...

    python和linux命令交互有两种方式:

    1. 直接使用os执行命令

    os.system("armory -leg %s"%(host))

    这种方式的问题在于命令直接输出到console中了,无法定制。

     

    2.使用pexpect

    import pexpect
    child = pexpect.spawn ('armory', ['-leg', host])
    child.expect([pexpect.EOF,pexpect.TIMEOUT])
    hosts=child.before.split("\r\n")
    hosts = [host for host in hosts if host !=""]
    print ",".join(hosts) 
    

     3. 貌似还可以使用os.popen

     lines = os.popen("netstat -an|grep ':3306' |awk '{print $5, $6}'").readlines()
    

     

     

    更多参考文档:

    http://my.oschina.net/renwofei423/blog/17403

    展开全文
  • Redis源码学习-Master&Slave的命令交互

    千次阅读 2013-11-13 23:07:44
    其中,redisClient为命令交互设置了缓冲区。querybuf用于存储客户端送过来的命令,buf和reply是用于应答的缓冲。querybuf是在文件事件readQueryFromClient中被填充,每次填充的最大字节数默认为1024B。而应答缓冲区...

    0. 写在前面

            Version Redis2.2.2

            Redis中可以支持主从结构,本文主要从master和slave的心跳机制出发(PING),分析redis的命令行交互。

            在Redis中,server为每个连接建立一个redisClient数据对象,来描述对应的连接。其中,redisClient为命令交互设置了缓冲区。querybuf用于存储客户端送过来的命令,buf和reply是用于应答的缓冲。querybuf是在文件事件readQueryFromClient中被填充,每次填充的最大字节数默认为1024B。而应答缓冲区是由addReply()函数填充,并由文件事件sendReplyToClient中发送给客户端。具体数据流如图1所示。MasterPorcess与SlaveProcess进行命令交互。其中,蓝色矩形框代表函数,白色矩形框代表数据,曲线描述数据流,折线描述数据间的从属关系。


    图1. Master&Slave交互的数据流(蓝色矩形框代表函数,白色矩形框代表数据,曲线描述数据流,折线描述数据间的从属关系)

    1. 相关数据结构

    typedef struct redisClient {
        int fd;					//connect fd
        ...
        sds querybuf;			//命令缓冲区,由readQueryFromClient()事件进行填充(sds equals to char*)
        int argc;				//for command;记录参数个数
        robj **argv;			//for command;记录命令行参数
        int reqtype;			//命令解析协议:INLINE or MULTIBULK
    	...
    	time_t lastinteraction; /* 最近交互时间 */
    	...
        list *reply;			//Replay object list
        /* Response buffer */
    	char buf[REDIS_REPLY_CHUNK_BYTES];	//Reply buffer,由addReply()函数进行填充
        int bufpos;				//记录buf已填充的长度
    	int sentlen;			//Replay阶段,记录当前buf已发送了多少字节
    } redisClient;
    
    struct redisServer {
        ...
        list *clients;
        dict *commands;             /* Command table hahs table */
        ...
        list *slaves, *monitors;	//Master : slave链表
        char neterr[ANET_ERR_LEN];
        aeEventLoop *el;			//Event list
        int cronloops;              //ServerCorn 执行次数
    	...
        redisClient *master;	//Slave :记录 master 的连接信息的client
        int replstate;          //Slave :当前的状态
        ...
    };
    
    struct redisCommand readonlyCommandTable[] = {
    	...
    	{"sync",syncCommand,1,0,NULL,0,0,0},
    	...
    	{"ping",pingCommand,1,0,NULL,0,0,0},
    	...
    }

    2. query的读取和命令的解析

            从图1可以看出,命令交互数据query的读取是在文件事件readQueryFromClient中填充到c->querybuf中。之后,querybuf由函数processInputBuffer进行命令的解析。命令的解析过程如图2所示。在函数processInputBuffer中,将缓存与querybuf中的所有命令(命令间按\n\r分隔)进行解析。之后,查询命令hashtabe查找相关命令函数。最后调用相应命令hander执行命令。


    图2.querybuf的解析

    具体代码分析如下:

    void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
        redisClient *c = (redisClient*) privdata;
        char buf[REDIS_IOBUF_LEN];
        int nread;
        REDIS_NOTUSED(el);
        REDIS_NOTUSED(mask);
    
        nread = read(fd, buf, REDIS_IOBUF_LEN);
        ...check...
        if (nread) {
            c->querybuf = sdscatlen(c->querybuf,buf,nread);
            c->lastinteraction = time(NULL);//更新时间戳
        } else {
            return;
        }
        processInputBuffer(c);//处理client传输过来的数据
    }
    
    void processInputBuffer(redisClient *c) {
        /* 执行querybub中的所有命令*/
        while(sdslen(c->querybuf)) {
    		...check...
            /*判定命令的解析协议 */
            if (!c->reqtype) {
                if (c->querybuf[0] == '*') {
                    c->reqtype = REDIS_REQ_MULTIBULK;
                } else {
                    c->reqtype = REDIS_REQ_INLINE;//按行解析
                }
            }
    
            if (c->reqtype == REDIS_REQ_INLINE) {
    			/*processInlineBuffer: 
    			1. 取出c->querybuf起始端到\r\n位置的字符串,更新c->querybuf
    			2. 将取出的字符串按照“ ”空格进行分段解析,得到命令及其参数
    			格式为: argc,*argv[],其中argv[0]为命令,argv[1~argc-1]为参数*/
                if (processInlineBuffer(c) != REDIS_OK) break;
            } else if (c->reqtype == REDIS_REQ_MULTIBULK) {
                ...
            }
    
            /* Multibulk processing could see a <= 0 length. */
            if (c->argc == 0) {
                resetClient(c);
            } else {
                /* Only reset the client when the command was executed. */
                if (processCommand(c) == REDIS_OK)	//执行命令
                    resetClient(c);
            }
        }
    }
    
    /* If this function gets called we already read a whole
     * command, argments are in the client argv/argc fields.
     * processCommand() execute the command or prepare the
     * server for a bulk read from the client.
     */
    int processCommand(redisClient *c) {
        struct redisCommand *cmd;
    
        ...
    
        /* Now lookup the command and check ASAP about trivial error conditions
         * such wrong arity, bad command name and so forth. */
        cmd = lookupCommand(c->argv[0]->ptr);
        
    	...check...
    
        /* Exec the command */
        if (c->flags & REDIS_MULTI &&
            cmd->proc != execCommand && cmd->proc != discardCommand &&
            cmd->proc != multiCommand && cmd->proc != watchCommand)
        {
            queueMultiCommand(c,cmd);
            addReply(c,shared.queued);
        } else {
            if (server.vm_enabled && server.vm_max_threads > 0 &&
                blockClientOnSwappedKeys(c,cmd)) 
    			return REDIS_ERR;
            call(c,cmd);	//执行命令
        }
        return REDIS_OK;
    }
    
    /* Call() is the core of Redis execution of a command */
    void call(redisClient *c, struct redisCommand *cmd) {
        long long dirty;
    
        dirty = server.dirty;
        cmd->proc(c);		//执行命令
        dirty = server.dirty-dirty;
    
        if (server.appendonly && dirty)
            feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
        if ((dirty || cmd->flags & REDIS_CMD_FORCE_REPLICATION) &&
            listLength(server.slaves))
            replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
        if (listLength(server.monitors))
            replicationFeedMonitors(server.monitors,c->db->id,c->argv,c->argc);
        server.stat_numcommands++;
    }

    3. 具体命令的执行(ping命令)

        其中,addReply将相关命令执行结果放入client的reply缓冲区中。reply缓冲区的发送时机是在事件sendReplyToClient中进行。

    #define REDIS_STRING 0
    shared.pong = createObject(REDIS_STRING,sdsnew("+PONG\r\n"));
    //{"ping",pingCommand,1,0,NULL,0,0,0}
    void pingCommand(redisClient *c) {
        addReply(c,shared.pong); //ping的回复是pong,打乒乓,呵呵
    }
    
    //将命令执行的返回结构写入c->buf 或者 c->reply
    void addReply(redisClient *c, robj *obj) {
        if (_installWriteEvent(c) != REDIS_OK) return;//创建event sendReplyToClient
        redisAssert(!server.vm_enabled || obj->storage == REDIS_VM_MEMORY);
    
        /* This is an important place where we can avoid copy-on-write
         * when there is a saving child running, avoiding touching the
         * refcount field of the object if it's not needed.
         *
         * If the encoding is RAW and there is room in the static buffer
         * we'll be able to send the object to the client without
         * messing with its page. */
        if (obj->encoding == REDIS_ENCODING_RAW) {
            if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
                _addReplyObjectToList(c,obj);
        } else {
            /* FIXME: convert the long into string and use _addReplyToBuffer()
             * instead of calling getDecodedObject. As this place in the
             * code is too performance critical. */
            obj = getDecodedObject(obj);
            if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
                _addReplyObjectToList(c,obj);
            decrRefCount(obj);
        }
    }

    4. reply缓冲区数据的发送

            将c->buf 和 c->reply中的数据发送到客户端(slave or master)。在每次文件事件中发送所有的reply缓冲区中的数据。

    void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
        redisClient *c = privdata;
        int nwritten = 0, totwritten = 0, objlen;
        robj *o;
        REDIS_NOTUSED(el);
        REDIS_NOTUSED(mask);
    
        while(c->bufpos > 0 || listLength(c->reply)) {
            if (c->bufpos > 0) {
    			//发送c->buf中的数据
                if (c->flags & REDIS_MASTER) {
                    /* Don't reply to a master */
                    nwritten = c->bufpos - c->sentlen;
                } else {
                    nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen);
                    if (nwritten <= 0) break;
                }
                c->sentlen += nwritten;
                totwritten += nwritten;
    
                /* If the buffer was sent, set bufpos to zero to continue with
                 * the remainder of the reply. */
                if (c->sentlen == c->bufpos) {
                    c->bufpos = 0;
                    c->sentlen = 0;
                }
            } else {
    			//发送c->reply中的数据
                o = listNodeValue(listFirst(c->reply));
                objlen = sdslen(o->ptr);
    
                if (objlen == 0) {
                    listDelNode(c->reply,listFirst(c->reply));
                    continue;
                }
    
                if (c->flags & REDIS_MASTER) {
                    /* Don't reply to a master */
                    nwritten = objlen - c->sentlen;
                } else {
                    nwritten = write(fd, ((char*)o->ptr)+c->sentlen,objlen-c->sentlen);
                    if (nwritten <= 0) break;
                }
                c->sentlen += nwritten;
                totwritten += nwritten;
    
                /* If we fully sent the object on head go to the next one */
                if (c->sentlen == objlen) {
                    listDelNode(c->reply,listFirst(c->reply));
                    c->sentlen = 0;
                }
            }
            /* Note that we avoid to send more thank REDIS_MAX_WRITE_PER_EVENT
             * bytes, in a single threaded server it's a good idea to serve
             * other clients as well, even if a very large request comes from
             * super fast link that is always able to accept data (in real world
             * scenario think about 'KEYS *' against the loopback interfae) */
            if (totwritten > REDIS_MAX_WRITE_PER_EVENT) break;
        }
        ...check...
        if (totwritten > 0) c->lastinteraction = time(NULL);
    	/*reply数据全部发送完毕后,要关闭该文件的写事件。
    	该事件重新开启的时机为addReply()>>_installWriteEvent(c)(见3小节)*/
        if (listLength(c->reply) == 0) {
            c->sentlen = 0;
            aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
    
            /* Close connection after entire reply has been sent. */
            if (c->flags & REDIS_CLOSE_AFTER_REPLY) freeClient(c);
        }
    }


    5. 总结

            命令行交互过程中,1.为每个连接有相应的数据进行描述(redisClient),这样便于连接的管理。2.命令行交互中,引入命令缓冲区querybuf,这样可以延时处理命令,这在事件轮询机制中,是至关重要的。

          原文链接 http://blog.csdn.net/ordeder/article/details/16105345

    展开全文
  • linux命令交互页面如何快速复制粘贴

    千次阅读 2019-02-23 10:16:33
    shift + ctrl + c 复制 shift + ctrl + v 粘贴 选中需要复制的内容,shift + ctrl + c 然后再命令行输入 shift + ctrl + v  

    shift + ctrl + c  复制

    shift + ctrl + v   粘贴

    选中需要复制的内容,shift + ctrl + c

    然后再命令行输入 shift + ctrl + v

     

    展开全文
  • 本文介绍URI的基本格式,并结合Hadoop 2.7.x相关HDFS命令,讲解在与HDFS交互中如何指定文件和目录确切位置的URI。
  • )从 Windows 命令提示符 (CMD) 或 PowerShell 运行 Linux 二进制文件。 从 Linux 运行 Windows 工具 如果对应的Windows 工具在环境变量中,那么在WSL输入即可直接启动Windows 工具,例如通过notepad.exe启动文本...
  • 为已经开发的系统提供一个命令操作界面以方便使用人员操作。 基本功能: 1、实现help、clear、dump、exit这些命令,这里仅作为示例; 2、简单的行文本编辑功能(光标的左右移动、backspace删除字符、上下方向键...
  • 说明:本demo仅仅是演示RTSP的命令交互过程,并没有真正的传输和播放视频。 如果对于RTSP交互命令的说明和返回的SDP信息不是很了解,可以先看看这篇文章 《TSP协议学习笔记》 关于使用VLC搭建RTSP服务器的...
  • 解决办法一:  手动安装:  sudo yum install libncurses5-dev  下载:  https://pypi.python.org/packages/source/r/readline/readline-6.2.4.1.tar.gz ...#md5=578237939c81fdbc2c8334d168b17907  ...
  • 但有时候单单监控是不够的,我们可能还需要修改相应的JOB,这时我们就需要进行datapumo的命令交互模式。 有两种方式可以进入命令交互模式,分别是: 1. 在logging模式下按ctrl+C 2. expdp or impdp attach=...
  • interactive-make, Laravel的交互命令 交互式制作 Laravel 5.4 正在启动要开始安装,你需要使用Composer安装软件包:composer require laracademy/interactive-make Laravel>
  • linux shell交互命令学习 交互命令read 非交互命令expect
  • expect交互命令

    千次阅读 2015-04-24 16:56:34
     是一个用来处理交互命令。借助expect,可以将交互过程写在一个脚本上,使之自动化完成。形象的说,ssh,ftp登录都符合交互的定义。  四个命令:send,expect,spawn,interact,send_user  send:用于向进程发送...
  • linux 交互命令

    千次阅读 2019-04-16 14:41:11
    (echo "xxxx" sleep 2 echo "xxx" sleep 5 echo "2425358736@qq.com")| npm login 命令 执行 npm login 命令后 先输入xxxx 2秒后输入 xxx 5秒后输入2425358736@qq.com
  • Laravel的交互式Make命令
  • 使用Python调用Abaqus交互命令,替代图形交互界面,ABAQUS官方帮助文档,侵删。
  • Hive 常用交互命令

    万次阅读 2019-05-14 11:30:52
    基本命令 [root@hadoop101 ~]# hive -h Unrecognized option: -h usage: hive -d,--define <key=value> Variable subsitution to apply to hive commands. e.g. -d A...
  • 今天小编就为大家分享一篇关于Linux下使用expect命令编写自动化交互脚本,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 571,223
精华内容 228,489
关键字:

命令交互