似乎无法使 C TCP 服务器-客户端通信正确

标签 c tcp client-server

好的,我需要一些认真的帮助。我必须制作一个 TCP 服务器客户端。当客户端使用三阶段握手连接到服务器时。之后...当客户端在终端中运行时,用户输入 linux shell 命令,如 xinput list、ls -1 等...使用标准输出的东西。服务器接受命令并使用 system()(在无限循环中的 fork() 中)运行命令,标准输出被重定向到客户端,客户端打印出每一行。

随后服务器发送一个“\377\n”的完成信号。其中客户端返回命令提示符请求新命令并在输入“退出”时关闭其连接和 exit()。

我知道您必须将 STDOUT_FILENO 和 STDERR_FILENO dup2() 到客户端文件描述符 {dup2(client_FD, STDOUT_FILENO)。一切正常,除了客户端检索 system() 的标准输出并将其打印出来...我得到的只是一个空白行,光标闪烁(客户端等待标准输入)。我尝试了各种不同的路线并在互联网上广泛搜索但无济于事......如果有人能指出我正确的方向,我将不胜感激

TCP 服务器代码

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

//Prototype
void handle_client(int connect_fd);


int main()
{
    int server_sockfd, client_sockfd;
    socklen_t server_len, client_len;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;

    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(9734);
    server_len = sizeof(server_address);
    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

/*  Create a connection queue, ignore child exit details and wait for clients.  */

    listen(server_sockfd, 10);

    signal(SIGCHLD, SIG_IGN);

    while(1) {

        printf("server waiting\n");

        client_len = sizeof(client_address);
        client_sockfd = accept(server_sockfd,
            (struct sockaddr *)&client_address, &client_len);

        if(fork() == 0)
            handle_client(client_sockfd);
        else
            close(client_sockfd);
    }
}

void handle_client(int connect_fd) {

    const char* remsh         = "<remsh>\n";
    const char* ready         = "<ready>\n";
    const char* ok            = "<ok>\n";
    const char* command       = "<command>\n";
    const char* complete      = "<\377\n";
    const char* shared_secret = "<shapoopi>\n";

    static char server_msg[201];
    static char client_msg[201];
    static char commands[201];

    int sys_return;

    //memset client_msg, server_msg, commands
    memset(&client_msg, 0, sizeof(client_msg));
    memset(&server_msg, 0, sizeof(client_msg));
    memset(&commands, 0, sizeof(commands));
    //read remsh from client
    read(connect_fd, &client_msg, 200);
    //check remsh validity from client
    if(strcmp(client_msg, remsh) != 0) {
        errno++;
        perror("Error Establishing Handshake");
        close(connect_fd);
        exit(1);
    }
    //memset client_msg
    memset(&client_msg, 0, sizeof(client_msg));
    //write remsh to client
    write(connect_fd, remsh, strlen(remsh));
    //read shared_secret from client
    read(connect_fd, &client_msg, 200);
    //check shared_secret validity from client
    if(strcmp(client_msg, shared_secret) != 0) {
        errno++;
        perror("Invalid Security Passphrase");
        write(connect_fd, "no", 2);
        close(connect_fd);
        exit(1);
    }
    //memset client_msg
    memset(&client_msg, 0, sizeof(client_msg));
    //write ok to client
    write(connect_fd, ok, strlen(ok));
    // dup2  STDOUT_FILENO <= client fd, STDERR_FILENO <= client fd
    dup2(connect_fd, STDOUT_FILENO);
    dup2(connect_fd, STDERR_FILENO);
    //begin while... while read (client_msg) from server and >0
    while(read(connect_fd, &client_msg, 200) > 0) {
        //check command validity from client
        if(strcmp(client_msg, command) != 0) {
            errno++;
            perror("Error, unable to retrieve data");
            close(connect_fd);
            exit(1);
        }
        //memset client_msg
        memset(&client_msg, 0, sizeof(client_msg));
        //write ready to client
        write(connect_fd, ready, strlen(ready));
        //read commands from client
        read(connect_fd, &commands, 200);
        //run commands using system( )
        sys_return = system(commands);
        //check success of system( )
        if(sys_return < 0) {
            perror("Invalid Commands");
            errno++;
        }
        //memset commands
        memset(commands, 0, sizeof(commands));
        //write complete to client
        write(connect_fd, complete, sizeof(complete));

    }
}

TCP 客户端代码

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "readline.c"

int main(int argc, char *argv[])

{
    int sockfd;
    int len;
    struct sockaddr_in address;
    int result;

    const char* remsh         = "<remsh>\n";
    const char* ready         = "<ready>\n";
    const char* ok            = "<ok>\n";
    const char* command       = "<command>\n";
    const char* complete      = "<\377\n";
    const char* shared_secret = "<shapoopi>\n";

    static char server_msg[201];
    static char client_msg[201];

    memset(&client_msg, 0, sizeof(client_msg));
    memset(&server_msg, 0, sizeof(server_msg));

/*  Create a socket for the client.  */

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

/*  Name the socket, as agreed with the server.  */
    memset(&address, 0, sizeof(address));

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(argv[1]);
    address.sin_port = htons(9734);
    len = sizeof(address);

/*  Now connect our socket to the server's socket.  */

    result = connect(sockfd, (struct sockaddr *)&address, len);

    if(result == -1) {
        perror("ACCESS DENIED");
        exit(1);
    }

    //write remsh to server
    write(sockfd, remsh, strlen(remsh));
    //read remsh from server
    read(sockfd, &server_msg, 200);
    //check remsh validity from server
    if(strcmp(server_msg, remsh) != 0) {
        errno++;
        perror("Error Establishing Initial Handshake");
        close(sockfd);
        exit(1);
    }
    //memset server_msg
    memset(&server_msg, 0, sizeof(server_msg));
    //write shared secret text to server
    write(sockfd, shared_secret, strlen(shared_secret));
    //read ok from server
    read(sockfd, &server_msg, 200);
    //check ok velidity from server
    if(strcmp(server_msg, ok) != 0 ) {
        errno++;
        perror("Incorrect security phrase");
        close(sockfd);
        exit(1);
    }
    //? dup2 STDIN_FILENO = server socket fd?
    //dup2(sockfd, STDIN_FILENO);
    //begin while(1)///////////////////////////////////////
    while(1){
        //memset both msg arrays
        memset(&client_msg, 0, sizeof(client_msg));
        memset(&server_msg, 0, sizeof(server_msg));
        //print Enter Command, scan input, fflush to stdout
        printf("<<Enter Command>> ");
        scanf("%s", client_msg);
        fflush(stdout);
        //check quit input, if true close and exit successfully
        if(strcmp(client_msg, "quit") == 0) {
            printf("Exiting\n");
            close(sockfd);
            exit(EXIT_SUCCESS);
        }
        //write command to server
        write(sockfd, command, strlen(command));
        //read ready from server
        read(sockfd, &server_msg, 200);
        //check ready validity from server
        if(strcmp(server_msg, ready) != 0) {
            errno++;
            perror("Failed Server Communications");
            close(sockfd);
            exit(1);
        }
        //memset server_msg
        memset(&server_msg, 0, sizeof(server_msg));
        //begin looping and retrieving from stdin,
        //break loop at EOF or complete
        while((read(sockfd, server_msg, 200) != 0) && (strcmp(server_msg, complete) != 0)) {
        //while((fgets(server_msg, 4096, stdin) != EOF) || (strcmp(server_msg, complete) == 0)) {
            printf("%s", server_msg);
            memset(&server_msg, 0, sizeof(server_msg));
        }
    }
}

最佳答案

我正在浏览代码并在我的 Ubuntu 机器上试用它,我得到了与 Vincent Czubatiuk 所描述的相同的结果。然后我决定检查代码并稍微调试一下。 我发现需要进行两次更正才能使其按预期工作。

1) TCP 客户端代码在 memset server_msg 之后缺少一行,其中通过 scanf 输入的命令未发送到服务器即:

//memset server_msg
write(sockfd, client_msg, strlen(client_msg));
memset(&server_msg, 0, sizeof(server_msg));

2) 第一次更正后,命令在服务器端执行,并将输出发送回客户端。但是它无法继续,因为系统返回错误。此处提供解决方案 C++: system(0) Returns 0 .这需要进行以下更改:

listen(server_sockfd, 10);
//signal(SIGCHLD, SIG_IGN);

希望这对您有所帮助。

关于似乎无法使 C TCP 服务器-客户端通信正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13713415/

相关文章:

c - 除了调用 free() 之外,有没有办法确定指针是否可以传递给 free()?

c - int 数组的动态内存分配

c - 指向 C 中指针的指针

python - Python TCP 套接字 recv(1) 与 recv(n) 的效率

c# - 如何在 C# 中正确设置 MySQLConnection?

C 在动态二维数组中存储字符串文字

go - 向代理发送 TCP 数据包

android - 尝试通过 TCP 通过 adb 连接到 Android 设备时显示 “error: closed”

java - 来回发送对象到线程

通过 REST Json 的 JavaFX2 客户端-服务器