使用UNIX域套接字延迟输出

时间:2016-03-06 21:56:02

标签: c linux unix debian unix-socket

我正在尝试编写一个简单的服务器和客户端,它将充当shell,在C中。 服务器以系统命令的形式从客户端接收数据,执行它们并将输出重定向到套接字。然后客户端读取套接字,并将其打印到stdout。当我输入像path = os.path.expanduser("~").decode(sys.getfilesystemencoding()) sqlite3.connect(os.path.join(path, u"test.db")) import ctypes import os def getEnvironmentVariable(name): name= unicode(name) # make sure string argument is unicode n= ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0) if n==0: return None buf= ctypes.create_unicode_buffer(u'\0'*n) ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n) return buf.value if 'HOME' in os.environ: userhome = getEnvironmentVariable('HOME') elif 'USERPROFILE' in os.environ: userhome = getEnvironmentVariable('USERPROFILE') sqlite3.connect(os.path.join(userhome, u"test.db")) 这样的现有系统命令时它很有效,并且它也适用于参数。所以ls工作正常。 但是,当我输入一个无法识别的命令时,服务器或客户端(我不知道哪一个)会滑动,输出会以某种方式延迟。我会告诉你我的意思。

这是我的df

ls -l

这是我的server.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define SOCK_PATH "echo_socket"

int main(void)
{
    int s, s2, t, len;
    struct sockaddr_un local, remote;
    char str[1024];

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, SOCK_PATH);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    if (bind(s, (struct sockaddr *)&local, len) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(s, 5) == -1) {
        perror("listen");
        exit(1);
    }

    for(;;) {
        int done, n;
        printf("Waiting for a connection...\n");
        t = sizeof(remote);
        if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
            perror("accept");
            exit(1);
        }

        printf("Connected.\n");

        done = 0;
        do {
            memset(str,0,strlen(str));
            n = recv(s2, str, 1024, 0);
            if (n <= 0) {
                if (n < 0) perror("recv");
                done = 1;
            }
            int cpid = fork();
            int e;
            if (cpid == 0)
            {
                printf("executing: %s\n", str);                
                dup2(s2, STDOUT_FILENO);
                dup2(s2, STDERR_FILENO);
                //system(str);
                execl("/bin/sh", "sh", "-c", str, (char *) 0)
                str[0] = 0;
                exit(0); 
            }
            wait();
        } while (!done);

        close(s2);
    }

    return 0;
}

以下是使用和输出的示例:

client.c

正如您所看到的,在我输入#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SOCK_PATH "echo_socket" int main(void) { int s, t, len; struct sockaddr_un remote; char str[1024]; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } printf("Trying to connect...\n"); remote.sun_family = AF_UNIX; strcpy(remote.sun_path, SOCK_PATH); len = strlen(remote.sun_path) + sizeof(remote.sun_family); if (connect(s, (struct sockaddr *)&remote, len) == -1) { perror("connect"); exit(1); } printf("Connected.\n"); while(str[0] = '\0', printf("Server shell> "), fgets(str, 1024, stdin), !feof(stdin)) { if (str[0] == '\n') continue; str[strlen(str) - 1] = '\0'; if (send(s, str, strlen(str), 0) == -1) { perror("send"); exit(1); } str[0] = '\0'; if ((t=recv(s, str, 1024, 0)) > 0) { str[t] = '\0'; printf("%s\n", str); } else { if (t < 0) perror("recv"); else printf("Server closed connection\n"); exit(1); } } close(s); return 0; } 之前,它无法正常识别。 有人可以帮帮我吗?如果您需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:3)

您的客户收到的回复不正确。

允许

recv接收任意数量的字节 - 从一个字节到可用的所有数据。

您只需拨打recv一次,这意味着您可能无法阅读整个回复。您需要继续调用它,直到您到达响应结束。但你怎么知道那是什么时候?

典型的方法是在发送响应之前发送响应的长度,或者在响应之后发送标记,这意味着&#34;响应已完成&#34;。如果您事先不知道答案,前者很难,所以你可以选择后者。

我建议使用NUL字节('\0')来标记响应的结束,因为它不应该出现在文本中。服务器应该在执行程序后发送一个,并且客户端应该继续接收和打印,直到它看到一个NUL字节。 (然后它应该将所有内容打印到NUL字节;您可能会在收到NUL字节的同一调用中收到部分响应!)