V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sbmzhcn
V2EX  ›  程序员

求 c#下的使用 socks 下载网页程序

  •  
  •   sbmzhcn · 2014-10-23 21:06:54 +08:00 · 2865 次点击
    这是一个创建于 3682 天前的主题,其中的信息可能已经有所发展或是发生改变。
    使用httpwebrequest下载网页非常简单,但它只能使用http代理,网上有没有类似socks连接的,可以使用socks5代理,我在网上找了很久,好像没有这方面的代码,即使有错误百出,有的不支持多线程,有的对错误处理不完美。难道没有比较好的关于socks网络编程的代码吗?

    说几点需求:
    可以使用socks代理
    可以支持多线程
    支持cookies
    支持gzip解压
    支持keep-alive
    11 条回复    2014-10-28 13:03:18 +08:00
    sbmzhcn
        1
    sbmzhcn  
    OP
       2014-10-23 21:08:08 +08:00
    添加一个最重要的,忘了,要支持异步,不然下载的时候会卡在那儿永远不会动,我遇到过。
    dong3580
        2
    dong3580  
       2014-10-23 21:48:42 +08:00 via Android
    看看模拟登录的代码试试,抓取原理类似,不过,我到没用过代理实现抓取页面,不知道可不可行。
    xenme
        3
    xenme  
       2014-10-23 21:55:52 +08:00
    单独每一个搜到类,然后自己拼起来嘛。
    mengskysama
        4
    mengskysama  
       2014-10-23 22:00:55 +08:00
    curl,自己在实现个线程池管一下就行了。.NET十几行代码的事情
    sbmzhcn
        5
    sbmzhcn  
    OP
       2014-10-23 22:03:48 +08:00 via Android
    如果这么简单我就不会问了,这问题一年多了吧,虽然我用代码写出来了,但稳定性不好,我想借鉴下其他代码,说十几行代码可以搞定 我只有呵呵了。
    mengskysama
        6
    mengskysama  
       2014-10-23 22:16:11 +08:00
    @sbmzhcn 为什么非要自己写,curl你要的实现都有,而且也是开源的,NET用就封装调用一下就行了。这东西根本不需要异步,自己用过线程池管理,gh上也有别人的异步封装。
    clijiac
        7
    clijiac  
       2014-10-23 22:33:38 +08:00
    最简单的不是弄个socks5 to http proxy么,用polipo试试
    takwai
        8
    takwai  
       2014-10-24 00:57:39 +08:00
    @sbmzhcn 卡 UI 的话,开一个新线程去处理下载即可。需求中的支持多线程,是同一个源多线程下载?

    @mengskysama 提供的方法是可行的,下面是简单实现。

    https://gist.github.com/takwai/871c59d9112133d2390c
    sbmzhcn
        9
    sbmzhcn  
    OP
       2014-10-24 09:09:27 +08:00
    '''
    #region page source analytics
    private void AnalyPageSource(MemoryStream ms,
    out WebHeaderCollection responseHeaders,
    out string pageContent)
    {
    byte[] bytes = ms.ToArray();
    StringBuilder string_buffer = new StringBuilder();
    byte[] contentBytes = new byte[bytes.Length];

    responseHeaders = new WebHeaderCollection();
    pageContent = string.Empty;
    // process headers
    for (int i = 0; i < bytes.Length; i++)
    {
    string_buffer.Append((char)bytes[i]);
    if (string_buffer.ToString().ToLower().IndexOf("\r\n\r\n") != -1)
    {
    int index = string_buffer.ToString().IndexOf("\r\n\r\n");
    string originalheaderString = string_buffer.ToString().Substring(0, index);
    Header = originalheaderString;

    //Array.Copy(bytes, index + 4, contentBytes, 0, ms.Length - index - 4);
    Array.Copy(bytes, index + 4, contentBytes, 0, bytes.Length - index - 4);
    string originalPageContent = Encoding.UTF8.GetString(contentBytes);

    string responseState = "";
    string[] headers = originalheaderString.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
    foreach (string item in headers)
    {
    if ( item.StartsWith( "Set-Cookie:", StringComparison.OrdinalIgnoreCase ))
    {
    string tCookie = item.Substring(11, item.IndexOf(";") < 0 ? item.Length - 11 : item.IndexOf(";") - 10).Trim();
    if ( !this.Cookies.Exists( f => f.Split( '=' )[0] == tCookie.Split( '=' )[0] ) )
    {
    this.Cookies.Add( tCookie );
    }
    }
    int colonIndex = item.IndexOf(":");
    if (colonIndex > -1)
    responseHeaders.Add(item.Substring(0, colonIndex).Trim(), item.Substring(colonIndex + 1).Trim());
    else
    responseState = item;
    }
    StatusCode = responseState.Split(' ')[1];

    if (responseState.IndexOf(" 302 ") != -1 || responseState.IndexOf(" 301 ") != -1)
    {
    if (responseHeaders["Location"] != null)
    {
    try { ResponseUri = new Uri(responseHeaders["Location"]); }
    catch { ResponseUri = new Uri(ResponseUri, responseHeaders["Location"]); }
    }
    }

    ContentType = Headers["Content-Type"];
    if (Headers["Content-Length"] != null)
    ContentLength = int.Parse(Headers["Content-Length"]);
    KeepAlive = (Headers["Connection"] != null && Headers["Connection"].ToLower() == "keep-alive") ||
    (Headers["Proxy-Connection"] != null && Headers["Proxy-Connection"].ToLower() == "keep-alive");

    try
    {
    if (!String.IsNullOrEmpty(responseHeaders[HttpResponseHeader.TransferEncoding]))
    {
    if (responseHeaders[HttpResponseHeader.TransferEncoding].Contains("chunked"))
    {
    contentBytes = ChunkedDecompress(contentBytes);
    }
    }
    }
    catch (Exception ex)
    {
    throw new Exception("处理chunked数据失败:" + ex);
    }
    try
    {
    if (!String.IsNullOrEmpty(responseHeaders[HttpResponseHeader.ContentEncoding]))
    {
    if (responseHeaders[HttpResponseHeader.ContentEncoding].Contains("gzip")
    || responseHeaders[HttpResponseHeader.ContentEncoding].Contains("deflate"))
    {
    pageContent = GzipDecompress(contentBytes);
    }
    }
    else
    {
    pageContent = Encoding.UTF8.GetString(contentBytes);
    }
    }
    catch (Exception ex)
    {
    throw new Exception("GzipDecompress Error: " + ex.Message);
    }

    if (string.IsNullOrEmpty(pageContent) && !string.IsNullOrEmpty(originalPageContent))
    {
    pageContent = originalPageContent;
    }
    break;
    }
    }
    }
    #endregion
    '''

    这是我代码中的一部分,为什么我没觉得那么简单呢。
    mengskysama
        10
    mengskysama  
       2014-10-24 11:30:48 +08:00
    @sbmzhcn 因为你是自己实现....现在没有程序猿会这么'愚蠢'。

    你要自己现也ok,对于理解http协议还是很有帮助的,至少先要读HTTP那几十篇RFC文档,不过如果你的目的是生产强烈建议你不要这么干。

    我指出你代码2个问题,第一个你的contentBytes是基于\r\n\r\n得到的,你可以查一下文档对于指定Content-Length的content前端是不强制性要求有这个标记的。第二个content的编码不一定是UTF8。所以通用性上面肯定有问题。

    还有你代码太乱。实现上你可以参考下python的urllib3的设计,也是完全开源的已经完整实现了HTTPS和连接池的管理了,代码也质量也相当高。所以我干这种事情都不用.NET。。。。
    sbmzhcn
        11
    sbmzhcn  
    OP
       2014-10-28 13:03:18 +08:00
    @mengskysama 首先必须用.net,因为要求开发C#的程序,二是我也不想这样实现,但这样实际有几个原因,一是使用这样的实现 可以使用socket代理,不知道其它的httpwebrequest有什么办法可以直接使用socket代理。我知道很少有人这样实现,所以才这样问,有没有这样的代码,就因为这样的代码很少,我才问的。你说的我也理解。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5456 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 03:25 · PVG 11:25 · LAX 19:25 · JFK 22:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.