Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
180 views
in Technique[技术] by (71.8m points)

Writing a Struct to Text file in C

What I am trying to do is to parse a file (WireShark dissector into a little descriptor file) in C.

I managed to parse successfully (the values in the struct are correct), but when I write to the text file, it adds a row of null values at the end (the number of nulls added are always equal to the number of structs I wrote to the file). For example, I wrote 6 lines, so 6 nulls were added at the end.

I would love to know if someone could identify what the problem is.

This is the write macro I use:

#define WRITE_F(file_name,modifier,value) fprintf(file_name,"%"#modifier,value);
//the used function - **space_val = " "**
void write_to_file(FILE* lua_descriptor, lua_line *line)
{
    WRITE_F(lua_descriptor,s, line->name);
    WRITE_F(lua_descriptor,s, line->str_size);
    WRITE_F(lua_descriptor,c, SPACE_VAL);
    WRITE_F(lua_descriptor,d, line->opcode);
    WRITE_F(lua_descriptor, s, "
");

} 

//the lua_line struct:
typedef struct lua_line{
    char * name;
    char * str_size;
    int opcode;
}lua_line;

This is handled by a client-server solution. This is the client side and I am sending it to the server like so:

/*
============================================
General : function is responsible for sending the length of the file to the server
Parameters : sock - socket connection between client and server
             *filesize - holds a pointer to the size that needs to be sent
             filesize_len - the length of the file size pointer

Return Value : returns TRUE when the length of the data was sent correctly.
returns FALSE when there was a socket error.
============================================
*/
bool send_file_length(SOCKET sock, long* filesize, int filesize_len)
{
    bool retval = true;
    unsigned char* pbuf = (unsigned char*)filesize;
    int num = send(sock, pbuf, filesize_len, 0);
    if (num == SOCKET_ERROR){retval = false;}
    return retval;
}

/*
============================================
General : transfers the size to network byte order
and sends data to the server
Parameters : sock - socket for the client - server connection
             filesize - the value of the file size

Return Value : returns TRUE when the length of the data was sent correctly.
returns FALSE when there was a socket error. 

============================================
*/
bool convert_size(SOCKET sock, long filesize)
{
    printf("file size  %d
", filesize);
    filesize = htonl(filesize);
    return send_file_length(sock, &filesize, sizeof(filesize));
}

/*
============================================
General : function is responsible of sending the new lua
file to the server
Parameters : sock - socket between the client and the server
             f - file that needs to be sent to the server

Return Value : returns TRUE when the file was sent correctly
returns FALSE when the file is empty or when there was a socket error
============================================
*/
bool send_file(SOCKET sock, FILE* f)
{
    bool retval = true;
    fseek(f, 0, SEEK_END);
    long filesize = ftell(f);
    char buffer[BUFFER_SIZE];
    rewind(f);
    if (filesize == EOF) { retval = false; }
    if (retval && !convert_size(sock, filesize)) { retval = false; }
    if (filesize > 0 && retval){
        while (filesize > 0 && retval){
            size_t num = filesize;
            num = fread(buffer, 1, num, f);
            if (num < 1) {
                retval = false;
            }
            if (!send(sock, buffer, num, 0)){
                retval = false;
            }
            filesize -= num;
        }
    }
    return retval;
}

And on the server side, I receive and write it to the file (which adds an extra null line) like so:

/*
===================================================
General : receives the length of the file and updates it

Parameters : sock - client socket to receive the data from
             *filesize - holds a pointer to the size of the buffer that needs to update
             filesize_len - the length of the file size pointer
Return Value : returns TRUE when the size is read correctly
               else, FALSE when there was a socket error or no bytes are received.
===================================================
*/
bool recv_file_len(SOCKET sock, long* filesize, int filesize_len)
{
    unsigned char* psize = (unsigned char*)filesize;//changes the pointer type so we can receive the data to it from recv
    bool retval = true;
    int num = recv(sock, psize, filesize_len, 0);//receive to size
    if (num == SOCKET_ERROR)
    {
        retval = false;
    }
    else if (num == 0)
    {
        retval = false;
    }
    return retval;
}

/*
===================================================
General : writes to the lua file the data from the file
that was received in the socket
Parameters : sock - the socket between the client and server
             *f - the file to write the data received to
Return Value : returns TRUE when everything was written to the file.
returns FALSE if there's no data received or detected a socket problem.
===================================================
*/
bool write_to_lua(SOCKET sock, FILE *f)
{
    long filesize;//size of address
    char buffer[BUFFER_SIZE];
    ZeroMemory(buffer, BUFFER_SIZE);
    bool retval = recv_file_len(sock, &filesize, sizeof(filesize));
    if (retval)//if the size of the file didn't fail to update
    {
        filesize = ntohl(filesize);
        printf("file size (From C client) : %ld
", filesize);
        while (filesize > 0 && retval)
        {
            int num = filesize;
            if (!recv(sock, buffer, sizeof(buffer), 0))//reads the data
            {
                retval = false;
            }
            int offset = 0;
            while (offset < num && retval)//writes to the file
            {
                size_t written = fwrite(&buffer[offset], 1, num - offset, f);
                //size_t written = fprintf(f,&buffer[offset]);
                if (written < 1)
                {
                    retval = false;
                }
                offset += written;
            }
            filesize -= num;
        }
    }
    return retval;
}
question from:https://stackoverflow.com/questions/65922128/writing-a-struct-to-text-file-in-c

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your write_to_file() looks fine to me, provided the lua_line is being setup correctly (which you did not show).

However, your handling of send() and recv() is all wrong. The return value is the number of bytes sent/received, not a bool like you are treating it. And, the return value may be smaller than the number of bytes requested, which you are not checking for to know if you have to call send()/recv() again to send/receive more bytes (similar to what you are doing for fwrite()).

You also have a potential buffer overflow in the send_file() loop, if the file is larger than your buffer. And the write_to_lua() loop is also potentially receiving too many bytes into its buffer and ignoring the actual filesize when writing that buffer to the output file. Which is likely where your extra nuls are coming from.

Try something more like this instead:

Client:

/*
============================================
General : function is responsible for sending the length of data to the server
Parameters : sock - socket connection between client and server
             *buf - holds a pointer to the data that needs to be sent
             bufsize - the length of the data pointer

Return Value : returns TRUE when the length of the data was sent correctly.
returns FALSE when there was a socket error. 
============================================
*/
bool send_raw(SOCKET sock, void* buf, int bufsize)
{
    unsigned char* pbuf = (unsigned char*)buf;
    while (bufsize > 0) {
        int num = send(sock, pbuf, bufsize, 0);
        if (num == SOCKET_ERROR){ return false; }
        pbuf += sent;
        bufsize -= sent;
    }
    return true;
}

/*
============================================
General : function is responsible for sending the length of the file
to the server in network byte order
Parameters : sock - socket connection between client and server
             filesize - the value of the file size

Return Value : returns TRUE when the length of the data was sent correctly.
returns FALSE when there was a socket error. 
============================================
*/
bool send_file_length(SOCKET sock, long filesize)
{
    filesize = htonl(filesize);
    return send_raw(sock, &filesize, sizeof(filesize));
}

/*
============================================
General : function is responsible of sending the new lua
file to the server
Parameters : sock - socket between the client and the server
             f - file that needs to be sent to the server

Return Value : returns TRUE when the file was sent correctly
returns FALSE when the file is empty or when there was a socket error
============================================
*/
bool send_file(SOCKET sock, FILE* f)
{
    if (fseek(f, 0, SEEK_END) != 0) { return false; }
    long filesize = ftell(f);
    rewind(f);
    if (filesize == -1L) { return false; }
    if (!send_file_length(sock, filesize)) { return false; }
    if (filesize > 0) {
        char buffer[BUFFER_SIZE];
        do {
            size_t num = fread(buffer, 1, min(filesize, BUFFER_SIZE), f);
            if (num < 1) { return false; }
            if (!send_raw(sock, buffer, num)) { return false; }
            filesize -= num;
        }
        while (filesize > 0);
    }
    return true;
}

Server:

/*
============================================
General : function is responsible for receiving a length of data from the client
Parameters : sock - client socket to receive the data from
             *buf - holds a pointer to the buffer that needs to update
             bufsize - the length of the buffer

Return Value : returns TRUE when the data is read correctly
               else, FALSE when there was a socket error or no bytes are received.
============================================
*/
bool recv_raw(SOCKET sock, void* buf, int bufsize)
{
    unsigned char* pbuf = (unsigned char*)buf;
    while (bufsize > 0) {
        int num = recv(sock, pbuf, bufsize, 0);
        if (num <= 0) { return false; }
        pbuf += num;
        bufsize -= num;
    }
    return true;
}

/*
===================================================
General : receives the length of the file and updates it

Parameters : sock - client socket to receive the data from
             *filesize - holds a pointer to the size of the buffer that needs to update
             filesize_len - the length of the file size pointer
Return Value : returns TRUE when the size is read correctly
               else, FALSE when there was a socket error or no bytes are received.
===================================================
*/
bool recv_file_len(SOCKET sock, long* filesize)
{
    if (!recv_raw(sock, filesize, sizeof(*filesize)) { return false; }
    *filesize = ntohl(*filesize);
    return true;
}

/*
===================================================
General : writes to the lua file the data from the file
that was received in the socket
Parameters : sock - the socket between the client and server
             *f - the file to write the data received to
Return Value : returns TRUE when everything was written to the file.
returns FALSE if there's no data received or detected a socket problem.
===================================================
*/
bool write_to_lua(SOCKET sock, FILE *f)
{
    long filesize;//size of address
    if (!recv_file_len(sock, &filesize)) { return false; }
    printf("file size (From C client) : %ld
", filesize);
    if (filesize > 0)
    {
        char buffer[BUFFER_SIZE];
        do {
            int num = min(filesize, BUFFER_SIZE);
            if (!recv_raw(sock, buffer, num)) { return false; }
            int offset = 0;
            do
            {
                size_t written = fwrite(&buffer[offset], 1, num - offset, f);
                if (written < 1) { return false; }
                offset += written;
            }
            while (offset < num);
            /* alternatively, no loop is needed:
            if (fwrite(buffer, num, 1, f) < 1) { return false; }
            */
            filesize -= num;
        }
        while (filesize > 0);
    }
    return true;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...