Сокет-сервер в C застрял при вызове функции send () и не проходит через нее - PullRequest
0 голосов
/ 25 января 2020

Я пытаюсь сделать так, чтобы клиент / сервер Socket работал одновременно, передавая информацию друг другу. Проблема в том, что после отправки первой части данных от клиента сервер возвращает ответ правильно, но застревает при вызове функции send(), отключая возможность для сервера получать другие данные от клиента.

Я использую следующие фрагменты кода на сервере и клиенте:

Код клиента

char requestToSend[1000] = "Some request";
int client_socket;
struct sockaddr_in servaddr;
client_socket = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(PORT);
connect(client_socket, (SA*)&servaddr, sizeof(servaddr));

char buffer[MAX];
bzero(buffer, sizeof(buffer));
send(server_socket, requestToSend, sizeof(requestToSend), 0);

bzero(requestToSend, sizeof(requestToSend));
while (strcmp(requestToSend, "") == 0) {
    recv(server_socket, requestToSend, sizeof(requestToSend), 0);
}

shutdown(client_socket, SHUT_RDWR);
printf("Received: %s", requestToSend); // requestToSend is not the received result!

Код сервера

Следующий код должен возвращать «Мой новый результат» в ответ на любой запрос от клиента.

while (1) {
    int server_socket, client_socket;
    struct sockaddr_in server, client;
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        printf("Socket creation failed...\n");
    } else {
        printf("Socket successfully created..\n");
    }
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(PORT);

    if ((bind(server_socket, (SA*)&server, sizeof(server))) != 0) {
        printf("Socket binding failed...\n");
    } else {
        printf("Socket successfully bound..\n");
    }

    if ((listen(server_socket, 5)) != 0) {
        printf("Listen failed...\n");
    } else {
        printf("Server listening..\n");
    }

    socklen_t len = sizeof(client);
    client_socket = accept(server_socket, (SA*)&client, &len);
    if (client_socket < 0) {
        printf("Server accceptance failed...\n");
    } else {
        printf("Server acccepted the client..\n");
    }

    char buffer[MAX];
    bzero(buffer, sizeof(buffer));
    recv(client_socket, buffer, sizeof(buffer), 0);
    strcpy(buffer, "My new result");
    send(client_socket, buffer, sizeof(buffer), 0);
    shutdown(server_socket, SHUT_RDWR);
}

Есть и другие вопросы о переполнении стека, в которых упоминается проблема застревания send(), но они не дают ответа на этот вопрос.

1 Ответ

0 голосов
/ 25 января 2020

Вы должны открывать и привязывать сокет сервера только один раз. L oop должен начинаться до вызова accept(). И вы должны закрыть клиентский сокет, а не просто позвонить shutdown().

Когда вы отправляете ответ, вы должны просто отправить strlen(buffer)+1 байтов, а не sizeof(buffer). Последний отправит MAX байтов, которые будут включать много неинициализированных байтов. Добавление 1 к strlen() будет включать нулевой байт.

int server_socket, client_socket;
struct sockaddr_in server, client;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
    printf("Socket creation failed...\n");
} else {
    printf("Socket successfully created..\n");
}
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORT);

if ((bind(server_socket, (SA*)&server, sizeof(server))) != 0) {
    printf("Socket binding failed...\n");
} else {
    printf("Socket successfully bound..\n");
}

if ((listen(server_socket, 5)) != 0) {
    printf("Listen failed...\n");
} else {
    printf("Server listening..\n");
}

while (1) {
    socklen_t len = sizeof(client);
    client_socket = accept(server_socket, (SA*)&client, &len);
    if (client_socket < 0) {
        printf("Server accceptance failed...\n");
    } else {
        printf("Server acccepted the client..\n");
    }

    char buffer[MAX];
    bzero(buffer, sizeof(buffer));
    recv(client_socket, buffer, sizeof(buffer), 0);
    strcpy(buffer, "My new result");
    send(client_socket, buffer, strlen(buffer)+1, 0);
    close(client_socket);
}

Клиент recv() l oop должен l oop, пока не получит 0, что означает, что сервер закрыл разъем. Каждый вызов должен добавляться в буфер, а не перезаписывать его.

char *ptr = requestToSend;
size_t len = sizeof(requestToSend);
int nread;
while ((nread = recv(server_socket, ptr, len, 0)) != 0) {
    if (nread < 0) {
        perror("recv from server");
        exit(1);
    }
    ptr += nread;
    len -= nread;
}

И он также должен закрывать сокет, а не использовать shutdown(). shutdown() обычно используется только тогда, когда вы хотите наполовину закрыть сокет - вы хотите отправить EOF в другую систему, но продолжаете читать ее ответы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...