如何在C中读写tar文件?

How to read and write tar file in C?

我想读取 tar 文件并使用 C 将其写入另一个 tar 文件。我在这里遵循的过程是:

  1. 正在创建文件夹的 tar 文件
  2. 编写客户端套接字程序以使用 fread 函数在 C 中将 tar 文件读取为二进制文件
  3. 将缓冲区中的任何内容写入套接字
  4. 编写服务器套接字程序以将发送的数据接收到缓冲区
  5. 正在将接收到的缓冲区写入另一个 tar 文件。
  6. 正在关闭文件和套接字。

这是代码:

Server.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define MAX 1024
#define SOCK_PATH "/tmp/foo"

int s, s2, t, len;
struct sockaddr_un local, remote;

void createSSocket()
{
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 
    {
        perror("socket");
        exit(1);
    }
    printf("\nServer Socket Created...");
}

void setSSocketPath()
{
    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, SOCK_PATH);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    printf("\nServer Socket Path Set...");
}

void bindSocket()
{
    if (bind(s, (struct sockaddr *)&local, len) == -1) 
    {
        perror("bind");
        exit(1);
    }
    printf("\nSocket Binded...");
}

void listenSocket()
{   
    if (listen(s, 5) == -1) 
    {
        perror("listen");
        exit(1);
    }
    printf("\nListening Socket...");
}

void acceptConnection()
{
    printf("\nWaiting for a connection...");
    t = sizeof(remote);
    if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) 
    {
        perror("accept");
        exit(1);
    }
    printf("\nServer Socket Connected...");
}

void closeSSocket()
{
    close(s);
    close(s2);
    printf("\nServer Socket Closed...");
}


void receiveTar()
{
    int len,ret;
    char buf[MAX] = {0};
    char path[MAX] = "/home/priyanka/Codes/3455.tgz";
    FILE* fp;
    fp = fopen(path,"wb");

    while((len = recv(s2,buf,MAX,0)) > 0)
    {
        buf[len] = 0;
        printf("\nReceived : %d",len);
        //fputs(buf,fp);
        //printf("%s",buf);
        ret = fwrite(buf,1,strlen(buf),fp);
        if(ret == -1)
        {
            perror("Error writing to file");
        }
        printf("    Write : %d",ret);
    }
    fclose(fp);
}

int main()
{
    createSSocket();    
    setSSocketPath();
    bindSocket();
    listenSocket();
    acceptConnection(); 

    receiveTar();

    closeSSocket();
    return 0;   
}

服务器程序的输出:

已创建服务器套接字...
服务器套接字路径设置...
套接字绑定...
侦听套接字...
正在等待连接...
服务器套接字已连接...
接收:1024 写入:1024
收到:459 写:459
收到:239 写:239
收到:529 写:529
接收:425 写入:425
收到:411 写:411
收到:493 写:493
收到:142 写:142
接收:1024 写入:1024
收到:397 写:397
收到:41 写:41
接收:158 写入:158
接收:1024 写入:1024
接收:705 写入:705
接收:505 写入:505
接收:1024 写入:1024
收到:87 写:87
接收:1024 写入:1024
接收:326 写入:326
接收:234 写入:234
接收:311 写入:311
收到:819 写:819
收到:571 写:571
接收:1024 写入:1024
接收:1024 写入:1024
收到:341 写:341
接收:243 写入:243
收到:630 写:630
收到:50 写:50
收到:35 写:35
接收:215 写入:215
服务器套接字已关闭...

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define MAX 1024
#define SOCK_PATH "/tmp/foo"


int s, t, len;
struct sockaddr_un remote;

void createCSocket()
{
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 
    {
        perror("socket");
        exit(1);
    }
    printf("\nClient Socket Created...");
}

void setCSocketPath()
{
    remote.sun_family = AF_UNIX;
    strcpy(remote.sun_path, SOCK_PATH);
    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
    printf("\nClient Socket Path Set...");
}

void connectSocket()
{
    printf("\nTrying to connect...");
    if (connect(s, (struct sockaddr *)&remote, len) == -1) 
    {
        perror("connect");
        exit(1);
    }
    printf("\nClient Connected...\n");
}

void closeCSocket()
{
    close(s);
    printf("\nClient Socket Closed...");
}

void sendTar()
{
    FILE *fp;
    int ret,len;
    char buf[MAX] = {0};
    fp = fopen("/home/priyanka/3455.tgz","rb");
    while(len = fread(buf,1,1024,fp))
    //while((buf[0] = fgetc(fp)) != EOF)
    {
        printf("\nRead : %d",len);
        ret = send(s,buf,strlen(buf),0);
        printf("    Sent : %d",ret);
        if(ret == -1)
        {
            perror("Error sending data : Client");
        }
    }
    fclose(fp);
}

int main()
{
    createCSocket();
    setCSocketPath();
    connectSocket();

    sendTar();

    closeCSocket(); 
    return 0;
}

客户端程序的输出:

已创建客户端套接字...
客户端套接字路径设置...
正在尝试连接...
客户端已连接...

读取:1024 发送:3
读取:1024 发送:1027
读取:1024 发送:273
读取:1024 发送:180
读取:1024 发送:239
读取:1024 发送:529
读取:1024 发送:425
读取:1024 发送:411
读取:1024 发送:493
读取:1024 发送:142
读取:1024 发送:1027
读取:1024 发送:394
读取:1024 发送:41
读取:1024 发送:158
读取:1024 发送:702
读取:1024 发送:1027
读取:1024 发送:503
读取:1024 发送:2
读取:1024 发送:1027
读取:1024 发送:84
读取:1024 发送:1027
读取:1024 发送:323
读取:1024 发送:234
读取:1024 发送:311
读取:1024 发送:819
读取:1024 发送:571
读取:1024 发送:1027
读取:1024 发送:1027
读取:1024 发送:335
读取:1024 发送:243
读取:1024 发送:630
读取:1024 发送:50
读取:1024 发送:35
读取:315 发送:215
客户端套接字已关闭...

我正面临这样的问题:

  1. 无论我在客户端程序中读取什么,实际发送的只有几个字节,接收函数仍在读取最大字节数。而我希望我的程序读取 1024 个字节,发送 1024 个字节,接收 1024 个字节并写入 1024 个字节,这在这种情况下不会发生。发送缓冲区长度是否有助于解决问题??

  2. 是我使用正确的方法通过套接字发送 tar 文件还是有不同的方法?

  3. 如何查看数据读取、发送、接收、写入是否成功??

您正在使用 fread 读取二进制文件并像发送字符串一样发送块:

        ret = send(s,buf,strlen(buf),0);

改用此方法仅发送 len 个字节。

        ret = send(s,buf,len,0);

同样,服务器程序应该只写入收到的 len 个字节。附加 '[=16=]' 可能会导致缓冲区溢出,如果收到 NUL 字节,写入 strlen(buf) 字节将无法写入收到的所有字节,如果 tar 文件是肯定会出现这种情况转发:

将逻辑更改为:

    ret = fwrite(buf,1,len,fp);

您可能还想使用 netcat 实用程序:man nc

有几个版本的 libtar,一个用 C 语言读取和写入 tar 归档文件的库。你应该使用它。

如果在接收方通过 tcp(7) sockets(7) (e.g. on Linux or POSIX), remember that TCP/IP is just a stream of bytes without any notion of message: a send(2) (or write) operation on the emitting side does not necessarily correspond to a single recv(2)(或 read)操作使用网络,"packets" 可能已被分段或重新组装(例如,通过中间路由器或您的网络硬件或控制器或内核层)。因此,您始终应该缓冲和管理部分 readsendwriterecv 操作的字节数。