【问题标题】:Transmission of audio file using c sockets使用 c 套接字传输音频文件
【发布时间】:2018-01-16 17:21:23
【问题描述】:

我正在尝试使用 c 中的套接字编程将音频文件从一台计算机发送到另一台计算机。当我发送没有任何框架信息(例如标题或尾部)的简单字符串时,它会完美发送。但是,当我尝试使用一些标头信息(如 socket_data 或 packet_no 的大小)发送相同的信息时。它没有正确发送。甚至两台机器上的终端输出都相同,但创建的文件完全不同且无法播放。我已经使用序列化概念来发送数据包。我附上代码。请评论出了什么问题。

Server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>

void set_socket(struct sockaddr_in *socket, int type, int host_short, int addr_type)
{
    socket -> sin_family = type;
    socket -> sin_port = htons(host_short);
    socket -> sin_addr.s_addr = htonl(addr_type);
}

void serialize(char *buffer, int count, char *data)
{
    int i=0, j=0;
    char temp1[20];

    sprintf(temp1, "%d", count);
    while(temp1[i] != '\0')
    {
        buffer[j++] = temp1[i++];
    }
    buffer[j++]=' ';

    for(i=0; data[i] != '\0'; i++)
    {
        buffer[j++] = data[i];
    }
    buffer[j] = '\0';
    printf("BUFFER =%ld\n", sizeof(buffer));
}

int main()
{
    int sid = 0, bid = 0, fp;
    char *send_data = (char *)malloc(1024*sizeof(char));
    char temp[1024];
    char *receive_data = (char *)malloc(1024*sizeof(char));
    int fd, count, cnt=0;
    struct sockaddr_in server_socket, client_socket;
    int size = sizeof(client_socket);

    if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    {
        printf("Connection error..\n");
        exit(1);
    }

    set_socket(&server_socket, AF_INET, 6000, INADDR_ANY);

    if((bid = bind(sid, (struct sockaddr *)&server_socket, sizeof(struct sockaddr))) == -1)
    {
        printf("Binding error..\n");
        exit(1);
    }

    printf("I am waiting for client..\n");

    recvfrom(sid, receive_data, 1024, 0,(struct sockaddr *)&client_socket, &size);
    printf("received data is : %s\n", receive_data);
    fd = open(receive_data, O_RDONLY);
    printf("size = %ld\n", sizeof(send_data));

    while((count=read(fd, temp, 500)) != 0)
    {
        printf("I am inside the loop : %d\n", cnt++);
        serialize(send_data, count, temp);
        printf("Serialized : %s\n", send_data);
        sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
    }
    printf("I am outside the loop : %d\n", count);
    strcpy(temp, "ENDOFFILE");
    serialize(send_data, sizeof(temp), temp);
    sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);

    fcloseall();
    close(sid);
    close(fd);
    return 0;
}

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>

void set_socket(struct sockaddr_in *socket, int type, int host_short)
{
    socket -> sin_family = type;
    socket -> sin_port = htons(host_short);
}

void deserialize(char *buffer, int *size, char *data)
{
    int i=0, j=0;
    char temp1[20];

    while(buffer[i] != ' ')
    {
        temp1[j++] = buffer[i++];
    }
    temp1[j] = '\0';
    printf("\nINT : %s\n", temp1);
    *size = atoi(temp1);

    i++;
    j=0;

    while(buffer[i] != '\0')
    {
        data[j++] = buffer[i++];
    }
    data[j++] = '\0';
}

int main()
{
    int sid = 0, bid = 0, con = 0;
    char *send_data = (char *)malloc(1024*sizeof(char));
    char *receive_data = (char *)malloc(1024*sizeof(char));
    char *temp = (char *)malloc(1024*sizeof(char));
    struct hostent *host;
    struct sockaddr_in server_socket;
    int size = sizeof(server_socket);

    if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    {
        printf("Connection error at client side..\n");
        exit(1);
    }

    set_socket(&server_socket, AF_INET, 6000);

    if (inet_aton("127.0.0.1", &server_socket.sin_addr)==0) 
    {
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    }

    printf("Enter the name of the file you want to see : ");
    scanf("%s", send_data);
    int fd = open("sanket.mp3", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR);
    sendto(sid, send_data, 1024, 0, (struct sockaddr *)&server_socket, size);
    printf("================= Contents of the File =====================\n");
    while(1)
    {
        int size;
        recvfrom(sid, temp, 1024, 0, (struct sockaddr *)&server_socket, &size);
        printf("Deserialize it : %s\n",temp);
        deserialize(temp, &size, receive_data);
        if(!strcmp(receive_data, "ENDOFFILE"))
        {
            printf("============================================================\n");
            break;
        }
        else
            write(fd, receive_data, size);
    }
    fcloseall();
    close(sid);

    return 0;
}

当我检查发送和接收文件的大小时,大小相同但内容不同,因此我无法播放接收到的音频文件。

【问题讨论】:

  • 可能与字节序有关。机器之间的编码是否也可能不同?
  • 看起来您正在通过 UDP 而不是 TCP 发送文件。这是故意的吗?
  • 如果您选择使用 TCP 而不是 UDP,来自另一篇文章的答案可能会对您有所帮助:stackoverflow.com/a/666788/34329
  • RichardJ.RossIII : 该程序甚至无法在单机上运行。 grieve : 是的,我故意通过 UDP 发送数据包。

标签: c sockets audio serialization


【解决方案1】:

您似乎正在从二进制数据文件中读取数据,但在您的 serialize 函数中,您将数据视为以空字符结尾的字符串数据。比如serialize里面的这个循环:

for(i=0; data[i] != '\0'; i++)
{
    buffer[j++] = data[i];
}

将在遇到的第一个零值处终止。如果这是来自您的音频文件的真正二进制数据,那么我相信您会得到0 值,这些值是实际的音频数据,而不是指示缓冲区的结尾。您应该终止传递给serialize 的缓冲区大小,而不是终止NULL 值,该大小是在while 循环中对read 的调用中读取的。这样您就可以确保将从您的 read 调用中读取的所有数据打包到您的发送缓冲区中。

其次,打印sizeof(buffer),当buffer 是指针时,只会打印指针类型的大小,而不是指针指向的实际缓冲区的大小。同样,您必须将该值显式传递给您的 serialize 函数。

第三,你正在用一个空值终止缓冲区......再次,这不是一个好主意,基于第一点关于这是原始二进制数据而不是空终止字符串。您应该提出某种类型的字符串来指示缓冲区中的传输结束,这将是一组不可能成为数据一部分的值,或者您应该显式读取字节数在您嵌入数据包数据的“计数”中。

最后,您并没有真正序列化您的数据......序列化的概念通常意味着以独立于平台的方式传输数据。您只是打包读取的字节并通过网络发送它们,假设接收端具有相同的字节顺序等。一个相当简单的序列化方法会做一些事情,比如从所有数据值创建 ASCII 字符串,但缺点是这将造成相当多的数据膨胀。序列化数据还有其他跨平台标准,如 JSON、SOAP 等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2013-04-27
    • 1970-01-01
    相关资源
    最近更新 更多