socket的pty功能

时间:2012-08-19 13:03:32

标签: c++ linux sockets pty libreadline

我正在编写linux守护进程,我想实现通过telnet配置其params的能力。我有一个cli接口代码,使用带有历史记录和完成符的gnu readline库编写,我想将该接口代码用于守护进程。

我尝试将stdin / stdout重定向到socket,将rl_instream / rl_outstream重定向到socket,读/写到master / slave pty,但没有成功。

similar question asked here没有任何答案。

另请阅读this question,但我没有子流程。

我的问题是:

  1. 如何在单个进程中使用pty功能?
  2. 如果我只有一个进程,是否需要使用master和slave pty?
  3. 代码示例(在pty设备上没有操作),预期结果 - readline正常工作

    char* readline_buff;
    
    int main(void){
    int mSock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
    int socketfd, n, flag = 1;
    
    int addrlen;
    daemon(1,1);
    setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int));
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(5000);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(mSock, (const sockaddr*)&addr, sizeof(addr));
    listen(mSock,SOMAXCONN);
    addrlen = sizeof(addrlen);
    bzero(&addr, sizeof(addr));
    
    int m_pty = posix_openpt(O_RDWR);
    grantpt(m_pty);
    unlockpt(m_pty);
    string m_ptsname = ptsname(m_pty);
    int slave = open(m_ptsname.c_str(), O_RDWR);
    //
    socketfd = accept(mSock, (struct sockaddr *) &addr, (socklen_t*)&addrlen);
    //
    close(STDOUT_FILENO);
    dup2(socketfd, STDOUT_FILENO);
    close(STDIN_FILENO);
    dup2(socketfd, STDIN_FILENO);
    close(STDERR_FILENO);
    dup2(socketfd, STDERR_FILENO);
    //
     while(true){   
      readline_buff = readline("ME: ");
      add_history(readline_buff);
      free(readline_buff);
    }
    return 0;
    }
    

    非常感谢。

3 个答案:

答案 0 :(得分:1)

telnet协议基本上是基于行的协议,因此它不容易处理单个按键或特殊代码。您可以要求连接的telnet客户端发送每个密钥而不是行,这可以通过telnet协商来完成。

要了解更多相关信息,您应该阅读telnet RFC,最重要的是RFC 854RFC 855。要禁用客户端编辑,还应阅读RFC 1116。另请检查Wikipedia page以查看所有与telnet相关的RFC的列表。

简而言之,您必须向客户端发送一系列命令,要求它停止执行行模式处理,并希望客户端回答它将停止执行此操作。这不是简单的事情,实际上恰恰相反。但是,实现完整的telnet状态机可以。即使这样,您也可能无法正确使用readline库,因为键击可能无法被识别为正确的向上/向下键,您可能还是必须进行一些翻译。我实际上建议你跳过正常的stdin / stdout处理和PTY处理,并让客户端处理编辑,同时通过使用外部库(如readline)的功能或通过内部来跟踪历史记录历史队列。

答案 1 :(得分:0)

不需要Pty。您需要为readline/etc/inputrc文件添加以下行,为~/.inputrc配置新的历史记录密钥:

"\e[A":history-search-backward
"\e[B":history-search-forward

原因:

当用户按向上或向下箭头键时,终端程序(读取:telnet客户端)通常会发送转义码。

转义码是:

\33[A   - up arrow 
\33[B   - down arrow

因为您的程序打印:^[[A^[[A^[[A^[[A,所以它不会对转义序列进行重新定义。 因此,您需要将这些转义序列告诉readline

请参阅more information

答案 2 :(得分:0)

Readline提供了一个测试文件rlPtyTest.c,它通过PTY测试readline。您可以将其用作实现套接字的模板。 https://github.com/alexmac/alcextra/blob/master/readline-6.2/examples/rlptytest.c