使用 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.
}
// ...