Заставить клиента непрерывно отвечать на сообщения с сервера

#c #client-server

#c #клиент-сервер

Вопрос:

Я пишу простое клиент-серверное приложение, и у меня возникают проблемы с тем, чтобы заставить клиента непрерывно отвечать на отправленные ему сообщения (на данный момент, echo).

client.c

 #define BUF_SIZE 1024

int ctrlsockfd;

void error(const char *message);
void closeStreams();
void writeResponse(const char *message);

int main (int argc, const char *argv[]) {
    printf("Clientn");

    // Connection code snipped

    // Handle responses
    int bytes_read;
    char buffer[BUF_SIZE];
    while (1) {
        // Fetch a message
        bytes_read = read(ctrlsockfd, buffer, BUF_SIZE);

        if (bytes_read == -1) {
            error("Failed to read");
        }

        // Send it back
        if (write(ctrlsockfd, buffer, strlen(buffer)   1) == -1) {
            error("Failed to write");
        }
    }

    // Disconnect
    closeStreams();

    return 0;
}
  

host.c

 #define BUF_SIZE 1024
#define LISTENPORT 9735

void closeStreams();
void error(const char *message);

int ctrlsockfd, clientsockfd;

int main (int argc, const char *argv[]) {
    printf("Servern");

    // Connection code snipped

    // Accept a request (blocking) - we can only connect to one client at a time
    clientlen = sizeof(clientaddr);
    clientsockfd = accept(ctrlsockfd, (struct sockaddr *) amp;clientaddr, (socklen_t*) amp;clientlen);
    if (clientsockfd == -1) {
        error("Error accepting");
    }

    while (1) {
        // Read input string from stdin
        printf("> ");
        char message[BUF_SIZE];
        if (scanf("%s", message) == -1) {
            error("Failed to read from terminal");
        }

        // Send to client
        if (write(clientsockfd, message, strlen(message)   1) == -1) {
            error("Failed to send message");
        } else {
            printf("Sent message %sn", message);
        }

        // Read response from client
        char response[BUF_SIZE];
        if (read(clientsockfd, response, BUF_SIZE) == -1) {
            error("Error reading response");
        } else {
            printf("Response: %sn", response);
        }

        // Close the connection
        closeStreams();
    }
}
  

В чем здесь проблема?

Ответ №1:

Я думаю, вы путаете сервер и клиент здесь. Обычно сервер прослушивает порт и ожидает сообщений, а затем отвечает на них. Кроме того, accept() должен быть частью цикла, если вы закрываете соединение на каждой итерации или, альтернативно, не закрываете соединение.

 Server       client
wait
             connect
             send data
read data
send data
             read data
<maybe iteration of send / receive here >
close        close
wait
...
  

Комментарии:

1. Да, в моем случае мне нужно поменять роли местами, чтобы вы могли просто поменять имена — мне также нужно слушать запросы только одного клиента.

2. @Ross — хорошо, все же обратите внимание, что вы по какой-то причине закрываете соединение в конце цикла работы сервера, если вы хотите продолжить отправку данных, вам не следует закрывать соединение.

3. Ах, вот в чем была проблема — спасибо за вашу помощь (и по другому вопросу)!

Ответ №2:

Здесь немного больше ошибок, но я бы сразу сделал это:

 // Send it back
if (bytes_read > 0 amp;amp; write(ctrlsockfd, buffer, strlen(buffer)   1) == -1) {
     error("Failed to write");
} 
  

Любопытно, что делали эти записи, когда ничего не было прочитано…

Комментарии:

1. О, понятно, извините, я не подумал об этом должным образом — я предполагал, что read будет блокироваться до тех пор, пока не будут прочитаны байты.

2. Я не знаю, какая у вас точная среда, но в какой-то момент при чтении сокета наступает тайм-аут и возвращается ошибка тайм-аута.

3. Есть ли способ предотвратить это (т. Е. Без тайм-аута) или лучший шаблон, который я должен использовать?