Remote Commander

ตัวอย่างโปรแกรมประยุกต์เพื่อใช้ในการส่งชุดคำสั่งระยะไกล เพื่อให้ไปประมวลผลคำสั่งที่เครื่องปลายทาง (server.c) แล้วส่งผลลัพธ์กลับมายังเครื่องที่สั่งการ (client.c) โดยใช้เทคนิคการสื่อสารด้วย socket ดังตัวอย่างข้างล่างนี้

โปรแกรม server.c

// server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 8080

// Function to execute shell commands and return results.
void execute_command(char* command, char* result, int resultBufferSize) {
    FILE* pipe = popen(command, "r");
        if (!pipe) {
            strcpy(result, "popen() failed!");
            return;
        }

        char buffer[128];
        int totalBytesRead = 0;
        while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
            int bytesRead = strlen(buffer);
            // Make sure we don't exceed the buffer size
            if (totalBytesRead + bytesRead >= resultBufferSize) {
                break;
            }
            strcat(result, buffer); // Append the new data to the total result
            totalBytesRead += bytesRead;
        }

        if (pclose(pipe) != 0) {
            // Handle errors reported by pclose(),
            // perhaps appending a message to the result
        }
}

int main(int argc, char const *argv[]) {
    int server_fd, new_socket; 
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char result[1024];

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the PORT 8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Binding socket to the PORT 8080
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // Display the server's IP and listening port
    char host[256];
    char *IP;
    struct hostent *host_entry;
    gethostname(host, sizeof(host));
    host_entry = gethostbyname(host);
    IP = inet_ntoa(*((struct in_addr*) host_entry->h_addr_list[0]));

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    printf("Server is running at IP: %s on Port: %d\n", IP, PORT);

    // Main loop to keep server running and accepting new connections
    while (1) {
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        printf("Connection established...\n");

        // Communication loop with the connected client
        while (1) {
            memset(buffer, 0, BUFFER_SIZE); // Clear the buffer
            int read_size = read(new_socket, buffer, BUFFER_SIZE);
            if (read_size > 0) {
                printf("Received command: %s\n", buffer);

                // Special case: close connection if client sends "exit"
                if (strcmp(buffer, "exit") == 0) {
                    printf("Closing connection...\n");
                    close(new_socket);
                    break; // Break out of the inner loop to start accepting new connections
                }

                // Execute the command
                execute_command(buffer, result, sizeof(result));
                // printf("Command result: %s\n", result);

                send(new_socket, result, strlen(result), 0);
                printf("Result sent back to client\n");
                memset(result, 0, BUFFER_SIZE); // Clear the result buffer

            } else {
                printf("Client disconnected or read error...\n");
                close(new_socket);
                break; // Break out of the inner loop to start accepting new connections
            }
        }
    }

    return 0;
}

เพื่อให้โปรแกรมสั่งการ (client.c) ทำตัวเองเหมือน Shell terminal ในการรันคำสั่งจากผู้ใช้ โดยใช้ตามมาตราฐาน VT100/ANSI Terminal จึงต้องมีการติดตั้ง library ที่ชื่อว่า libreadline-dev ก่อน เพื่อเรียกใช้ในโปรแกรม client.c ได้ดังนี้

ทำการคอมไพล์โปรแกรมทั้งสอง โดยสร้างหน้าต่าง terminal 2 หน้าต่าง ดังนี้

Last updated

Was this helpful?