套接字接收挂起

本文关键字:挂起 套接字 | 更新日期: 2023-09-27 18:03:05

我正在尝试下载,搜索bing页面,并询问使用套接字,我决定使用套接字,而不是webclient。

socket.Receive();在bing, yahoo, google的情况下,在几个循环后挂起,但对于ask有效。For Google循环将接收4 - 5次,然后在调用时冻结。

我不明白为什么?

public string Get(string url)
{
    Uri requestedUri = new Uri(url);
    string fulladdress = requestedUri.Host;
    IPHostEntry entry = Dns.GetHostEntry(fulladdress);
    StringBuilder sb = new StringBuilder();
    try
    {
        using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP))
        {
            socket.Connect(entry.AddressList[0], 80);
            NetworkStream ns = new NetworkStream(socket);
            string part_request = string.Empty;
            string build_request = string.Empty;
            if (jar.Count != 0)
            {
                part_request = "GET {0} HTTP/1.1'r'nHost: {1} 'r'nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'r'nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'r'nAccept-Language: en-us,en;q=0.5'r'nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'r'nCookie: {2}'r'nConnection: keep-alive'r'n'r'n";
                build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host, GetCookies(requestedUri));
            }
            else
            {
                part_request = "GET {0} HTTP/1.1'r'nHost: {1} 'r'nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'r'nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'r'nAccept-Language: en-us,en;q=0.5'r'nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'r'nConnection: keep-alive'r'n'r'n";
                build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host);
            }
            byte[] data = Encoding.UTF8.GetBytes(build_request);
            socket.Send(data, data.Length, 0);
            byte[] bytesReceived = new byte[102400];
            int bytes = 0;
            do
            {
                bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
                sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
            }
            while (bytes > 0);
            List<String> CookieHeaders = new List<string>();
            foreach (string header in sb.ToString().Split("'n'r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                if (header.StartsWith("Set-Cookie"))
                {
                    CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
                }
            }
            this.AddCookies(CookieHeaders, requestedUri);
            socket.Close();
        }
    }
    catch (Exception ex)
    {
        string errorMessage = ex.Message;
    }
    return sb.ToString();
}
CookieContainer jar = new CookieContainer();
public string GetCookies(Uri _uri)
{
    StringBuilder sb = new StringBuilder();
    CookieCollection collection = jar.GetCookies(_uri);
    if (collection.Count != 0)
    {
        foreach (Cookie item in collection)
        {
            sb.Append(item.Name + "=" + item.Value + ";");
        }
    }
    return sb.ToString();
}

套接字接收挂起

这是因为你已经达到了内容的结尾,但你仍然要求更多…

do
{
   bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
   sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
}
while (bytes > 0);

这假设只要最后一个请求返回的字节超过0,就有更多的可用字节,而实际上,当网络流到达终点时,您将有可能在最后一个循环中填充一些缓冲区。(例如bytes> 0,但没有更多的获取)…所以服务器关闭连接。

试试这样做…

do
{
   bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
   sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
}
while (bytes == bytesReceived.Length);

一些服务器(ask可能是其中之一)显然不会像你期望的那样自动关闭连接,因此它不会总是失败。

编辑

::::::

我的测试样本:

加载visual studio,创建一个新的控制台应用程序,然后将以下代码粘贴到生成的程序类中(代替所有现有代码):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string test = Get("http://www.google.co.uk/search?q=test&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-GB:official&client=firefox-a");
            Console.Read();
        }
        public static string Get(string url)
        {
            Uri requestedUri = new Uri(url);
            string fulladdress = requestedUri.Host;
            IPHostEntry entry = Dns.GetHostEntry(fulladdress);
            StringBuilder sb = new StringBuilder();
            try
            {
                using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP))
                {
                    socket.Connect(entry.AddressList[0], 80);
                    NetworkStream ns = new NetworkStream(socket);
                    string part_request = string.Empty;
                    string build_request = string.Empty;
                    if (jar.Count != 0)
                    {
                        part_request = "GET {0} HTTP/1.1'r'nHost: {1} 'r'nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'r'nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'r'nAccept-Language: en-us,en;q=0.5'r'nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'r'nCookie: {2}'r'nConnection: keep-alive'r'n'r'n";
                        build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host, GetCookies(requestedUri));
                    }
                    else
                    {
                        part_request = "GET {0} HTTP/1.1'r'nHost: {1} 'r'nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'r'nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'r'nAccept-Language: en-us,en;q=0.5'r'nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'r'nConnection: keep-alive'r'n'r'n";
                        build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host);
                    }
                    byte[] data = Encoding.UTF8.GetBytes(build_request);
                    socket.Send(data, data.Length, 0);
                    byte[] bytesReceived = new byte[4096];
                    int bytes = 0;
                    string currentBatch = "";
                    do
                    {
                        bytes = socket.Receive(bytesReceived);
                        currentBatch = Encoding.ASCII.GetString(bytesReceived, 0, bytes);
                        Console.Write(currentBatch);
                        sb.Append(currentBatch);
                    }
                    while (bytes == bytesReceived.Length);
                    List<String> CookieHeaders = new List<string>();
                    foreach (string header in sb.ToString().Split("'n'r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (header.StartsWith("Set-Cookie"))
                        {
                            CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
                        }
                    }
                    //this.AddCookies(CookieHeaders, requestedUri);
                    socket.Close();
                }
            }
            catch (Exception ex)
            {
                string errorMessage = ex.Message;
            }
            return sb.ToString();
        }
        static CookieContainer jar = new CookieContainer();
        public static string GetCookies(Uri _uri)
        {
            StringBuilder sb = new StringBuilder();
            CookieCollection collection = jar.GetCookies(_uri);
            if (collection.Count != 0)
            {
                foreach (Cookie item in collection)
                {
                    sb.Append(item.Name + "=" + item.Value + ";");
                }
            }
            return sb.ToString();
        }
        }
    }

我减少了缓冲区以确保它被多次填充…在我看来似乎没问题这篇文章附带了我个人电脑保证的典型作品:)

测试接收的字节数大多数时间

但是,如果最后一块数据与缓冲区长度匹配会发生什么?

byte[] requestBuffer = new byte[100];
int bytesRead;
do
{
    bytesRead = socket.Receive(requestBuffer);
    //do something
}
while (bytes == bytesReceived.Length); // Pretend bytes = 100

在上面的例子中,如果bytes == 100套接字没有更多的内容可以接收。

我建议使用Socket.Available属性,以确保程序在没有更多可用内容时停止读取。

byte[] requestBuffer = new byte[100];
int bytesRead;
while (socket.Available > 0)    
{
    bytesRead = socket.Receive(requestBuffer);
    //do something
}

您从流中读取的内容比给定的内容多。

  1. 所以,你打开一个连接到谷歌,并要求主页。Google会给你它的主页,比如10KB大小。
  2. 你分配一个102400字节大的缓冲区(也就是。

现在,这就是问题出现的地方。

  1. 你一直在阅读主页,一次几个字节,现在你已经达到10KB的标记。谷歌已经给你提供了整个主页,但你一直试图阅读,试图要求更多的数据!现在发生的是,你只是在等待更多的数据,更多的数据不会出现!你只要一直等待,直到你的超时时间到来。但是因为您已经(在代码中)指定了在读取100KB之前接收,但是只给了10KB,所以您永远不会到达那里,并且似乎挂在那个循环中!

解决方案吗?

检查是否收到任何字节。

bytes = socket.Receive(...);
if (bytes == 0)
{
    // no more data, exit loop. you can `break;` or use a while loop, as demonstrated below
}

你可以这样清晰地实现它:

do
{
   bytes = socket.Receive(...);
   // Process your data
}
while (bytes > 0);