Socket异步下载网页,阻塞在BeginReceive下

love4026 2014-04-19 04:35:26
代码是根据http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx 这上面的写的,这上面是代码是异步通信的例子,我想应该也适合下载网页吧,所以我把Send(client,"This is a test<EOF>"); 改为
Send(client, ”GET / HTTP/1.1\r\nHost: www.baidu.com\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko\r\nAccept-Language: en-US;q=0.8,en-US;q=0.6,en;q=0.4\r\nConnection: Keep-Alive\r\nCookie: \r\n\r\n“);

经过我的调试是能下载网页的,但是在这一步:


private static void ReceiveCallback( IAsyncResult ar ) {
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket client = state.workSocket;

// Read data from the remote device.
int bytesRead = client.EndReceive(ar);

if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));

// Get the rest of the data.
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}

出现问题,我一步一步调试,发现可以完整下个整个网页源代码。唯一的问题是bytesRead 永远不可能为0.我想知道为什么。 当整个网页下载完成后,到这一步 // Get the rest of the data.
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);,便永远不会再往下执行了。
bytesRead 值在未下载完成之前都是256,等快下载结束时,因为最后的数据不够256字节,可能是50或者其它的数值,我想着再循环一次就会变成0了,但却卡在了 client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);这句代码上,我想知道为什么,是不是异步通信与下载网页是完全不一样的情况,怎么修改?

别外,我想找一个使用socket下载网页的类,有了解这方面的,期待可以告诉我一个。在网上找了许多下载网页的方法,都是webrequest,没有socket类的。
...全文
183 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
love4026 2014-04-20
  • 打赏
  • 举报
回复
引用 15 楼 sp1234 的回复:
[quote=引用 楼主 love4026 的回复:] 别外,我想找一个使用socket下载网页的类,有了解这方面的,期待可以告诉我一个。在网上找了许多下载网页的方法,都是webrequest,没有socket类的。
你应该找.net中稍微高级一点的类,然后看看.net的源代码。包括(比如说)简单的语句 new WebClient().DownloadData(....)的实现。 如果你不看源代码,那么永远都会这样“连高级的类内部调用socket都不知道”![/quote] 要一步一步来。我目前恐怕还看不懂。最近看了很多socket异步通信的例子,想用它当作 http web request使用,没发现网上有写的特别好的, “连高级的类内部调用socket都不知道” 我知道它是调用socket,但让我现在看它,目前还不到时候,我只是一个初学者。
  • 打赏
  • 举报
回复
引用 楼主 love4026 的回复:
别外,我想找一个使用socket下载网页的类,有了解这方面的,期待可以告诉我一个。在网上找了许多下载网页的方法,都是webrequest,没有socket类的。
你应该找.net中稍微高级一点的类,然后看看.net的源代码。包括(比如说)简单的语句 new WebClient().DownloadData(....)的实现。 如果你不看源代码,那么永远都会这样“连高级的类内部调用socket都不知道”!
showjim 2014-04-20
  • 打赏
  • 举报
回复
引用 13 楼 love4026 的回复:
在网上找了很久,没有找到很好的例子,能否提供一个解决方案呢。 http://blog.soukey.com/?p=13 这篇文章说了怎么做,但我代码写不出来。 00006000\r\n 中间的是内容(有可能是经过gzip压缩的) \r\n00000000\r\n\r\n
gzip用GZipStream解压就可以了。 解析协议这一路下来,基本上相当于写一个webClient核心了,我暂时还没有这需求。 其实需求都已经很明确了,如果写不出来,还是使用System.Net.WebClient吧。
love4026 2014-04-20
  • 打赏
  • 举报
回复
引用 12 楼 sbwwkmyd 的回复:
比如
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

5
START
F
0123456789ABCDE
3
END
0

注意长度是16进制数,每一段以\r\n结束,最后一个0的后面补两个\r\n
在网上找了很久,没有找到很好的例子,能否提供一个解决方案呢。 http://blog.soukey.com/?p=13 这篇文章说了怎么做,但我代码写不出来。 00006000\r\n 中间的是内容(有可能是经过gzip压缩的) \r\n00000000\r\n\r\n 上面的内容在这个循环里如何获取呢 if (bytesRead > 0) { // There might be more data, so store the data received so far. state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead)); // Get the rest of the data. client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, new AsyncCallback(ReceiveCallback), state); } else { // All the data has arrived; put it in response. if (state.sb.Length > 1) { response = state.sb.ToString(); } // Signal that all bytes have been received. receiveDone.Set(); }
showjim 2014-04-19
  • 打赏
  • 举报
回复
比如
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

5
START
F
0123456789ABCDE
3
END
0

注意长度是16进制数,每一段以\r\n结束,最后一个0的后面补两个\r\n
showjim 2014-04-19
  • 打赏
  • 举报
回复
引用 10 楼 love4026 的回复:
response header中一般没有Content-Length,一般都是chunk的。 如果没有返回Content-Length是否就是无法使用keep-alive,但是我们的浏览器好像不是这样的,无论服务器是什么样的,都是可以使用keep-alive的,并且http1.1默认就支持keep-alive,难道我每次都要发送Connection: Close. (我下载的网页大部分是没有Content-Length的)
Chunked也是用长度的,当某个长度为0的时候表示结束。这个应该很容易搜索到的。
love4026 2014-04-19
  • 打赏
  • 举报
回复
response header中一般没有Content-Length,一般都是chunk的。 如果没有返回Content-Length是否就是无法使用keep-alive,但是我们的浏览器好像不是这样的,无论服务器是什么样的,都是可以使用keep-alive的,并且http1.1默认就支持keep-alive,难道我每次都要发送Connection: Close. (我下载的网页大部分是没有Content-Length的)
love4026 2014-04-19
  • 打赏
  • 举报
回复
引用 8 楼 sbwwkmyd 的回复:
[quote=引用 7 楼 love4026 的回复:] [quote=引用 6 楼 sbwwkmyd 的回复:] 如果Connection: Keep-Alive,服务器会等着下一个请求,不会断开连接的。
正解,那如何保持连接呢,难道用了socket keep-live就不能用了?[/quote]如果你要保持连接,那就要解析协议了,比如Header里面可能有Content-Length。[/quote] 有没有示例,我在google上搜索了好多技术资料都没有特别详细的,能否给一些关键词,我来在网上查询下。
showjim 2014-04-19
  • 打赏
  • 举报
回复
引用 7 楼 love4026 的回复:
[quote=引用 6 楼 sbwwkmyd 的回复:] 如果Connection: Keep-Alive,服务器会等着下一个请求,不会断开连接的。
正解,那如何保持连接呢,难道用了socket keep-live就不能用了?[/quote]如果你要保持连接,那就要解析协议了,比如Header里面可能有Content-Length。
love4026 2014-04-19
  • 打赏
  • 举报
回复
引用 6 楼 sbwwkmyd 的回复:
如果Connection: Keep-Alive,服务器会等着下一个请求,不会断开连接的。
正解,那如何保持连接呢,难道用了socket keep-live就不能用了?
showjim 2014-04-19
  • 打赏
  • 举报
回复
如果Connection: Keep-Alive,服务器会等着下一个请求,不会断开连接的。
showjim 2014-04-19
  • 打赏
  • 举报
回复
去掉这个 Connection: Keep-Alive
本拉灯 2014-04-19
  • 打赏
  • 举报
回复
引用 2 楼 love4026 的回复:
我知道会等待,我的意思是为什么网页数据已经下载完成了,服务器不会再返回数据了,它还是在等待,这样的话,我下载一个网页都至少需要几分钟的时间,明显不是我想要的结果。怎么实现,让它知道网页下载完成了,别再等了。
一般网页都是短连接的 还有看看最后收到的 int bytesRead = client.EndReceive(ar); 这个是不是为0 如为0那你就要把Socket断开。 还有可能就是网页的包没发完整
love4026 2014-04-19
  • 打赏
  • 举报
回复
我知道会等待,我的意思是为什么网页数据已经下载完成了,服务器不会再返回数据了,它还是在等待,这样的话,我下载一个网页都至少需要几分钟的时间,明显不是我想要的结果。怎么实现,让它知道网页下载完成了,别再等了。
本拉灯 2014-04-19
  • 打赏
  • 举报
回复
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0, new AsyncCallback(ReceiveCallback), state);, 没错呀,他就是这里会等待新的数据过来呀,如果没有就一直等下去呀

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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