警告: 这可能(或可能不)满足您的需求,因为我在下面的更正代码中反转了客户端和服务器循环的含义。正如我在上面的评论中提到的:
像这样的应用程序的正常方向是,客户端连接到服务器,并且客户端将命令[从stdin
]
读取到服务器[这样做popen
]并反馈结果。就是这样ssh
。您的方向相反。您所拥有的是您开火sshd
并等待ssh
连接,然后sshd
将命令发送至ssh
。换句话说,应切换各侧的回路。
扭转这种局面是使事情对我有意义的唯一途径。如果在您想要的用例中逆转无法正常进行,则下面的代码可能仍会为您提供一些建议。
我通过引入 标记 字符的概念来表示输出结束来解决挂起问题。我从
PPP[点对点]协议中借用了这个概念
RS-232。
标志字符只是一个给定的值(例如
0x10),不太可能是正常数据的一部分。由于您的数据很有可能是
ascii或
utf-8,因此
0x00-0x1F可以使用该范围内的任何[未使用]字符(即,不要使用tab,cr,换行符等)。
如果您 需要
发送标志字符(即您的数据必须是完整的二进制范围
0x00-0xFF),我已经包括了一些实现
PPP上面使用的转义码的数据包编码/解码例程。我编写它们,但实际上并没有钩他们。在这种情况下,该标志[和逃生]字符可以是
任意 的二进制值通常
0xFF和
0xFE分别。
为简单起见,我将双方合并为一个
.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 1024int 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)// clientintclient(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,"exitn") == 0); // send the command nread = strlen(buf); write(sock, buf, nread); if (exitflg) break; while (1) { dbgprt("client: PREREADn"); nread = read(sock, buf, 1024); dbgprt("client: POSTREAD nread=%dn",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;}// serverintserver(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("[+] Startingn"); 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 connectionn"); acc_sock = accept(sock,(struct sockaddr *)&cli_addr,&cli_addrlen); dbgprt("[+] Connectedn"); xfin = fdopen(acc_sock,"r"); while (1) { dbgprt("[+] Waiting for commandn"); 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("[+] Disconnectn"); }}// packet_enpre -- enpre packet// RETURNS: (outlen << 1)intpacket_enpre(void *dst,const void *src,int srclen){ const byte *sp = src; byte *dp = dst; const byte *ep; byte chr; int dstlen; // enpre 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_depre -- depre packet// RETURNS: (outlen << 1) | flagintpacket_depre(void *dst,const void *src,int srclen){ const byte *sp = src; byte *dp = dst; const byte *ep; byte chr; int flag; int dstlen; // depre 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;}intmain(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;}


