使用 C 中的套接字通过 TCP 发送音频文件
Sending an audio file over TCP using sockets in C
发送普通的 .txt 文件效果很好。但是如果我尝试发送一个 .wav 文件,生成的输出文件只是输入文件大小的一小部分(而且它不播放任何东西)。我已经尝试了几乎所有我能在 Google 上找到的东西,这可能与没有正确读取 .wav 文件有关。但是我一次读写一个字符,所以我不知道为什么这会成为一个问题。此外,通过本地主机执行此操作。任何帮助将不胜感激,谢谢!
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 provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &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 *) &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 *) &cli_addr,
&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: %s\n", 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 port\n", 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 host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &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] = '[=11=]';
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;
}
要确定传输结束,您必须检查 read() 的 return 值,而不是检查读取数据中的 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.
}
// ...
发送普通的 .txt 文件效果很好。但是如果我尝试发送一个 .wav 文件,生成的输出文件只是输入文件大小的一小部分(而且它不播放任何东西)。我已经尝试了几乎所有我能在 Google 上找到的东西,这可能与没有正确读取 .wav 文件有关。但是我一次读写一个字符,所以我不知道为什么这会成为一个问题。此外,通过本地主机执行此操作。任何帮助将不胜感激,谢谢!
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 provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &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 *) &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 *) &cli_addr,
&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: %s\n", 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 port\n", 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 host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &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] = '[=11=]';
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;
}
要确定传输结束,您必须检查 read() 的 return 值,而不是检查读取数据中的 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.
}
// ...