用socket send数据成功,但是在recv卡住了,是不是我代码有问题?

changecode 2012-09-14 06:27:42
我的代码


WSADATA WSAData={0};
SOCKET sockfd;
struct sockaddr_in addr;
struct hostent *pURL;


初始化我的套接字:
pURL = gethostbyname("www.abc.com");
WSAStartup(MAKEWORD(2,2), &WSAData);
sockfd = socket(PF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((unsigned long*)pURL->h_addr);
addr.sin_port = htons(80);


连接:
connect(sockfd,(SOCKADDR *)&addr,sizeof(addr));


这个是我构建的包:
char *pHead =
"POST /abc.asp HTTP/1.1\r\n"
"User-Agent: kkc/89 (Windows NT 9.1; U; Edition IBIS; zh-cn) Presto/2.10.289 Version/12.01\r\n"
"Host: www.abc.com\r\n"
"Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1\r\n"
"Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Connection: Keep-Alive\r\n"
"Content-Length: 15\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n\r\n"
"user=abc&pw=abc";

send:
int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sockfd , 0X02);
closesocket(sockfd);
break;
}
len -= ret;
}while(len > 0);


以上能正确执行,服务器也能接收到我的数据。关键在以下这里,阻塞了我五秒多钟才能显示出数据。

while ( recv(sockfd, text, 255, 0) > 0)
{
printf("%s", text);
memset(text, 0, 255);
}


我是模拟网页用户名和密码提交的,网页编码是utf-8,好像使用了chunked,我接收到的数据才不过 1-2 Kb 而已,我已经确认send成功了,也能够recv到完整的数据,网络环境也是非常稳定高速的,如果我用浏览器执行相同的提交操作,浏览器返回的数据不超过一秒。希望有这方面经验的朋友帮助下,我也是刚接触socket,一步步从网上找资料学习,深夜了也该去睡觉了,明天来看看。谢谢。
...全文
2171 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
wstion 2014-02-05
  • 打赏
  • 举报
回复
引用 14 楼 zhmx_love 的回复:
谢谢,你回答得很详细,通过测试,我发现原来需要对抓到的包进行参数的修该,现在正常了,不过我接收到的是乱码,接收的数据时utf-8格式的,有没有转换函数可以转换一下呢?。我晚点试一下你所说的解析后再接收实际的数据。 [Quote=引用 12 楼 的回复:] 接收代码有问题 如果使用Keep-Alive,你必须小心处理接收:分两步走:接收并解释头,然后接收实体,在解释头数据中,要解析出实体数据的长度(Content-Length 或chunked),然后接收精确长度的字节数,然后go on... 或者使用"Connection: close"请求 即使使用后者,也应该按照header+body的数据接收+同步处理,而不是一个简单的循环recv…… [/Quote]
正解~
ok1234567 2012-09-17
  • 打赏
  • 举报
回复
在chunked的情形下,你是一块一块地接收body,每一个chunk又有自己的头和数据,还是要接收头并解析头,然后再接收数据拼接数据
ok1234567 2012-09-17
  • 打赏
  • 举报
回复
接收代码有问题
如果使用Keep-Alive,你必须小心处理接收:分两步走:接收并解释头,然后接收实体,在解释头数据中,要解析出实体数据的长度(Content-Length 或chunked),然后接收精确长度的字节数,然后go on...

或者使用"Connection: close"请求
即使使用后者,也应该按照header+body的数据接收+同步处理,而不是一个简单的循环recv
ok1234567 2012-09-17
  • 打赏
  • 举报
回复
给你一个编码转换函数
要做好http协议应用,其实有很多东西需要研究
必须的起码有:gzip,deflate,ssl



char * UTF82Ansi(char *psz)
{
int iLen=strlen(psz)+1;
WCHAR * pbuf;
pbuf=new WCHAR[iLen];
if (MultiByteToWideChar( CP_UTF8, 0, psz, iLen,pbuf, (DWORD)iLen) == 0)
{
delete pbuf;
return NULL;
}
BOOL bValue = FALSE;
memset(psz,'\0',iLen);
//---CP_ACP
if(WideCharToMultiByte(936, 0, pbuf,-1,psz, iLen-1, "?", &bValue)==0)
{
delete pbuf;
return NULL;
}
delete pbuf;
return psz;

}

changecode 2012-09-17
  • 打赏
  • 举报
回复
先把帖结了,谢谢大家的回答。
changecode 2012-09-17
  • 打赏
  • 举报
回复
谢谢,你回答得很详细,通过测试,我发现原来需要对抓到的包进行参数的修该,现在正常了,不过我接收到的是乱码,接收的数据时utf-8格式的,有没有转换函数可以转换一下呢?。我晚点试一下你所说的解析后再接收实际的数据。
[Quote=引用 12 楼 的回复:]
接收代码有问题
如果使用Keep-Alive,你必须小心处理接收:分两步走:接收并解释头,然后接收实体,在解释头数据中,要解析出实体数据的长度(Content-Length 或chunked),然后接收精确长度的字节数,然后go on...

或者使用"Connection: close"请求
即使使用后者,也应该按照header+body的数据接收+同步处理,而不是一个简单的循环recv……
[/Quote]
changecode 2012-09-17
  • 打赏
  • 举报
回复
你好,你的分析让我受益匪浅。我叫别人测试了我的代码,是不存在这种情况的,是即刻返回,但是在我的机上就出现了这种问题,我的网络环境是不错的,实际速度都有稳定的100kb。
[Quote=引用 10 楼 的回复:]
应该是你的 recv 有问题:
while ( recv(sockfd, text, 255, 0) > 0)
{
printf("%s", text);
memset(text, 0, 255);
}

从代码看,程序使用的socket是阻塞模式,这样在你发送完了数据后,对 recv的调用在三种情况下会返回:
1. 接收到了服务器的数据;
2. 服务器关闭了连接;
……
[/Quote]
Geoff08Zhang 2012-09-16
  • 打赏
  • 举报
回复
应该是你的 recv 有问题:
while ( recv(sockfd, text, 255, 0) > 0)
{
printf("%s", text);
memset(text, 0, 255);
}

从代码看,程序使用的socket是阻塞模式,这样在你发送完了数据后,对 recv的调用在三种情况下会返回:
1. 接收到了服务器的数据;
2. 服务器关闭了连接;
3. 网络发生了错误.
从你的情况看,应该是服务器把数据发送给你的程序了,但因为 recv 是阻塞的,所以之后如果服务器不再发送数据你的 recv 就一起停在那了,直到服务器关闭这个连接.你说停了5秒,估计是服务器发完数据5秒后关闭了这个socket,所以recv才返回.
解决方案: 使用非阻塞socket.下面这个地址有 HTTP 客户端和服务器的代码,请参考,解压后把 WebSrv, WebClnt.
来自《WinSock网络编程经络》,源码下载地址:http://download.csdn.net/detail/geoff08zhang/4571358
Gloveing 2012-09-14
  • 打赏
  • 举报
回复
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sockfd , 0X02);
closesocket(sockfd);
break;
}
len -= ret;
}while(len > 0);
-----------------------------
确实很大的问题,还循环send、shutdown 、closesocket
luawkk 2012-09-14
  • 打赏
  • 举报
回复
send:
int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sockfd , 0X02);
closesocket(sockfd);
break;
}
len -= ret;
}while(len > 0);

这个确实存在问题

第一次循环 发送了多少个在字节(长度),应该把发送的数据库缓存后移对应的长度
youngwolf 2012-09-14
  • 打赏
  • 举报
回复
int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sockfd , 0X02);
closesocket(sockfd);
break;
}
len -= ret;
}while(len > 0);
这段代码有严重问题,你没有出问题,是因为你网络状态好。

while ( recv(sockfd, text, 255, 0) > 0)
{
printf("%s", text);
memset(text, 0, 255);
}
这段代码要服务端关闭连接后才会返回(http一般是短连接,你应该用的是通用的http服务器,从这里可以看出,你所用的web服务器,在短连接上,保持5秒),所以也是有问题的,等5秒返回就不错了,如果是长连接,肯定就卡住了,永远不返回。
shuihan20e 2012-09-14
  • 打赏
  • 举报
回复
接收到的数据比较大吗?改一下缓冲区大小试下
zhanshen2891 2012-09-14
  • 打赏
  • 举报
回复
能接收到完整数据就没问题呗。

你可以看一下wininet,如果是http的话用这个比较好,它都帮你把协议内容都封装好了,用来很方便.
changecode 2012-09-14
  • 打赏
  • 举报
回复
感谢你的回答,我知道do里面哪里出错了,应该把终止条件改为 (ret > 0) ,然后把len -= ret;
去掉,是吧?
我确实是访问web服务器的,通过域名访问而不是ip地址。然后为什么会卡住呢?是不是我哪里设置不对?我感觉好像是没有告诉服务器已经发送完毕,所以它会一直等待到超时再返回给我哦。是不是?
[Quote=引用 3 楼 的回复:]
int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sock……
[/Quote]
changecode 2012-09-14
  • 打赏
  • 举报
回复
感谢你的回复,小弟惭愧,没好好看代码,应该把 do 循环终止条件改为(ret>0),把循环中的 len -= ret; 去掉是吧。
然后,确实如你所说,我是对web服务器进行send操作的,是对域名访问而不是ip地址。请问这里有什么问题?我发现好像是在send完之后好像缺少个通知服务器我已经发送完毕了,不知道是不是?


[Quote=引用 3 楼 的回复:]
int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
shutdown (sock……
[/Quote]
bsnry 2012-09-14
  • 打赏
  • 举报
回复
楼主 用堵塞的函数send,如果发送不出去,则不会返回。




while ( recv(sockfd, text, 255, 0) > 0)
{
printf("%s", text);
memset(text, 0, 255);
}
这段代码要服务端关闭连接后才会返回(http一般是短连接,你应该用的是通用的http服务器,从这里可以看出,你所用的web服务器,在短连接上,保持5秒),所以也是有问题的,等5秒返回就不错了,如果是长连接,肯定就卡住了,永远不返回。


为什么他的代码是短连接,就没事?








[Quote=引用 3 楼 的回复:]

int len = strlen(pHead);
do
{
ret = send(sockfd, pHead, strlen(pHead), 0);
if( ret == SOCKET_ERROR )
{
printf("*********************Send error *******************\n");
……
[/Quote]

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧