`

C#用Socket读取网页(转载)

    博客分类:
  • C#
阅读更多

因为项目需要,对C#进行了一些了解应用,现将收集资料存档,以备查。

 

C#用Socket读取网页,可实现加载头信息的用户认证

 

    public class GetPageWithSocket
    {
        /// <summary>
        /// 使用socket得到网页html
        /// </summary>
        /// <param name="strUrl">网页url</param>
        /// <returns>网页html代码</returns>
        public string GetHtml(string strUrl,string username,string password)
        {

            bool hasRelocated = false;
            string strHost = GetHost(strUrl);
            int port = 80;
            if(strHost.IndexOf(":")!=-1)
            {
                port = int.Parse(strHost.Substring(strHost.IndexOf(":")+1));
                strHost = strHost.Substring(0, strHost.IndexOf(":"));
            }
            string strGetHeader = "";
            strGetHeader += "GET " + GetRelativeUrl(strUrl) + " HTTP/1.1\n";
            strGetHeader += "Host: " + strHost + "\n";
            string test = Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + password));
            strGetHeader += "Authorization: Basic " + test + "\n";
            strGetHeader += "Connection: Close\n";
            strGetHeader += "\n";

            byte[] getBytes = Encoding.ASCII.GetBytes(strGetHeader);
            try
            {
                int iTotalCount;
                byte[] responseBytes = GetHtmlOriginByte(strHost,port, getBytes, out iTotalCount); //得到网页
                string strResponse = Encoding.UTF8.GetString(responseBytes, 0, iTotalCount);
                hasRelocated = HasRelocated(ref strResponse,username,password);
                if (!hasRelocated) //如果没跳转则转化字符后返回
                {
                    int iStart = FindBodyStartPosition(responseBytes);
                    //总长度不再计算头http头部了
                    iTotalCount -= iStart;
                    int iIndex = strResponse.IndexOf("\n\n");
                    if (iIndex != -1)
                    {
                        string strHeader = strResponse.Substring(0, iIndex);//头部
                        DecompressWebPage(ref responseBytes, ref iTotalCount, strHeader, iStart);
                        //转码
                        strResponse = DecodeWebStringByHttpHeader(responseBytes, iTotalCount, strHeader);
                        strResponse = DecodeWebStringByHtmlPageInfo(responseBytes, iTotalCount, strResponse);
                    }
                }
                return strResponse;
            }
            catch (System.Exception ex)
            {
                return "error:get html error";
            }
        }
        /// <summary>
        /// 得到网页原始字节数组
        /// </summary>
        /// <param name="strHost">主机头</param>
        /// <param name="getBytes">Get字符串的字节数组形式</param>
        /// <param name="iTotalCount">接受的字节数</param>
        /// <returns>原始网页字节数组</returns>
        private byte[] GetHtmlOriginByte(string strHost,int port, byte[] getBytes, out int iTotalCount)
        {
            int iReponseByteSize = 400 * 1024;
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(strHost, port);
            socket.Send(getBytes);
            byte[] buffer = new byte[256];
            byte[] responseBytes = new byte[iReponseByteSize];
            int iNumber = socket.Receive(buffer, buffer.Length, SocketFlags.None);
            iTotalCount = iNumber;
            buffer.CopyTo(responseBytes, 0);
            while (iNumber > 0)
            {
                iNumber = socket.Receive(buffer, buffer.Length, SocketFlags.None);
                if (iTotalCount + iNumber >= responseBytes.Length)
                {
                    //重新生成个更大的数组
                    byte[] temp = new byte[responseBytes.Length * 2];
                    //原数据copy到新数组中
                    responseBytes.CopyTo(temp, 0);
                    buffer.CopyTo(temp, iTotalCount - 1);
                    responseBytes = temp; //引用变更
                }
                else
                {
                    buffer.CopyTo(responseBytes, iTotalCount - 1);
                }
                iTotalCount += iNumber; //索引位置增加
            }
            return responseBytes;
        }
        /// <summary>
        /// 解压网页
        /// </summary>
        /// <param name="responseBytes">网页字节数组含http头</param>
        /// <param name="iTotalCount">数组长度</param>
        /// <param name="strHeader">Http头字符串</param>
        /// <param name="iStart">网页正文开始位置</param>
        private void DecompressWebPage(ref byte[] responseBytes, ref int iTotalCount, string strHeader, int iStart)
        {
            byte[] szSwapBuffer = new byte[iTotalCount];
            Array.Copy(responseBytes, iStart, szSwapBuffer, 0, iTotalCount);
            Regex regZip = new Regex(@"Content-Encoding:\s+gzip[^\n]*\r\n", RegexOptions.IgnoreCase);

            if (regZip.IsMatch(strHeader))
            {
                responseBytes = Decompress(szSwapBuffer);
                iTotalCount = responseBytes.Length; //解压后长度变了
            }
            else
            {
                responseBytes = szSwapBuffer;
            }
        }
        /// <summary>
        /// 根据网页meta标记里面的字符编码解析字符串
        /// </summary>
        /// <param name="responseBytes">网页内容字节数组(除http头以外的内容)</param>
        /// <param name="iTotalCount">网页内容字节数组长度</param>
        /// <param name="strResponse">网页内容字符串, 可能已经根据其它转码要求转换过的字符串</param>
        /// <returns>转好的字符串</returns>
        private string DecodeWebStringByHtmlPageInfo(byte[] responseBytes, int iTotalCount, string strResponse)
        {
            Regex regGB2312 = new Regex(@"<meta[^>]+Content-Type[^>]+gb2312[^>]*>", RegexOptions.IgnoreCase);
            Regex regGBK = new Regex(@"<meta[^>]+Content-Type[^>]+gbk[^>]*>", RegexOptions.IgnoreCase);
            Regex regBig5 = new Regex(@"<meta[^>]+Content-Type[^>]+Big5[^>]*>", RegexOptions.IgnoreCase);
            if (regGB2312.IsMatch(strResponse) || regGBK.IsMatch(strResponse))
                strResponse = Encoding.GetEncoding("GBK").GetString(responseBytes, 0, iTotalCount);
            if (regBig5.IsMatch(strResponse))
                strResponse = Encoding.GetEncoding("Big5").GetString(responseBytes, 0, iTotalCount);
            return strResponse;
        }
        /// <summary>
        /// 根据Http头标记里面的字符编码解析字符串
        /// </summary>
        /// <param name="responseBytes">网页内容字节数组(除http头以外的内容)</param>
        /// <param name="iTotalCount">网页内容字节数组长度</param>
        /// <param name="strHeader">http头的字符串</param>
        /// <returns>转好的字符串</returns>
        private string DecodeWebStringByHttpHeader(byte[] responseBytes, int iTotalCount, string strHeader)
        {
            string strResponse = "";
            if (strHeader.Contains("charset=GBK") || strHeader.Contains("charset=gb2312"))
            {
                strResponse = Encoding.GetEncoding("GBK").GetString(responseBytes, 0, iTotalCount);
            }
            else
                strResponse = Encoding.UTF8.GetString(responseBytes, 0, iTotalCount);
            return strResponse;
        }
        /// <summary>
        /// 是否已跳转
        /// </summary>
        /// <param name="strResponse">http响应字符串</param>
        /// <returns>bool值 是否跳转</returns>
        private bool HasRelocated(ref string strResponse,string username,string password)
        {
            bool hasRelocated = false;
            int iIndex = strResponse.IndexOf("\n\n");
            if (iIndex != -1)
            {
                string strHeader = strResponse.Substring(0, iIndex);//头部
                if (strResponse.StartsWith("HTTP/1.1 302") || strResponse.StartsWith("HTTP/1.1 301"))//跳转
                {
                    int iStart = strHeader.IndexOf("\nLocation: ");
                    string strRelocateUrl = strHeader.Substring(iStart + "\nLocation: ".Length);
                    int iEnd = strRelocateUrl.IndexOf("\n");
                    strRelocateUrl = strRelocateUrl.Substring(0, iEnd);
                    strResponse = GetHtml(strRelocateUrl,username, password); //递归的获取
                    hasRelocated = true;
                }
            }
            return hasRelocated;
        }
        /// <summary>
        /// 查找html开始部分(去除了html头)\r\n\r\n后面第一个byte的位置
        /// </summary>
        /// <param name="szHtmlBuffer">接受到的byte数组</param>
        /// <returns>第一个byte位置</returns>
        private int FindBodyStartPosition(byte[] szHtmlBuffer)
        {
            for (int i = 0; i < szHtmlBuffer.Length - 3; ++i)
            {
                if (szHtmlBuffer[i] == 13 && szHtmlBuffer[i + 1] == 10 && szHtmlBuffer[i + 2] == 13 && szHtmlBuffer[i + 3] == 10)
                    return i + 4;
            }
            return -1;
        }
        /// <summary>
        /// 得到请求资源的相对路径
        /// </summary>
        /// <param name="strUrl">Url字符串</param>
        /// <returns>url的相对路径</returns>
        private string GetRelativeUrl(string strUrl)
        {
            int iIndex = strUrl.IndexOf(@"//");
            if (iIndex <= 0)
                return "/";
            string strTemp = strUrl.Substring(iIndex + 2);
            iIndex = strTemp.IndexOf(@"/");
            if (iIndex > 0)
                return strTemp.Substring(iIndex);
            else
                return "/";
        }
        /// <summary>
        /// 根据Url得到host
        /// </summary>
        /// <param name="strUrl">url字符串</param>
        /// <returns>host字符串</returns>
        private string GetHost(string strUrl)
        {
            int iIndex = strUrl.IndexOf(@"//");
            if (iIndex <= 0)
                return "";
            string strTemp = strUrl.Substring(iIndex + 2);
            iIndex = strTemp.IndexOf(@"/");
            if (iIndex > 0)
                return strTemp.Substring(0, iIndex);
            else
                return strTemp;
        }
        /// <summary>
        /// 解压gzip网页
        /// </summary>
        /// <param name="szSource">压缩过的字符串字节数组</param>
        /// <returns>解压后的字节数组</returns>
        private byte[] Decompress(byte[] szSource)
        {
            MemoryStream msSource = new MemoryStream(szSource);
            //DeflateStream  也可以这儿
            GZipStream stream = new GZipStream(msSource, CompressionMode.Decompress);
            byte[] szTotal = new byte[40 * 1024];
            long lTotal = 0;
            byte[] buffer = new byte[8];
            int iCount = 0;
            do
            {
                iCount = stream.Read(buffer, 0, 8);
                if (szTotal.Length <= lTotal + iCount) //放大数组
                {
                    byte[] temp = new byte[szTotal.Length * 10];
                    szTotal.CopyTo(temp, 0);
                    szTotal = temp;
                }
                buffer.CopyTo(szTotal, lTotal);
                lTotal += iCount;
            } while (iCount != 0);
            byte[] szDest = new byte[lTotal];
            Array.Copy(szTotal, 0, szDest, 0, lTotal);
            return szDest;
        }
    }

 

 

 

 

代码为转载,转载位置未存,望原作者见谅。

分享到:
评论

相关推荐

    C#SuperSocket服务端与客户端通信实例

    本教程将深入探讨如何使用C#编程语言以及SuperSocket库来构建一个高效、稳定的服务器端和客户端通信模型。SuperSocket是一个轻量级且易于使用的.NET Socket服务端开发框架,它为开发者提供了构建自定义网络应用的...

    C#使用Socket实现发送和接收图片的方法

    本示例中,我们将探讨如何使用C#的Socket类来实现发送和接收图片的功能。 首先,我们创建一个服务器端,其主要任务是监听客户端的连接请求,并将图片文件发送给客户端。在`Main`方法中,我们执行以下步骤: 1. **...

    socket读取plc

    在Linux平台上,通过Socket进行PLC(可编程逻辑控制器)数据的读取是工业自动化领域常见的通信方式之一。本文将详细讲解如何利用Socket接口和Modbus TCP协议来实现这一功能。 首先,我们要理解什么是Socket。Socket...

    c#与PLC通过SocketTcp通讯代码

    c#与PLC通过SocketTcp通讯代码.仅通讯部分,不包含协议解析

    C#Socket文件传输简单例子(将文件名和文件同时传输)

    本示例主要探讨如何使用C#的Socket类进行文件的传输,包括文件名和文件内容的同步发送与接收。这里我们将详细讲解实现这一功能的关键步骤和相关知识点。 首先,了解Socket的工作原理。Socket是TCP/IP协议栈的一部分...

    利用C# Socket 实现HTTP WEB服务器

    在本文中,我们将深入探讨如何使用C#编程语言和Socket技术来实现一个基本的HTTP Web服务器。C#是一种面向对象的、类型安全的编程语言,广泛应用于Windows平台上的应用程序开发,包括网络服务。Socket是网络通信的...

    C# Socket编程 客户异步读取

    对于标题中的“C# Socket编程 客户异步读取”,我们关注的是如何在客户端使用异步方法来读取服务器发送的数据。C#的异步编程模型主要基于.NET Framework的`async/await`关键字。在Socket编程中,我们可以使用`...

    C#实现Socket编程 (异步通讯,解决Tcp粘包)第三阶段

    本文将深入探讨如何使用C#语言来实现Socket编程,特别是在处理异步通信和解决TCP粘包问题的第三阶段。C#提供了丰富的类库支持网络编程,使得开发者能够方便地构建基于TCP/IP的客户端和服务器应用。 首先,让我们...

    C#Modbus Socket通信实例.rar

    C#中实现Modbus TCP通信,我们需要使用Socket类,它是.NET Framework提供的基础网络通信组件。Socket类提供了低级别的网络编程接口,可以用于创建TCP/IP或UDP/IP连接。在本例中,我们将专注于TCP,因为Modbus TCP是...

    C#用Socket发送和接收文件的源代码

    3. **读取文件**:使用FileStream或其它文件读取方式读取待发送的文件内容。 4. **数据分块**:大文件传输时,不能一次性将整个文件内容发送,而是需要将其分割成多个小块。 5. **发送数据**:使用Socket的Send...

    C#+Socket异步传输,c#socket通信,C#

    在IT行业中,网络通信是不可或缺的一部分,而C#语言提供了强大的Socket类库,使得开发者能够构建高效、可靠的网络应用程序。本篇文章将深入探讨C#中的Socket异步传输,以及如何利用它进行网络通信。 首先,Socket是...

    c# socket 传输文件

    在本文中,我们将深入探讨如何使用C# Socket类进行文件传输,包括文件的发送和接收,以及在此过程中可能遇到的关键技术和注意事项。 1. **Socket基本概念** - Socket是基于TCP/IP协议族的通信接口,它允许应用程序...

    c#基于socket 服务器端TCP程序

    标题中的“c#基于socket 服务器端TCP程序”指的是使用C#语言编写的一套服务器应用程序,它利用了Socket类库来处理TCP(传输控制协议)连接。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,广泛用于...

    C#语言Socket传文件例子

    本示例主要探讨如何使用C#的Socket类进行文件的传输,具体是从客户端向服务器端发送文件。这个过程涉及到了网络编程的基本原理、Socket通信机制以及文件I/O操作。 首先,Socket是TCP/IP协议族的基础,它为应用程序...

    C#TCP\Socket粘包处理(加长度头)

    在C#中,如果使用Socket进行TCP通信,就需要处理这种现象,以确保正确地解析接收到的数据。 "TCP\Socket粘包处理(加长度头)"这个主题主要涉及如何解决这个问题。在TCP中处理粘包的关键是添加一种机制来区分不同的...

    基于C#的socket通信编程

    在C#中,我们可以先将文件读取为字节数组,然后通过Socket的Send方法分块发送。服务器端接收到数据后,再写入到本地文件系统,恢复成原始文件。这个过程中,需要注意文件的分块发送和接收,以及正确处理文件头信息,...

    Socket异步发送读取,客户端和服务端

    总结来说,"Socket异步发送读取,客户端和服务端"这个主题涵盖了C#中使用Socket进行网络通信的核心技术,包括异步发送和接收数据,以及与Winform界面的交互。理解并掌握这些知识点对于开发网络应用至关重要。

    c#通讯实例_C#_socket_

    例如,`RWFile.cs`可能包含用于读取和写入文件的函数,可能使用`FileStream`打开文件,然后使用`StreamReader`或`StreamWriter`进行读写操作。 4. **日志记录(LogHelper.cs)** `LogHelper.cs`文件可能包含了日志...

    C#中Socket服务端通讯的代码

    在IT领域,网络通信是不可或缺的一部分,而C#作为.NET框架的主要编程语言,提供了丰富的库来支持网络编程,其中就包括Socket。本篇文章将详细解析标题中的"C#中Socket服务端通讯的代码",以及如何实现高效、稳定的...

Global site tag (gtag.js) - Google Analytics