Проблема с простым клиентом / сервером, файл печатается неправильно - PullRequest
0 голосов
/ 01 февраля 2019

По сути, сервер должен напечатать в файл структуру, заполненную клиентом, и клиент, и сервер должны остановиться, когда message.fine == 1. Проблема в том, что каждый раз, когда файл создается, он заполняется тысячаминуля, что означает, что функция чтения и записи не работает правильно.Не могли бы вы помочь мне с этой проблемой?

Это клиент:

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

struct Data 
{
    int a;
    float b;
    int fine;
    int risultato;
};

int main()
{   
    int sock;
    struct Data message, response;
    message.fine = 0;

    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_port = htons(6869);
    address.sin_addr.s_addr = inet_addr("127.0.0.1");

    sock = socket(AF_INET, SOCK_STREAM, 0);

    connect(sock, (struct sockaddr *)&address, sizeof(address));

    while(message.fine != 1)
    {   
        printf("\nInsert an integer number:");
        scanf("%d", &message.a);
        printf("\nInsert a float number:");
        scanf("%f", &message.b);
        printf("\nIs this the final message? (0 = no, 1 = yes)\n");
        scanf("%d", &message.fine);


        write(sock, &message, sizeof(struct Data));
        read(sock, &response, sizeof(struct Data));

        if(response.risultato == -1)
        {
            fprintf(stderr, "\nServer returned Writing Error\n");
            exit(EXIT_FAILURE);
        }
        else if(response.risultato == 1)
        {
            printf("\nSuccess in Operation\n");
        }
    }
    close(sock);
    exit(EXIT_SUCCESS);
}

И это сервер:

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

struct Data 
{
    int a;
    float b;
    int fine;
    int risultato;
};



void * handler(void * args)
{
    struct Data message;    
    int sock = *(int *)args;
    FILE *fp;

     if(!(fp = fopen("result.txt", "a")))
        {
        fprintf(stderr, "Error in opening file\n");
        exit(EXIT_FAILURE);
        }

    while(1)
    {

        read(sock, &message, sizeof(struct Data));

        printf("%d, %f, %d", message.a, message.b, message.fine);

        if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
        {
            message.risultato = -1;
        }
        else{
            message.risultato = 1;
        }

        if(message.fine == 1)
        {
            break;
        }
        write(sock, &message, sizeof(struct Data));

    }
    fclose(fp);
    close(sock);
    free(args);
    pthread_exit(NULL);
}


int main()
{
    int sock, client_sock;
    int * new_sock;

    pthread_t tid;

    struct sockaddr_in address, client_address;
    address.sin_family = AF_INET;
    address.sin_port = htons(6869);
    address.sin_addr.s_addr = inet_addr("127.0.0.1");

    socklen_t sock_len = (socklen_t)sizeof(address);


    sock = socket(AF_INET, SOCK_STREAM, 0);

    bind(sock, (struct sockaddr *)&address, sock_len);

    listen(sock, 3);

    while(1)
    {
       new_sock = (int *)malloc(sizeof(int));
       sock_len = sizeof(client_address);
       client_sock = accept(sock, (struct sockaddr *)&client_address, &sock_len); 
       *new_sock = client_sock;       
       pthread_create(&tid, NULL, handler, (void *)new_sock);
       pthread_detach(tid);
    }

}

Фактический результат должен бытьчисла в файлах message.a и message.b печатаются последовательно в файле.

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Ваш код чтения на стороне клиента / сервера должен быть изменен, чтобы проверить возвращаемое значение вызова чтения.Помните, что когда вы используете SOCK_STREAM, все отправленные данные отправляются и принимаются в виде потока (не в виде дейтаграмм), что приводит к объединению данных последующих отправлений и, таким образом, не требует получения всех данных одного отправления водин переход на другую сторону.

Измененный фрагмент кода сервера (просто псевдокод), пожалуйста, проверьте и измените исходный код соответствующим образом:

while(1)
{
    int res_bytes = 0;
    int res = 0;
    while (res_bytes < sizeof(struct Data))
    {
        res = read(sock, &message+res_bytes, (sizeof(struct Data) - res_bytes));
        if ((res == 0) || (res == -1))
        {
            printf("read returned an error, returning");
            return;
        }
        res_bytes = res_bytes + res;
    }

    printf("%d, %f, %d", message.a, message.b, message.fine);

    if(fprintf(fp,"\n[%d] [%.2f]\n", message.a, message.b) < 0)
    {
        message.risultato = -1;
    }
    else{
        message.risultato = 1;
    }

    if(message.fine == 1)
    {
        break;
    }
    res = write(sock, &message, sizeof(struct Data));
    if ((res == 0) || (res == -1))
    {
       printf("Error while writing");
       return;
    }
}
0 голосов
/ 01 февраля 2019

Спасибо @bruno и @Jay за помощь и за все предложения.Я расположил часть для чтения следующим образом:

do{

   res = read(sock, &message, sizeof(struct Data));

  }while(res < sizeof(struct Data));

То же самое для записи, и теперь она работает!

PS Я заметил, что если я не очищаю поток файлов после fprintfбыл успешным, файл не печатается, он печатает его после разрыва цикла.Почему это происходит?

0 голосов
/ 01 февраля 2019

Проблема в том, что каждый раз, когда файл создается, он заполняется тысячами нулей, что указывает на то, что функция чтения и записи не работала правильно

Предупреждение вы используете SOCK_STREAM, у вас нет гарантии на чтение всех ожидаемых байтов на one read.

На сервере вам нужно проверить результат

   read(sock, &message, sizeof(struct Data));

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

Вероятный сценарий, который у вас был: во время обменов (может быть первым) на сервере read не читает всю структуру, потому что message.fine не установленов 1 и некоторые другие значения тоже не установлены, потому что message.fine != 1 вы повторяете цикл и снова читаете, но из непрочитанных байтов, а не с начала структуры, так что даже вы читаете sizeof(Data) байтов в то время, когда структура не очень хорошозаполнено, и снова message.fine не установлено в 1, а другие атрибуты не установлены с правильным значением и т. д., и в данный момент нечего читать, и вы зацикливаетесь бесконечно, потому что сообщение остается неизменным.

Конечно, я рекомендую вам также проверить результат записи , и у вас возникает такая же проблема, когда вы читаете в своем клиенте

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