C сокет периодически сбрасывает соединение и не получает полный запрос от python запросов - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть программа python, с которой я хочу связаться с программой C через http. Я использую запросы в python для отправки некоторых json данных в сокет в C.

Иногда python выдает ошибку «сброс соединения по одноранговой сети», и я не могу понять это. Когда я получаю эту ошибку, программа C отправляет и получает все содержимое, кроме содержимого запроса. В моем приложении я также делаю запросы от клиента, написанного в Go. С этим клиентом я никогда не получаю эти ошибки, поэтому я думаю, что мне не хватает какой-то конфигурации или простого решения в библиотеке запросов. Почему это происходит и что может решить мою проблему?

Вот простой пример; Я не очень знаком с сокетами:

Сервер C:

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

#define RECV_BUF_SIZE 1024

int main(void)
{
    struct sockaddr_in serv_addr, cli_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(8080);

    int option = 1;
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
    if (socketfd < 0)
    {
        perror("failed to start socket");
        exit(1);
    }

    if (bind(socketfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
    {
        perror("failed to bind");
        exit(1);
    }

    if (listen(socketfd, 1000) != 0)
    {
        perror("listen error");
        exit(1);
    }

    char buf[RECV_BUF_SIZE];

    while (1)
    {
        int addrlen = sizeof(cli_addr);
        int clientfd = accept(socketfd, (struct sockaddr*) &cli_addr, &addrlen);
        if (clientfd < 0)
        {
            perror("accept error");
        }
        else
        {
            int n_recv = recv(clientfd, buf, RECV_BUF_SIZE, 0);

            // print everything, character by character.
            char* tmp_buf = buf;
            while (n_recv--) printf("%c", *tmp_buf++);
            printf("\n\n****************************\n\n");

            FILE* res = fdopen(clientfd, "w");
            fprintf(res, "HTTP/1.1 200 OK\r\n\r\n");
            fclose(res);
            shutdown(clientfd, SHUT_RDWR);
            close(clientfd);
        }
    }
}

Сценарий запроса Python:

import requests

json_data = {
    "hello": "thanks"
}

requests.post("http://localhost:8080", json=json_data)

Спасибо вам! * * 1013

1 Ответ

1 голос
/ 30 апреля 2020

относительно связи сервера с клиентом, есть несколько небольших проблем, таких как неправильные типы переменных и отсутствие проверки ошибок.

Я поставил свои комментарии перед >> и использовал условную компиляцию, чтобы показать, как я заменил определенные части кода OP с предлагаемыми улучшениями.

Предупреждение: поскольку сервер не знает Ожидаемое количество байтов для получения от клиента, ответ не включает в себя все oop, пытаясь получить все байты, ожидаемые от клиента

char buf[ RECV_BUF_SIZE +1 ];  // >> +1 for string terminator

while (1)
{
    // >> the third parameter is a 'socklen_t', not an 'int'
    socklen_t addrlen = sizeof(cli_addr);
    int clientfd = 
        accept(socketfd, (struct sockaddr*) &cli_addr, &addrlen);
    if (clientfd < 0)
    {
        perror("accept error");
    }

    else
    {
        // >>recv() returns a `ssize_t`, not an `int`
        ssize_t n_recv = recv(clientfd, buf, RECV_BUF_SIZE, 0);

        #if 0

            // >>this takes WAY too long, so the connection
            // >>could timeout
            // print everything, character by character.
            char* tmp_buf = buf;
            while (n_recv--) printf("%c", *tmp_buf++);

        #else

            if( n_recv < 0 )
            {  // then an error occurred
                perror( "recv failed" );
                write( clientfd, 
                       "receive error", 
                       sizeof( "receive error" ) );
                close( clientfd );
            }

            else if( n_recv == 0 )
            {  // then client closed connection
                printf( "%s\n", 
                        "client closed connection" );
                close( clientfd );
            }

            else
            { // some data received from client
                buf[ n_recv ] = '\0';  // terminate string
                printf( "%s\n", buf );
            }

        #endif

        printf("\n\n****************************\n\n");

        #if 0

            FILE* res = fdopen(clientfd, "w");
            fprintf(res, "HTTP/1.1 200 OK\r\n\r\n");
            fclose(res);
            shutdown(clientfd, SHUT_RDWR);
            close(clientfd);

        #else

            ssize_t writeBytes;
            if( (writeBytes = 
                 write( clientfd, 
                        "HTTP/1.1 200 OK\r\n\r\n", 
                        strlen( "HTTP/1.1 200 OK\r\n\r\n" ) ) ) 
                        != strlen( "HTTP/1.1 200 OK\r\n\r\n" ) )
            { // then incomplete write
                printf( "%s\n",  
                        "write didn't write all bytes to client" );
            }

            close( clientfd );

        #endif
    }
}
...