现在已完成了与代理的连接测试,用户名密码验证也可通过.
问题是我不知道如何利用代理与服务器交换数据.
打个比方:大家都用QQ,QQ设置里有socks5代理,我现在就是实现了它的测试这一步,现在就是要利用代理实现登录注册等功能.会了登录就会注册了,关键是第一步迈不出!请这方面的高手帮帮忙,有源码最好!

解决方案 »

  1.   

    你的意思是 
    如 webrequest 里的proxy 属性吗?
      

  2.   

    应该和你说的意思不一样, 我这个是C/S socket编程 ,就像QQ迅雷等软件那样, 可以使用socks5代理向服务端发送并接收消息
      

  3.   

    我在用的:
    其实就是拿到一个 Socket 时有区别, 拿到后就一样了,  public class Proxy
      {
        #region members
        string _targetHost;
        ushort _targetPort;
        int _proxyTimeout = 500;// timeout in sec
        ProxyType _proxyType;
        string _proxyHost;
        ushort _proxyPort;
        string _proxyUser;
        string _proxyPassword;
        static readonly string[] socks5ErrorMessages = {
            "Operation completed successfully.",//操作成功完成
            "General SOCKS server failure.",//常规服务器失败
            "Connection not allowed by ruleset.",//连接不被允许
            "Network unreachable.",//网络不能到达
            "Host unreachable.",//主机不能到达
            "Connection refused.",//连接被拒绝
            "TTL expired.",//TTL期满
            "Command not supported.",//不支持的命令
            "Address type not supported.",//不被支持的地址类型
            "Unknown error."//未名的错误
          };    #endregion    #region properties
        public string TargetHost
        {
          get { return _targetHost; }
          set { _targetHost = value; }
        }    public ushort TargetPort
        {
          get { return _targetPort; }
          set { _targetPort = value; }
        }    public ProxyType ProxyType
        {
          get { return _proxyType; }
        }    public string ProxyHost
        {
          get { return _proxyHost; }
          set { _proxyHost = value; }
        }    public ushort ProxyPort
        {
          get { return _proxyPort; }
          set { _proxyPort = value; }
        }    public string ProxyUser
        {
          get { return _proxyUser; }
          set { _proxyUser = value; }
        }    public string ProxyPassword
        {
          get { return _proxyPassword; }
          set { _proxyPassword = value; }
        }
        #endregion    #region constructors
        public Proxy(ProxyType proxyType)
        {
          _proxyType = proxyType;
        }
        #endregion    #region GetSocket
        internal Socket GetSocket()
        {
          Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
          socket.SendTimeout = _proxyTimeout;
          socket.ReceiveTimeout = _proxyTimeout;      switch (_proxyType)
          {
            case ProxyType.None:
              socket.Connect(_targetHost, _targetPort);
              break;
            case ProxyType.Socks5:
              connectToSocks5Proxy(socket, _proxyHost, _proxyPort, _proxyUser, _proxyPassword);
              socks5connectToTarget(socket, _targetHost, _targetPort);
              break;
            default:
              throw new ArgumentOutOfRangeException("not supported proxy type");
          }
          return socket;
        }
        #endregion    #region private
        static void connectToSocks5Proxy(Socket socket, string proxyHost,
          ushort port, string proxyuser, string proxypassword)
        {
          // 请求
          byte[] requestBuffer = new byte[257];
          // 应答
          byte[] responseBuffer = new byte[257];
          ushort nIndex;
          // 客户端连到服务器后, 然后就发送请求来协商版本和认证方法: 
          socket.Connect(proxyHost, port);      nIndex = 0;
          requestBuffer[nIndex++] = 0x05; // V 5.      [版本]
          requestBuffer[nIndex++] = 0x02; // 2 种验证方式[方法的数目]
          requestBuffer[nIndex++] = 0x00; // X'00'  不需要认证 [方法1]
          requestBuffer[nIndex++] = 0x02; // X'02'  用户名/密码[方法2]
          socket.Send(requestBuffer, nIndex, SocketFlags.None);      // 收到2个字节的应答, 填充到response中, 如果不是两个字节, 则抛出异常
          int nGot = socket.Receive(responseBuffer, 2, SocketFlags.None);
          if (nGot != 2)
            throw new Exception("代理服务器应答错误");      // 连接成功
          // 当前定义的方法有:
          // X'00'  不需要认证
          // X'01'  GSSAPI
          // X'02'  用户名/密码
          // X'03' -- X'7F'   由IANA分配
          // X'80' -- X'FE'  为私人方法所保留的
          // X'FF'  没有可以接受的方法
          switch (responseBuffer[1])
          {
            case 0xFF:
              throw new Exception("代理服务器没有可以使用的验证方式");
              break;
            case 0x02:
              loginToSocks5Proxy(socket, proxyuser, proxypassword);
              break;
          }
        }    static void loginToSocks5Proxy(Socket socket, string proxyuser, string proxypassword)
        {
          byte[] request = new byte[257];
          byte[] response = new byte[257];
          ushort nIndex;
          byte[] rawBytes;      nIndex = 0;
          request[nIndex++] = 0x05; // Version 5.
          // 加入 user name
          // 一个字节,放UserName的长度
          request[nIndex++] = (Byte)proxyuser.Length;
          rawBytes = Encoding.Default.GetBytes(proxyuser);
          // 将userName 加入
          rawBytes.CopyTo(request, nIndex);
          nIndex += (ushort)rawBytes.Length;      // 加入 password
          // 一个字节,放PassWord的长度
          request[nIndex++] = (Byte)proxypassword.Length;
          rawBytes = Encoding.Default.GetBytes(proxypassword);
          rawBytes.CopyTo(request, nIndex);
          nIndex += (ushort)rawBytes.Length;      // 发送 Username/Password 请求
          socket.Send(request, nIndex, SocketFlags.None);      // 收到2个字节的应答,填充到response中
          int nGot = socket.Receive(response, 2, SocketFlags.None);
          if (nGot != 2)
          {
            throw new Exception("从 proxy server 返回错误的应答.");
          }
          if (response[1] != 0x00) //返回如下的报文字节序列映像为:0x01 | 验证结果标志-.0x00 验证通过, 其余均表示有故障
          {
            throw new Exception("错误的 Usernaem/Password.");
          }
        }
      

  4.   

    我日, 超长了    static void socks5connectToTarget(Socket socket, string targetIp, ushort targetPort)
        {
          // 这个函数只实现了connect 命令
          //
          // +----+-----+-------+------+----------+----------+
          // |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
          // +----+-----+-------+------+----------+----------+
          // | 1  |  1  | X'00' |  1   | Variable |    2     |
          // +----+-----+-------+------+----------+----------+
          //
          // CMD 命令
          // o  CONNECT X'01'
          // o  BIND X'02'
          // o  UDP ASSOCIATE X'03'
          //
          // ATYP 地址类型
          //    o  IPv4  : X'01'
          //    o  网址  : X'03'
          //    o  IPv6  : X'04'
          //
          // DST.ADDR  目标地址
          //    DST.PORT  目标端口
          byte[] requestBuffer = new byte[257];
          byte[] responseBuffer = new byte[257];
          ushort nIndex;      byte[] rawBytes;
          nIndex = 0;
          requestBuffer[nIndex++] = 0x05; // version 5.
          requestBuffer[nIndex++] = 0x01; // command = connect.
          requestBuffer[nIndex++] = 0x00; // Reserve = 必须是 0x00      IPAddress targetAddress = null;
          if (!IPAddress.TryParse(targetIp, out targetAddress))
          {
            try
            {
              IPHostEntry iphe = Dns.GetHostEntry(targetIp);
              targetAddress = iphe.AddressList[0];
            }
            catch
            {
            }
          }      if (targetAddress != null)
          {
            switch (targetAddress.AddressFamily)//目的地址
            {
              case AddressFamily.InterNetwork://IPV4
                requestBuffer[nIndex++] = 0x01;
                rawBytes = targetAddress.GetAddressBytes();
                rawBytes.CopyTo(requestBuffer, nIndex);
                nIndex += (ushort)rawBytes.Length;
                break;
              case AddressFamily.InterNetworkV6://IPV6
                requestBuffer[nIndex++] = 0x04;
                rawBytes = targetAddress.GetAddressBytes();
                rawBytes.CopyTo(requestBuffer, nIndex);
                nIndex += (ushort)rawBytes.Length;
                break;
            }
          }
          else
          {
            // 目标地址是域名
            requestBuffer[nIndex++] = 0x03; // 地址是域名
            requestBuffer[nIndex++] = Convert.ToByte(targetIp.Length); // 该地址的长度
            rawBytes = Encoding.Default.GetBytes(targetIp);
            rawBytes.CopyTo(requestBuffer, nIndex);
            nIndex += (ushort)rawBytes.Length;
          }      // 使用 big-edian 字节顺序
          byte[] portBytes = BitConverter.GetBytes(targetPort);
          for (int i = portBytes.Length - 1; i >= 0; i--)
          {
            requestBuffer[nIndex++] = portBytes[i];
          }
          // 发送连接请求
          socket.Send(requestBuffer, nIndex, SocketFlags.None);
          int len = socket.Receive(responseBuffer); //获得没有固定长度的应答      // 应答格式
          // +----+-----+-------+------+----------+----------+
          // |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
          // +----+-----+-------+------+----------+----------+
          // | 1  |  1  | X'00' |  1   | Variable |    2     |
          // +----+-----+-------+------+----------+----------+
          //
          // o  VER    版本: X'05'
          // o  REP   
          //    o  X'00' 成功
          //    o  X'01' 普通的SOCKS服务器请求失败
          //    o  X'02' 现有的规则不允许的连接
          //    o  X'03' 网络不可达
          //    o  X'04' 主机不可达
          //    o  X'05' 连接被拒
          //    o  X'06' TTL超时
          //    o  X'07' 不支持的命令
          //    o  X'08' 不支持的地址类型
          //    o  X'09'到X'FF'  未定义
          // o  RSV    保留
          // o  ATYP   地址类型
          //    o  IPv4 : X'01'
          //    o  网址 : X'03'
          //    o  IPv6 : X'04'
          // o  BND.ADDR       服务器绑定的地址
          // o  BND.PORT       以网络字节顺序表示的服务器绑定的端口
          if (responseBuffer[1] != 0x00)
          {
            if (responseBuffer[1] >= socks5ErrorMessages.Length)
            {
              String message = System.Text.Encoding.Default.GetString(responseBuffer, 0, len);
              throw new Exception(message);
            }
            else
              throw new Exception(socks5ErrorMessages[responseBuffer[1]]);
          }      Byte addrType = responseBuffer[3];
          int bndAddrLength = len - 6;
          byte[] bndAddrBuffer = new byte[bndAddrLength];
          System.Array.Copy(responseBuffer, 4, bndAddrBuffer, 0, bndAddrLength);      String what = System.Text.Encoding.UTF8.GetString(bndAddrBuffer);      Byte bndPort1 = responseBuffer[len - 2];
          Byte bndPort2 = responseBuffer[len - 1];
        }
        #endregion  }
      

  5.   

    GetSocket() connectToSocks5Proxy() loginToSocks5Proxy()3个方法是连接socks5代理并做用户验证吧
    socks5connectToTarget()这个方法是连接目标服务器吗?这个方法中的socket参数怎么给?是上面方法中的还是新建的?
    如果是连接的,那么连接之后怎么登录?可以模拟下吗?Dobzhansky高手帮下忙
      

  6.   


        public POP3Client(Proxy proxy, string username, string password)
        {
          _proxy = proxy;
          _userName = username;
          _password = password;
            _socket = _proxy.GetSocket(); // 管他是代理还是直接连接呢, proxy 负责了        // 下面就当 socket 是目的机器
            // 初始化流
            _networkStream = new NetworkStream(_socket, true);
            _streamReader = new StreamReader(_networkStream, System.Text.Encoding.ASCII);
            _streamWriter = new StreamWriter(_networkStream, System.Text.Encoding.ASCII);
            _streamWriter.AutoFlush = true;        string answer = _streamReader.ReadLine();
        }
      

  7.   

    首先我谢谢Dobzhansky的帮忙,非常感谢!POP3Client()方法中的username,password是我要登录的目标服务器的用户名和密码吗?放在哪个地方呢?下面一段是我不用代理的连接方法,用了代理要如何改呢?呵呵 高手不要闲我烦哦!/// <summary>
            /// 登陆到服务器验证该用户名密码的用户是否为合法用户
            /// </summary>
            /// <param name="uid">用户名</param>
            /// <param name="pwd">密码</param>
            /// <returns>验证结果</returns>
            public static string[] CheckLogin(string uid,string pwd,TcpClient tcpClient)
            {
                pwd = EncryptAndDecrypt.MD5(uid+pwd);
                //string login = EncryptAndDecrypt.EncryptDES("login");
                Stream stream = tcpClient.GetStream();
                UTF8Encoding utf8 = new UTF8Encoding();
                byte[] bytes = utf8.GetBytes("login;" + uid + ";" + pwd);
                stream.Write(bytes, 0, bytes.Length);
                byte[] bb = new byte[1024];
                stream.Read(bb,0,bb.Length);
                string message = Encoding.UTF8.GetString(bb);
                string[] param = message.Split(';');
                stream.Close();
                tcpClient.Close();
                return param;
            }
      

  8.   


           /// 类增加两个成员变量保存代理类, socket 类
            Proxy _proxy;
            Socket _socket;
            // 上面两个成员的
            void createProxy()
            {
            _proxy= new Proxy(ProxyType.Socks5);
            _proxy.ProxyHost = "192.168.0.1";
            _proxy.ProxyPort = 1080;
            _proxy.TargetHost = "pop3.126.com";//目标主机和端口根据自己需要修改
            _proxy.TargetPort = 110;         }
    /// <summary>
            /// 登陆到服务器验证该用户名密码的用户是否为合法用户
            /// </summary>
            /// <param name="uid">用户名</param>
            /// <param name="pwd">密码</param>
            /// <returns>验证结果</returns>
            public static string[] CheckLogin(string uid,string pwd,TcpClient tcpClient)
            {
                pwd = EncryptAndDecrypt.MD5(uid+pwd);
                //string login = EncryptAndDecrypt.EncryptDES("login");
                /// 注意这里
                createProxy();
                _socket = _proxy.GetSocket(); // 这个调用发生连接到 proxy, proxy 连接到远程主机
                Stream stream = new NetworkStream(_socket, true);;
                UTF8Encoding utf8 = new UTF8Encoding();
                byte[] bytes = utf8.GetBytes("login;" + uid + ";" + pwd);
                stream.Write(bytes, 0, bytes.Length);
                byte[] bb = new byte[1024];
                stream.Read(bb,0,bb.Length);
                string message = Encoding.UTF8.GetString(bb);
                string[] param = message.Split(';');
                stream.Close();
                tcpClient.Close();
                return param;
            }
      

  9.   

    void CTestDlg::OnHttp() 
    {
        // TODO: Add your control notification handler code here
        CString m_sError;
        ClientSock.Create();
        //if( !ClientSock.Connect("61.145.123.202",3128) )
        if( !ClientSock.Connect("211.92.143.19",3128) )
        //if( !ClientSock.Connect("WWW.TOM.COM",80) )
        {
            m_sError = _T("不能连接到代理服务器!");
            ClientSock.Close();
            MessageBox(m_sError);
            return ;
        }    char buff[600] = {0};
    //    sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n");
        sprintf( buff, "%s%s:%d%s","CONNECT ","219.201.39.50",21," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
    //    sprintf( buff, "%s%s:%d%s","CONNECT ","www.tom.com",80," HTTP/1.1\r\nUser-Agent: CERN-LineMode/2.15 libwww/2.17b3\r\n\r\n");
    //    sprintf( buff, "%s%s","GET ","HTTP://WWW.TOM.COM HTTP/1.1\r\n\r\n");
        
        ClientSock.Send(buff,strlen(buff)); //发送请求
        memset(buff,0,600);
        ClientSock.Receive(buff,600);
        if(strstr(buff, "HTTP/1.0 200 Connection established") == NULL) //连接不成功
        {
            m_sError = _T("通过代理连接主站不成功!");
            ClientSock.Close();
            return ;
        }
        /*    if( strstr(buff, "Error 403") )
        {
            //return GoError(PROXYERROR_PROXYDISABLE);  //代理服务器拒绝请求
        }
        
        if( strstr(buff, "407 Proxy authentication required") )  //需要身份验证
        {
            //return GoError(PROXYERROR_USERNAMEORPASSWORD);  //用户身份校检不成功
        }
        if( strstr(buff, "Connection refuesed") )
        {
            //return GoError(PROXYERROR_CONNECTHOSTSERVER);  //通过代理连接主站不成功
        }
        if( strstr(buff, "Access Denied") )
        {
            //return GoError(PROXYERROR_USERNAMEORPASSWORD);  //用户身份校检不成功
        }
        if(strstr(buff, "Connection refused by Remote Host") )
        {
            //return GoError(PROXYERROR_CONNECTHOSTSERVER);  //通过代理连接主站不成功
        }
        
        ClientSock.Close();    
    */
    //连接已经建立,发送及接收数据
        memset(buff,0,600);
        strcpy(buff,"Hello!");
        ClientSock.Send(buff,sizeof(buff));
        memset(buff,0,600);
        ClientSock.Receive(buff,600);
        MessageBox(buff);
        ClientSock.Close();
        
        
    }
      

  10.   

    ProxyType 这个是什么类,怎么在C#中没找到。