首页 > 解决方案 > 在 C 中将结构写入文本文件

问题描述

我想要做的是在 C 中解析一个文件(WireShark 解析器到一个小描述符文件)。

我设法解析成功(结构中的值是正确的),但是当我写入文本文件时,它在最后添加了一行空值(添加的空值的数量总是等于我写的结构的数量到文件)。比如我写了6行,所以最后加了6个null。

我很想知道是否有人可以确定问题所在。

这是我使用的写宏:

#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, "\n");

} 

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

这由客户端-服务器解决方案处理。这是客户端,我将其发送到服务器,如下所示:

/*
============================================
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\n", 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;
}

在服务器端,我接收它并将其写入文件(添加了一个额外的空行),如下所示:

/*
===================================================
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\n", 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;
}

标签: cfilesocketsmacrostransfer

解决方案


如果设置正确(您没有显示),您对write_to_file()我来说看起来不错。lua_line

但是,您对send()and的处理recv()都是错误的。返回值是发送/接收的字节数,而不是bool像您对待它的那样。而且,返回值可能小于请求的字节数,您无需检查是否必须再次调用send()/recv()来发送/接收更多字节(类似于您正在执行的操作fwrite())。

如果文件大于send_file()您的buffer. 并且write_to_lua()循环也可能会在其中接收太多字节,并在将其写入输出文件时buffer忽略实际。这很可能是您额外的 nuls 的来源。filesizebuffer

尝试更多类似的东西:

客户:

/*
============================================
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;
}

服务器:

/*
============================================
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\n", 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;
}

推荐阅读