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

有人可以帮我实现以下服务器和客户端吗?

服务器:

#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。换句话说,应切换各侧的回路。

扭转这种局面是使事情对我有意义的唯一途径。如果在您想要的用例中逆转无法正常进行,则下面的代码可能仍会为您提供一些建议。

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

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

如果您 需要

发送标志字符(即您的数据必须是完整的二进制范围0x00-0xFF),我已经包括了一些实现PPP上面使用的转义码的数据包编码/解码例程。我编写它们,但实际上并没有钩他们。在这种情况下,该标志[和逃生]字符可以是

任意 的二进制值通常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;

}

以上是 使用popen()通过套接字执行命令 的全部内容, 来源链接: utcz.com/qa/410168.html

回到顶部