简介:实现一套远程shell,实现远程调试。
在嵌入式软件开发的测试验收环节,跨地域协作构成了一项显著挑战,尤其体现在远程调试过程中。当前流程通常要求研发人员依赖测试团队在目标设备上执行特定指令,这一协作模式耗时耗力。鉴于嵌入式系统的资源限制,部署第三方远程控制工具往往不可行。因此,构建一个轻量级远程Shell解决方案成为迫切需求。
远程Shell工具为研发人员提供了在本地环境中无缝连接至目标设备的能力,实现这一功能的核心在于能够远程输入Shell
命令并实时获取执行结果。
技术实现层面,该工具主要依托于socket
通信机制与popen
函数。socket
用于建立两端之间的网络连接,确保数据包的可靠传输;popen
则负责在目标设备上执行命令,并捕获输出结果。两者协同工作,共同构建了一个稳定高效的远程交互平台。
以研发调试的角度,对于远程shell
功能主要概括如下:
Shell
环境中准确执行。确保稳定性与安全性(*)
<font color="blue"><span style="font-size:13px">[1] 注:* 表示非强制需求。</span></font>
基于上述需求分析,以下是设计方案的大致流程:
Socket
服务端:创建并绑定一个监听端口,确保其能接收来自多个客户端的连接请求。 实现主要聚焦于构建一个基于Socket
的服务端程序,其核心功能包括监听客户端连接请求、接收并解析客户端数据、处理接收到的信息以及向客户端提供响应反馈。
特别值得注意的是,在处理客户端发送的数据时,需过滤包含的\r\n
字符序列,这是由于使用Telnet
等工具进行输入时,数据中会自动附加此类字符。
int main(int argc, const char *argv[])
{
if (argc < 2) {
SPR_LOGE("Usage: ./rshellx <port>\n");
return -1;
}
short port = atoi(argv[1]);
if (port <= 0) {
SPR_LOGE("Invalid port: %d\n", port);
return -1;
}
auto pEpoll = make_shared<EpollEventHandler>();
std::list<std::shared_ptr<PSocket>> clients;
auto tcpServer = make_shared<PSocket>(AF_INET, SOCK_STREAM, 0, [&](int cli, void *arg) {
PSocket* pSrvObj = (PSocket*)arg;
if (pSrvObj == nullptr) {
SPR_LOGE("PSocket is nullptr\n");
return;
}
auto tcpClient = make_shared<PSocket>(cli, [&](int sock, void *arg) {
PSocket* pCliObj = (PSocket*)arg;
if (pCliObj == nullptr) {
SPR_LOGE("PSocket is nullptr\n");
return;
}
// Mimics the input display format of a remote terminal session.
// Example:
// # pwd
// /tmp/Release/Bin
std::string rBuf;
int rc = pCliObj->Read(sock, rBuf);
if (rc > 0) {
SPR_LOGD("# RECV [%d]> %s\n", sock, rBuf.c_str());
rBuf.erase(std::find_if(rBuf.rbegin(), rBuf.rend(), [](unsigned char ch) {
return ch != '\r' && ch != '\n';
}).base(), rBuf.end());
std::string out;
int result = GeneralUtils::SystemCmd(out, rBuf.c_str());
if (result == -1) {
out = "Invaild parameter! CMD: " + rBuf;
}
if (out.empty()) {
out = "No return. CMD: " + rBuf;
}
out += "\r\n# ";
rc = pCliObj->Write(sock, out);
if (rc > 0) {
// SPR_LOGD("# SEND [%d]> %s\n", sock, out.c_str());
} else {
SPR_LOGE("# SEND failed!\n");
}
}
if (rc <= 0) {
clients.remove_if([sock, pEpoll, pCliObj](shared_ptr<PSocket>& v) {
pEpoll->DelPoll(pCliObj);
return (v->GetEpollFd() == sock);
});
}
});
tcpClient->AsTcpClient();
pEpoll->AddPoll(tcpClient.get());
clients.push_back(tcpClient);
});
tcpServer->AsTcpServer(port, 5);
pEpoll->AddPoll(tcpServer.get());
pEpoll->EpollLoop(true);
return 0;
}
rshellx
,并输入端口号。$ ./rshellx 8080
76 EpollEvent D: Add epoll fd 4
Telnet
工具连接远程终端rshellx
~$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
bindermanagersrv
debugbinder
debugcore
debugmsg
debugsrv
default.prop
infrawatch
init.conf
logmanagersrv
logshow
mediatorsrv
powermanagersrv
propertiessrv
property_get
property_set
rshellx
sample_sqlite
sample_tcpclient
sample_tcpserver
servicemanagersrv
sparrowsrv
system.prop
vendor.prop
# pwd
/home/dx/hdd1/Gitee/Sparrow/Release/Bin
# lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 22.04.2 LTS
Release: 22.04
Codename: jammy
shell
很方便跨地域调试。由于涉及到安全问题,它应该仅在调试阶段被使用。由指定人员在目标设备手动拉起,然后研发再远程连接。rshellx
仅实现了客户端命令透传功能,后续还可以扩展指令集,方便通过指令查看设备对应的状态、数据等关键信息。