Как читать и писать tar-файл в C?

Я хочу прочитать tar-файл и записать его в другой файл tar, используя C. Процедура, которую я здесь проделал:

  1. Создание файла tar из папки
  2. Написание программы-сокета для чтения этого файла tar в виде двоичного файла в C с использованием функции fread
  3. Запись любых сообщений в буфере в сокет
  4. Запись программы сокета сервера для приема отправленных данных в буфер
  5. Запись полученного буфера в другой файл tar.
  6. Закрытие файлов и сокетов.

Вот код:

Server.c

#include  #include  #include  #include  #include  #include  #include  #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  #include  #include  #include  #include  #include  #include  #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 и send, как если бы они были строками:

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

Используйте это вместо отправки только len байтов.

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

Аналогично, серверная программа должна просто написать полученные len байты. Добавление '\0' может привести к переполнению буфера, и запись байтов strlen(buf) не сможет записать все полученные байты, если принимается байт NUL, как это будет, если будет передан tar-файл:

Измените логику так:

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

Вы также можете использовать утилиту netcat: man nc

Существует несколько версий libtar , библиотека для чтения и записи файлов архива tar в C. Вы должны использовать его.

Если вы используете сеть через tcp (7) сокеты (7) (например, в Linux или POSIX), помните, что TCP / IP – это просто stream байтов без какого-либо понятия сообщения: операция отправки (2) (или write ) на излучающая сторона не обязательно соответствует одной операции recv (2) (или read ) на стороне приема, «пакеты» могут быть fragmentированы или повторно собраны (например, промежуточными маршрутизаторами или вашим сетевым оборудованием или controllerом или уровнем ядра). Таким образом, вы всегда должны буферизировать и управлять количеством байтов операций частичного read , send , write , recv .