#c #sockets #audio #wav
#c #сокеты #Аудио #wav
Вопрос:
Отправка обычного файла .txt работает отлично. Но если я попытаюсь отправить файл .wav, генерируемый выходной файл будет лишь частью размера входного файла (и он ничего не воспроизводит). Я перепробовал практически все, что смог найти в Google, возможно, это как-то связано с тем, что я не читал .wav-файл правильно. Но я читаю и записываю по одному символу за раз, поэтому я не знаю, почему это должно быть проблемой. Кроме того, это делается через localhost. Любая помощь будет принята с благодарностью, спасибо!
server.c
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFFER_SIZE 32
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, n;
socklen_t clilen, servlen;
char buffer[BUFFER_SIZE];
FILE *fp;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port providedn");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) amp;serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) amp;serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
servlen = sizeof(serv_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) amp;cli_addr,
amp;clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer, BUFFER_SIZE);
n = read(newsockfd, buffer, BUFFER_SIZE);
if (n < 0) error("ERROR reading from socket");
printf("Received file name: %sn", buffer);
fp = fopen(buffer, "rb");
if (fp == NULL)
printf("File open failed!n");
else
printf("File successfully opened!n");
while (1) {
bzero(buffer, BUFFER_SIZE);
char ch;
int i;
for (i = 0; i < BUFFER_SIZE; i ) {
ch = fgetc(fp);
buffer[i] = ch;
if (ch == EOF)
break;
}
n = write(newsockfd, buffer, BUFFER_SIZE);
if (n < 0)
error("ERROR writing to socket");
if (ch == EOF)
break;
}
printf("File sending complete...n");
if (fp != NULL)
fclose(fp);
close(newsockfd);
close(sockfd);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define BUFFER_SIZE 32
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[BUFFER_SIZE];
FILE *out;
if (argc < 3) {
fprintf(stderr,"usage %s hostname portn", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such hostn");
exit(0);
}
bzero((char *) amp;serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)amp;serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) amp;serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Enter the file name: ");
bzero(buffer, BUFFER_SIZE);
fgets(buffer, BUFFER_SIZE - 1, stdin);
buffer[strlen(buffer) - 1] = '';
n = write(sockfd, buffer, strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
out = fopen("out.wav", "wb");
while (1) {
bzero(buffer, BUFFER_SIZE);
int i, j;
n = read(sockfd, buffer, BUFFER_SIZE);
if (n < 0)
error("ERROR reading from socket");
char ch;
for (i = 0; i < BUFFER_SIZE; i ) {
ch = buffer[i];
if (ch == EOF)
break;
j = (int)ch;
fputc(j, out);
}
if (ch == EOF)
break;
}
printf("File write complete... You can now use the output file!!n");
if (out != NULL)
fclose(out);
close(sockfd);
return 0;
}
Комментарии:
1.
ch = buffer[i]; if (ch == EOF)
Это выглядит неправильно.read
никогда не сохранитсяEOF
в буфере. На самом деле это невозможно, посколькуEOF
этоint
не achar
.2.
char ch; ch = fgetc(fp); if (ch == EOF)
Аналогично, это тоже неправильно.fgetc
возвращаетint
. Это важно, какEOF
int
и .3.
for (i = 0; i < BUFFER_SIZE; i )
. Это тоже неправильно. Вы предполагаете, что каждыйread
получит полныйBUFFER_SIZE
. Это распространенное недоразумение. Для потоковых протоколов, таких как TCP, каждое чтение может принимать переменное количество байтов. Необходимо использовать возвращаемое значениеread
, а не просто предполагатьBUFFER_SIZE
. Как бы то ни было, вы, вероятно, записываете в файл непреднамеренные нули.4. @kaylum Я имею в виду, что вы можете быть правы. Но я просто попытался напечатать внутри этого оператора if, чтобы посмотреть, соответствует ли он чему-либо (ch == EOF когда-либо становится true), и это действительно так. Кроме того, если это было проблемой, разве отправка файлов .txt также не должна работать? Спасибо!
5. И я прошу прощения, если это показалось мне покровительственным. Никто не знает уровень знаний человека по другую сторону клавиатуры. После некоторого использования SO вы видите много людей, которые все еще изучают основы и указывают даже на простые вещи, которые часто помогают им. Многие люди действительно думают, что прохождение одного теста означает, что их код не содержит ошибок (они даже говорят это явно).
Ответ №1:
Чтобы определить окончание передачи, вы должны проверить возвращаемое значение read() , а не проверять наличие EOF в прочитанных данных. Я также взял на себя смелость реструктурировать и упростить ваш код.
Рассмотрим следующие (непроверенные) изменения:
server.c:
// ...
while (1) {
size_t num_read = fread(buffer, 1, BUFFER_SIZE, fp);
if (num_read == 0) // end of file.
break;
n = write(newsockfd, buffer, num_read);
if (n < 0) // Error
error("ERROR writing to socket");
else if (n == 0) // Could handle this too
break;
}
// ...
client.c:
// ...
while (1) {
n = read(sockfd, buffer, BUFFER_SIZE);
if (n < 0)
error("ERROR reading from socket");
else if (n == 0) // Socket closed. Transfer is complete (or borked)
break;
fwrite(buffer, 1, n, out); // Could check fwrite too.
}
// ...
Комментарии:
1. Попробовал, код теперь выглядит намного, намного проще, и проблема, похоже, устранена. Большое спасибо!