【问题标题】:Bus error after calling recv()/ How to recieve chunked compressed data调用 recv() 后出现总线错误/如何接收分块压缩数据
【发布时间】:2012-01-21 09:17:50
【问题描述】:

您好,我有一个简单的浏览器,它向 yahoo.com 发送一个请求,服务器响应并告诉我 200 Ok,它会使用编码传输:分块向我发送一个 gzip 文件。这很好,但是当我运行我的程序并不断调用 recv() 时,我最终遇到了总线错误。我不确定此时这意味着什么。另外我不清楚如何读取数据包的标头来告诉我它将发送多少字节,因为压缩文件是机器代码。在这个问题中,我在我的代码以及我在终端中看到的输出中包含了正确的内容。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

#define MAXDATASIZE 500;

int main(int argc, char *argv[]){
struct addrinfo serverSide,*serverInfo;
int mySock, status;
char buf[501],ipstr[INET6_ADDRSTRLEN];

memset(&serverSide, 0, sizeof serverSide);
serverSide.ai_family = AF_UNSPEC;
serverSide.ai_socktype = SOCK_STREAM;

if(getaddrinfo("www.yahoo.com","80",&serverSide,&serverInfo)==0){

}

mySock = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
connect(mySock, serverInfo->ai_addr, serverInfo->ai_addrlen);

char msg[500] = "GET http://www.yahoo.com HTTP/1.1\r\n";
strcat(msg,"Host: www.yahoo.com:80\r\n");
strcat(msg,"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1\r\n");
strcat(msg,"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n");
strcat(msg,"Accept-Language: en-us,en;q=0.5\r\n");
strcat(msg,"Accept-Encoding: gzip, deflate\r\n");
strcat(msg,"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n");
strcat(msg,"Connection: keep-alive\r\n\r\n");

// I want to keep the code simple so I just call recv enough times to see what has been
// written to my buffer. If I could read the packet length in the header then I would 
// code in a while loop to adjust for that.
if((status = send(mySock,msg,strlen(msg),0))== -1){
printf("request not sent %d\n",status);
perror("\n");
}else{
if((status = recv(mySock, buf, 1500, 0))== -1){
printf("recieved byte error");
}else{
printf("%s",buf);
}
if((status = recv(mySock, buf, 1500, 0))== -1){
printf("recieved byte error");
}else{
printf("%s",buf);
}
if((status = recv(mySock, buf, 1500, 0))== -1){
printf("recieved byte error");
}else{
printf("%s",buf);
}
if((status = recv(mySock, buf, 1500, 0))== -1){
printf("recieved byte error");
}else{
printf("%s",buf);
}
}
close(mySock);
freeaddrinfo(serverInfo);
return 0;
}

下面是我的代码的输出。服务器响应以下内容...

HTTP/1.1 200 OK 日期:2012 年 1 月 21 日星期六 08:53:09 GMT 设置 Cookie: B=4peq6lh7hkv7l&b=3&s=u4;到期=格林威治标准时间 2014 年 1 月 21 日星期二 20:00:00; 路径=/;域=.yahoo.com P3P: policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi Sami OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV" 缓存控制:私有 X 帧选项:SAMEORIGIN 设置 Cookie: IU=删除;过期=格林威治标准时间 2011 年 1 月 21 日星期五 08:53:09;路径=/; domain=.yahoo.com Set-Cookie: PH=deleted;过期=2011 年 1 月 21 日星期五 格林威治标准时间 08:53:09;路径=/;域=.yahoo.com 设置 Cookie: FPC = D = 2BrdHmSMUw00.1uwnK1w8hHJcKnQt3UjRGxvUnBVIn0e6eAyRyd96eAPIN33Jne3IWoEE8r8eAk9xF0ExLsN5JJJmANZRlEBg8hpcDJ1GD7Gd50uZeP1H0_Wbf_mc.LJ45tDfhhwjR1BSedjT7AeGszK321i_gS34xKNuHlH2niKnP1lFG8y3aztEQsOkQHUu1w3zxk-&V = 2; 过期=星期日,2013 年 1 月 20 日 08:53:10 GMT;路径=/;域名=www.yahoo.com 设置 Cookie:CH=已删除;过期=格林威治标准时间 2011 年 1 月 21 日星期五 08:53:09;路径=/; 域=www.yahoo.com 设置 Cookie: CH=AgBPGnwQAA9AEAAA3RAAKY0QAAMPEAAYcxAAKN0QAD5XEAASNBAAJeoQACI8; 过期=星期一,2012 年 2 月 20 日 08:53:09 GMT;路径=/;域=.yahoo.com 设置 Cookie: FPT = d = nZFZlZHXecyEB3UWO0p6uOQtHkIdLjY734kqWOMHwg8Yq1e0sUpJBiMgYN63uaJ0.zEBsZIbeO93bfF0mXfQ8CtJYxAuet8CIS5PYmNMWfBDUU6ew8pXSI6cY3aX7Nk743wzRxbuCoBZGqvOM0eGhQMFOQ7BrCYBAZsAIYAOqwHKu7sNvbkPN7r0T7ncKpu5bX8LWPGngHHS97cCbNgpbgzOh13nP1m6.9cw7oPeudXdRjfzxsDUYqq2LvQJdECPWmccPhDEYfAoIl.Cfc8T8w_5.zrvoWG5kJr_T0megV4GtcTB324ZS2zkf0pi1GiMGYVHxGNh01c04XJnjk5q0ek_Xgogaa5oZoyhkMYQLI66nMCt1yAiz1jXmq2MTBxHqtbxBkoJaVsJt0YQMdpkkxwpRpXZHUgur.K9kY4j3vgyG1j44CQPlNsh7mBMxNe5nLdCMjFMy0ufmocRYowg38kMiK9hpFqkFnwYZSZPMGM4wAK5wVvFrwn1phkY3OXr76z5OC5tjNeq3Q - &V = 1; 路径=/; domain=www.yahoo.com Set-Cookie: fpps=deleted;过期=周五, 格林威治标准时间 2011 年 1 月 21 日 08:53:09;路径=/;域=www.yahoo.com 设置 Cookie: fpc_s = d = 33OMFTGMUw2Z.oeMhzS8DGMizJ2NFSc4VT5QjW6pM.25xOqOYy5nr_kK5C83.tjkxzIiFvBITPc7P5YBehviyRS3piAAliJxvHQHDlbZYOlAdvgPXzJ4zGghf.xEL6Rb6rVdP90xlOc_njpBqlqOcwyMeq0ZqBy2VXuNrIxiD9QjUUsJyfVJ4miF1frSXQOI5Z8MVIErFoBjW3jTQANFu_CayJrjp6RRDc.YG5DCn04SFk3hKALdzVPSyIoawxmicCoWFfN7dvyge8jRoeQXHey.IALpAtcCPlY4eX.teLb.GO0yQxUN5HzgR9I-&V = 2; 路径=/; domain=www.yahoo.com 变化:接受编码内容类型: text/html;charset=utf-8 内容编码:gzip 年龄:2 传输编码:分块连接:保持活动服务器:YTS/1.20.0

000088e ���I�HG8Ae��t�>#%xc�c#���a��e9��*d��S��@�~}�ZF��~x� 6�S8�#ӉO�i:i%��?���a��9rxJ�n���<Q����_�-�A����!D{�{ޱN���f*/h��ΰ ���Ea�h��E��2UY� 2�7�����dL>U���^W˳g��H�Q�>���~����iiΟ��@:���R�L�b��K���=�# Ғ�5���|'�J��eo��{� 总线错误

【问题讨论】:

    标签: c sockets tcp tcpclient


    【解决方案1】:
    char buf[501];
    ...
    recv(mySock, buf, 1500, 0)
                      ^^^^
    

    如果recv 实际读取的字节数超过 501 个字节,则会溢出缓冲区,从而导致未定义的行为。确保您读取的字节数永远不会超过 501 字节,或增加缓冲区的大小。

    printfs 也不安全。没有什么可以保证输入是正确的,0-终止的 C 字符串。 (您可以使用 write 并传递返回的长度 recv。)

    【讨论】:

    • 但是现在我不再收到那个错误了,如果我想知道这些数据包的开始和结束,如何读取 gzip 的块?
    • 这是 TCP,没有数据包的开始/结束,只是一个流。您将需要解析标头,并自己解析分块编码以确定您需要读取多少。
    • 阅读 RFC 2616 第 3.6.1 节。它准确地解释了chunked 转账的运作方式。每个块都以一行文本开始,该行指定块中剩余的字节数,然后字节后跟一个 CRLF 换行符。最后一个块的字节大小为 0,然后一组额外的 HTTP 标头完成响应。
    【解决方案2】:

    一眼看去,好像你超速了buf;您将其声明为长度为 501,然后尝试将 1500 个字节读入其中。

    【讨论】:

    • 哦,哇,我没听懂。谢谢,我实际上有三个不同的文件,我想我把 501 的全部改成了 1500 的。看起来我的缓冲区溢出了,但我不确定如何。你的修复成功了!再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 2020-05-07
    • 1970-01-01
    • 2013-06-16
    • 2012-02-16
    • 2017-02-17
    相关资源
    最近更新 更多