简单的客户端/服务器问题,文件打印错误

时间:2019-02-01 16:49:53

标签: c sockets pthreads

基本上,服务器需要将由客户端填充的结构打印到文件中,当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 :(得分:2)

  

问题在于,每次创建文件时,它都会填充成千上万个零,这表明读写功能无法正常工作

警告:您使用SOCK_STREAM,但不保证在一个读取时读取所有预期的字节。

在服务器中,您需要检查结果

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

出错时中断或重新读取,如果全部未读,则未读,或者如果读取的内容少于预期大小,则 message 完全或部分不变,或者在未设置时未设置在第一个循环中,您有一个机会可以循环到最后一次,当然,您在文件中打印的值也保持不变或无效。

您可能遇到的情况是:在服务器中的交换期间(可能是第一次), read 不会读取所有结构,因为未设置message.fine设置为1以及其他一些值也未设置,因为message.fine != 1再次循环并再次读取,但是从未读字节开始读取,而不是从结构的开头读取,因此即使您在那时读取sizeof(Data)字节, struct的填充不正确,并且message.fine再次未设置为1且其他属性未设置正确的值,依此类推,此刻没有什么可读取的,并且由于 message 而无限期地循环em>保持不变。

当然,我鼓励您也检查 write 的结果,当您在客户端读取内容时遇到同样的问题

答案 1 :(得分:1)

必须修改您的客户端/服务器端读取代码,以检查读取调用的返回值。请记住,当您使用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;
    }
}

答案 2 :(得分:0)

感谢@bruno和@Jay的帮助和所有建议。我这样安排阅读部分:

do{

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

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

相同的东西,现在可以了!

P.S。我注意到,如果在fprintf成功后不刷新文件流,则不会打印该文件,而是在循环中断后将其打印出来。为什么会这样?