gpt4 book ai didi

c - 使用 popen() 通过套接字执行命令

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:49:41 26 4
gpt4 key购买 nike

任何人都可以帮助我尝试实现以下服务器和客户端吗?:

服务器:

#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>

int main(void) {
int sock = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in serv_addr = { 0 };
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(1234);
bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

listen(sock, 128);

struct sockaddr_in cli_addr = { 0 };
socklen_t cli_addrlen = sizeof(cli_addr);
int acc_sock = accept(sock, (struct sockaddr *)&cli_addr, &cli_addrlen);
printf("[+] Connected \n");
char buf[1024];
ssize_t nread;
memset(buf, 0, sizeof(buf));
int a;
while (1) {
nread = read(0, buf, 1024);
write(acc_sock, buf, nread);
memset(buf, 0, sizeof(buf));

while ((read(acc_sock, buf, 1024)) != 0) {
printf("%s", buf);
memset(buf, 0, sizeof(buf));
}
}
}

所有服务器所做的就是扫描来自 stdin 的命令并通过套接字将其发送到客户端。然后扫描客户端响应并将其打印到 stdout

客户端:

#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[]) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv = { 0 };
char buf[1024];
char command[1024];
memset(buf, 0, sizeof(buf));
memset(command, 0, sizeof(command));
int nread;
FILE *in;
extern FILE *popen();

serv.sin_family = AF_INET;
serv.sin_port = htons(atoi(argv[1]));
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
int a;
connect(sock, (struct sockaddr*)&serv, sizeof(serv));
while (1) {
nread = read(sock, buf, 1024);
in = popen(buf, "r");
while ((fgets(command, sizeof(command), in)) != NULL) {;
write(sock, command, sizeof(command));
}
memset(buf, 0, sizeof(buf));
}
return 0;
}

本质上客户端接收到服务器端扫描到的命令,使用popen()执行,并逐行发送命令行内容直到NULL

问题是代码在第一个命令之后突然停止工作。命令的传输和命令的输出令人满意,但是在打印第一个命令的输出后,程序就停止工作了。我认为 fgets() 有问题,但我可能是错的。这个问题有什么解决方案吗?

最佳答案

警告:这可能 [或可能不] 满足您的需求,因为我在下面更正的代码中颠倒了客户端和服务器循环的意义。正如我在上面的评论中提到的:

像这样的应用程序的正常方向是客户端连接到服务器,客户端将命令 [从 stdin 读取] 提供给服务器 [它执行 popen ] 并反馈结果。 ssh 就是这样工作的。你的方向颠倒了。你得到的是你触发 sshd 并等待 ssh 连接,然后 sshd 将命令发送到 ssh .换言之,双方的循环应该互换。

扭转这种局面是让事情对我有意义的唯一方式。如果逆转对于您想要的用例没有 [很好] 起作用,下面的代码可能仍然会给您一些想法。

我通过引入标志 字符的概念来表示输出结束来解决挂起问题。我从 RS-232 上的 PPP [点对点] 协议(protocol)中借用了这个概念。

标志字符只是一个给定值(例如 0x10),它不太可能是正常数据的一部分。由于您的数据很可能是 asciiutf-8,因此可以使用 0x00-0x1F 范围内的任何 [unused] 字符(即不要'使用制表符、cr、换行符等)。

如果您需要传输标志字符(即您的数据必须是完整的二进制范围 0x00-0xFF),我已经包含了一些数据包编码/解码实现上述 PPP 中使用的转义码的例程。我已经对它们进行了编码,但实际上并没有将它们 Hook 。在这种情况下,标志 [和转义] 字符可以是任何二进制值[通常是 0xFF0xFE 分别].

为简单起见,我将双方合并到一个 .c 文件中。使用 -s [first] 调用服务器。

无论如何,这是经过测试的代码[请原谅不必要的样式清理]:

// inetpair/inetpair -- server/client communication

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

typedef unsigned char byte;

#define BUFMAX 1024
int port = 1234;
int opt_svr;
int opt_debug;

#define FLAG 0x10
#define ESC 0x11
#define ESC_FLAG 0x01
#define ESC_ESC 0x02

#define dbgprt(_fmt...) \
do { \
if (opt_debug) \
printf(_fmt); \
} while (0)

// client
int
client(void)
{
int sock;
struct sockaddr_in serv = { 0 };
char *cp;
char buf[BUFMAX + 1];
int nread;
int flag;
int exitflg;

sock = socket(AF_INET, SOCK_STREAM, 0);

serv.sin_family = AF_INET;
serv.sin_port = htons(port);
serv.sin_addr.s_addr = inet_addr("127.0.0.1");

connect(sock, (struct sockaddr *) &serv, sizeof(serv));

while (1) {
cp = fgets(buf,BUFMAX,stdin);
if (cp == NULL)
break;

exitflg = (strcmp(buf,"exit\n") == 0);

// send the command
nread = strlen(buf);
write(sock, buf, nread);

if (exitflg)
break;

while (1) {
dbgprt("client: PREREAD\n");
nread = read(sock, buf, 1024);
dbgprt("client: POSTREAD nread=%d\n",nread);
if (nread <= 0)
break;

cp = memchr(buf,FLAG,nread);
flag = (cp != NULL);
if (flag)
nread = cp - buf;

write(1,buf,nread);

if (flag)
break;
}
}

close(sock);

return 0;
}

// server
int
server(void)
{
struct sockaddr_in serv_addr = { 0 };
int sock;
int acc_sock;
char buf[BUFMAX + 1];
char command[BUFMAX + 1];
ssize_t nread;
FILE *pin;
FILE *xfin;
char *cp;
struct sockaddr_in cli_addr = { 0 };

opt_debug = ! opt_debug;

dbgprt("[+] Starting\n");

sock = socket(AF_INET, SOCK_STREAM, 0);

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sock, 128);

while (1) {
socklen_t cli_addrlen = sizeof(cli_addr);

dbgprt("[+] Waiting for connection\n");
acc_sock = accept(sock,(struct sockaddr *)&cli_addr,&cli_addrlen);

dbgprt("[+] Connected\n");

xfin = fdopen(acc_sock,"r");

while (1) {
dbgprt("[+] Waiting for command\n");

cp = fgets(buf,BUFMAX,xfin);
if (cp == NULL)
break;

cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;

dbgprt("[+] Command '%s'\n",buf);

if (strcmp(buf,"exit") == 0)
break;

pin = popen(buf, "r");
while (1) {
cp = fgets(command, BUFMAX, pin);
if (cp == NULL)
break;
nread = strlen(command);
write(acc_sock, command, nread);
}
pclose(pin);

command[0] = FLAG;
write(acc_sock,command,1);
}

fclose(xfin);
close(acc_sock);

dbgprt("[+] Disconnect\n");
}
}

// packet_encode -- encode packet
// RETURNS: (outlen << 1)
int
packet_encode(void *dst,const void *src,int srclen)
{
const byte *sp = src;
byte *dp = dst;
const byte *ep;
byte chr;
int dstlen;

// encode packet in manner similar to PPP (point-to-point) protocol does
// over RS-232 line

ep = sp + srclen;
for (; sp < ep; ++sp) {
chr = *sp;

switch (chr) {
case FLAG:
*dp++ = ESC;
*dp++ = ESC_FLAG;
break;

case ESC:
*dp++ = ESC;
*dp++ = ESC_ESC;
break;

default:
*dp++ = chr;
break;
}
}

dstlen = dp - (byte *) dst;
dstlen <<= 1;

return dstlen;
}

// packet_decode -- decode packet
// RETURNS: (outlen << 1) | flag
int
packet_decode(void *dst,const void *src,int srclen)
{
const byte *sp = src;
byte *dp = dst;
const byte *ep;
byte chr;
int flag;
int dstlen;

// decode packet in manner similar to PPP (point-to-point) protocol does
// over RS-232 line

ep = sp + srclen;
flag = 0;
while (sp < ep) {
chr = *sp++;

flag = (chr == FLAG);
if (flag)
break;

switch (chr) {
case ESC:
chr = *sp++;

switch (chr) {
case ESC_FLAG:
*dp++ = FLAG;
break;
case ESC_ESC:
*dp++ = ESC;
break;
}
break;

default:
*dp++ = chr;
break;
}
}

dstlen = dp - (byte *) dst;
dstlen <<= 1;

if (flag)
dstlen |= 0x01;

return dstlen;
}

int
main(int argc, char **argv)
{
char *cp;

--argc;
++argv;

for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;

switch (cp[1]) {
case 'd':
opt_debug = 1;
break;

case 'P':
port = atoi(cp + 2);
break;

case 's':
opt_svr = 1;
break;
}
}

if (opt_svr)
server();
else
client();

return 0;
}

关于c - 使用 popen() 通过套接字执行命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35443876/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com