C:丢失UDP数据包的最后字节数

时间:2014-10-01 13:31:00

标签: c sockets stream udp recvfrom

我正在编写基于UDP的流媒体服务器并遇到一个奇怪的问题,我确信它只是一个简单的错误,但我找不到解决方案。服务器按照以下方式执行:

FILE* infile = fopen(inf, "rb");
register int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int16_t buffer[LENGTH+HEADER];
struct header header;
int16_t data[LENGTH];
uint32_t number = 0;

/*set socket options etc. */

while(!feof(infile)){
    fread(data, 1, LENGTH, infile);
    /* if i write the contents of data to a file here, the error below occurs*/
    fwrite(data, 1, LENGTH, testfile);
    /*create a header, encode everything with htons/htonl*/


    if(sendto(sock, buffer, LENGTH+HEADER, 0, (struct sockaddr*) &to,
                    sizeof to) < 0)
         /*die*/            
}

这似乎有效。我可以解码它,数据没有损坏。但是,我写了一个测试客户端,可以工作(或者更确切地说:不工作),如下所示:

struct sockaddr_in si_other, si_me;
register int s;
unsigned int slen = sizeof(si_other);
int16_t buf[LENGTH+HEADER];
int16_t data[LENGTH];
FILE* file = fopen(of, "wb");

/*open socket, set options, etc. */

while(1){
    if(recvfrom(s, (char *)buf, LENGTH+HEADER, 0, (struct sockaddr*) &si_other,
                 &slen) < 0)
        /*die*/    
    decode(buf, data);
    /* If I write the decoded data to a file here, the error below occurs */
    fwrite(data, 1, LENGTH, testfile);
    if(is_empty(data) == 0){
        printf("End signal received.\n");
        break;
    }
} 

现在我的问题。当我用diff <(xxd test_before) <(xxd test_after)检查十六进制的测试文件时,我得到了这个(示例差异线):

< 03d5ff0: f3fd f3fd 99fe 99fe 40ff 40ff e7ff e7ff  ........@.@.....
---
> 03d5ff0: f3fd f3fd 0000 0000 0000 0000 0000 0000  ................

这意味着数据包的最后12个字节&#39;数据丢失了。其他一切都很好。

这只是测试代码,所以它并不重要(我猜),但它很奇怪,我想知道原因。

有什么想法吗?

修改

我现在已经从答案中尝试了一些方法,到目前为止还没有得到任何答案。我会继续努力。

编辑2:

代码适用于其他计算机。我不确定问题是什么,但它似乎对除了我以外的任何人都有用。很抱歉偷了你的时间,并感谢您提供有关如何改进代码的所有建议!

提前致谢, 卡森

3 个答案:

答案 0 :(得分:2)

您正在向 char 投射 2个字节 buf并读取其中的一半。

recvfrom(s, (char *)buf, LENGTH+HEADER, 0, (struct sockaddr*) &si_other,
             &slen) 

buf 数组有(LENGTH+HEADER) * 2个字节,你读了一半

使用 char 数组进行发送接收

修改

这是阅读文件的方式:

unsigned char data[LENGTH];

fseek(inf, 0, SEEK_END);
int file_Size = ftell(inf);
fseek(inf, 0, SEEK_SET);
if(file_Size  > LENGTH){
    //file larger than data
}
fread(data, sizeof(unsigned char), file_Size, inf);

答案 1 :(得分:2)

您的代码非常不完整,因此很难确定。如何将数据放入int16_t buffer[LENGTH+HEADER]发送方?解码和编码功能是什么样的?

我可以看到一个明显的危险是你的缓冲区是uint16_t类型,这是两个字节。函数sendto()recvfrom()期望缓冲区长度(以字节为单位)。换句话说,你的buf是你实际告诉sendto()的两倍长度(以字节为单位)。因此,您的编码功能可能会使一些数据从发送/接收的pov中消失。

疯狂猜测,丢失12个字节可能是一个合适的4字节值或其他数据htonl()已处理,然后在发送时丢失。

发布更完整的代码,以获得更好的猜测。

答案 2 :(得分:0)

如编辑2中所述,代码适用于我测试代码的所有机器,但我的代码。我不确定问题是什么/但是它似乎对除了我以外的任何人都有用。很抱歉偷了你的时间,并感谢您提供有关如何改进代码的所有建议!