none
如何访问Socket5 代理? RRS feed

  • 问题

  • LRESULT CClientSocket::OnSocketNotifyProxyRead()
    {
    	char* cRecvBuf=0;
    	int iRecvBufPos=0;
    	WORD wRecvSize=0;
    	WORD iRecvBufferLen=0;
    	int nServerIP = inet_addr(m_szRemoteIP);
    	if (m_nProxyOpState==1) 
    	{
    		if (!cRecvBuf)
    			cRecvBuf=new char[2];
    		//读取数据
    		int iRetCode=recv(m_hSocket,(char *)cRecvBuf,sizeof(cRecvBuf),0);
    		if (iRetCode==SOCKET_ERROR)
    			throw TEXT("读取代理服务器数据失败");
    		m_wRecvSize+=iRetCode;
    
    		if(m_wRecvSize==2)
    		{
    			if(cRecvBuf[0]!= 5)
    				throw TEXT("代理服务器数据异常");
    			if(cRecvBuf[1])			//需要验证
    			{
    				if (cRecvBuf[1]!=2)
    					throw TEXT("不支持的代理服务器验证方式");
    				//发送验证数据
    				LPCSTR lpszAsciiUser = m_ProxyInfo.strProxyName;
    				LPCSTR lpszAsciiPass = m_ProxyInfo.strProxyPass;
    				ASSERT(strlen(lpszAsciiUser)<=255);
    				ASSERT(strlen(lpszAsciiPass)<=255);
    				unsigned char *buffer = new unsigned char[3 + (lpszAsciiUser?strlen(lpszAsciiUser):0) + (lpszAsciiPass?strlen(lpszAsciiPass):0) + 1];
    				sprintf((char *)buffer, "  %s %s", lpszAsciiUser?lpszAsciiUser:"", lpszAsciiPass?lpszAsciiPass:"");
    				buffer[0]=1;
    				buffer[1]=static_cast<unsigned char>(strlen(lpszAsciiUser));
    				buffer[2+strlen(lpszAsciiUser)]=static_cast<unsigned char>(strlen(lpszAsciiPass));
    				int len=3+strlen(lpszAsciiUser)+strlen(lpszAsciiPass);
    				int res=send(m_hSocket,(LPSTR)&buffer,len,0);
    				delete [] buffer;
    				if (res==SOCKET_ERROR || res<len)
    				{
    					throw TEXT("代理服务器数据异常");
    				}
    				m_nProxyOpState++;
    				return 1;
    			}
    			//不需要验证
    			char *command=new char[10];
    			memset(command,0,10);
    			command[0]=5;
    			command[1]=1;			//请求类型 1:CONNECT,2:END,3:UDP ASSOCIATE
    			command[2]=0;
    			command[3]=1;			//地址类型 1:IPv4, 3:域名, 4:IPv6
    			int len=4;
    			if (nServerIP)
    			{
    				memcpy(&command[len],&nServerIP,4);
    				len+=4;
    			}
    			int nPort = htons(m_wRemotePort);
    			memcpy(&command[len],&nPort,2);
    			len+=2;
    			int res=send(m_hSocket,command,len,0);
    			delete [] command;
    			if (res==SOCKET_ERROR || res<len)
    			{
    				throw TEXT("代理服务器数据异常");
    			}
    			m_nProxyOpState+=2;
    			return 1;
    		}
    	}
    	else if(m_nProxyOpState==2)
    	{
    		if (!cRecvBuf)
    			cRecvBuf=new char[2];
    		int iRetCode=recv(m_hSocket,cRecvBuf+iRecvBufPos, 2-iRecvBufPos,0);
    		if (iRetCode==SOCKET_ERROR)
    		{
    			throw TEXT("代理服务器数据异常");
    		}
    		iRecvBufPos+=iRetCode;
    		if (iRecvBufPos==2)
    		{
    			if (cRecvBuf[1]!=0)
    			{
    				throw TEXT("代理服务器数据异常");
    			}
    			LPCSTR lpszAsciiHost =m_ProxyInfo.strProxyServer;
    			char *command=new char[10+strlen(lpszAsciiHost)+1];
    			memset(command,0,10+strlen(lpszAsciiHost)+1);
    			command[0]=5;
    			command[1]=1;
    			command[2]=0;
    			command[3]=1;
    			int len=4;
    			if (nServerIP)
    			{
    				memcpy(&command[len],&nServerIP,4);
    				len+=4;
    			}
    			int nPort = htons(m_wRemotePort);
    			memcpy(&command[len],&nPort,2);
    			len+=2;
    			int res=send(m_hSocket,command,len,0);
    			delete [] command;
    			if (res==SOCKET_ERROR || res<len)
    			{
    				throw TEXT("代理服务器数据异常");
    			}
    			m_nProxyOpState++;
    			return 1;
    		};
    	}
    	else if(m_nProxyOpState==3)
    	{
    		if (!cRecvBuf)
    		{
    			cRecvBuf=new char[10];
    			iRecvBufferLen = 10;
    		};
    		int iRetCode=recv(m_hSocket,cRecvBuf+iRecvBufPos, iRecvBufferLen-iRecvBufPos,0);
    		if (iRetCode==SOCKET_ERROR)
    		{
    			throw TEXT("代理服务器数据异常");
    		};
    		
    		iRecvBufPos+=iRetCode;
    		
    		if (iRecvBufPos==iRecvBufferLen)
    		{
    			if (cRecvBuf[1]!=0 || cRecvBuf[0]!=5)
    			{
    				static TCHAR szBuffer[64];
    				_snprintf(szBuffer,sizeof(szBuffer),TEXT("代理服务器连接游戏服务器错误,错误代码 [ %d ]"),cRecvBuf[1]);
    				throw szBuffer;
    			};
    			
    			SOCKADDR_IN SocketBindHostAddr; 
    
    			if (cRecvBuf[3]==1)
    			{
    				// 得到代理绑定地址
    				unsigned long ip;
    				int port;
    
    				ASSERT(cRecvBuf[3]==1);
    				memcpy(&ip,&cRecvBuf[4],4);
    				memcpy(&port,&cRecvBuf[8],2);
    
    				
    				static TCHAR szBuffer[64];
    				_snprintf(szBuffer,sizeof(szBuffer),TEXT("IP[%d],Port[%d]"),ip,port);
    
    				memset(&SocketBindHostAddr,0,sizeof(SocketBindHostAddr));
    				SocketBindHostAddr.sin_family=AF_INET;
    				SocketBindHostAddr.sin_port=port;
    				SocketBindHostAddr.sin_addr.S_un.S_addr=ip;		
    			}
    			else
    			{
    				char *tmp=new char[iRecvBufferLen+=cRecvBuf[4]+2];
    				memcpy(tmp,cRecvBuf,5);
    				delete [] cRecvBuf;
    				cRecvBuf=tmp;
    				iRecvBufferLen+=cRecvBuf[4]+2;
    			};
    
    			m_nProxyOpState++;
    
    
    						
    	
    			// 得到本机绑定地址
    			int len = sizeof(SocketBindHostAddr);
    			getsockname(m_hSocket,(SOCKADDR*)&SocketBindHostAddr,&len);
    
    			m_pIClientSocketSink->OnSocketConnect(0,TEXT(""),this);
    
    			return 1;
    		};
    	}
    	else
    	{
    		return 0;
    	};
    }
    大家帮忙看看 这是一个和Socket5代理服务器通信得函数。当m_nProxyOpState==3时,代理服务器应该返回 连接信息 ,这部分我就处理不明白了!希望高人指点。
    2009年10月9日 6:52

答案

  • 朋友,您好
    通过Socket5代理服务器访问网络的问题,我将以代码的形式说明并讲解你的问题。
    Socket5版本的协议说明参考 RFC1928,RFC1929
    下面简单地罗列程序实现,不涉及详细的协议规范。首先对于TCP连接,然后再讨论UDP传输。至于通过socket5的多播通讯,有兴趣可以参考MSDN 技术文章中D. Chouinard的文章。

    1、TCP:

    // 建立流套接字 
    SOCKET m_socTCP=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 连接到代理服务器
    int nRet = connect(m_socTCP,(SOCKADDR*)&m_saiProxy,sizeof(m_saiProxy));

    // Step 1: 连接代理服务器成功后,马上开始和代理协商,协商报文如下,询问服务器,版本5,是需要验证(0x02)还是不需要验证(0x00)
      +------+-------------------+------------+
      |VER   | Number of METHODS | METHODS    |
      +------+-------------------+------------+
      | 0x05 | 0x02 (有两个方法)  | 0x00 | 0x02|
      +------+-------------------+------------+
    const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
    nRet = send(m_socTCP,reqNego,4,0);

    // Setp 2: 代理服务器将返回两个字节的协商结果,接收协商结果
    fd_set fdread;FD_ZERO(&fdread);
    FD_SET(m_socTCP,&fdread);
    // Last param set to NULL for blocking operation. (struct timeval*)
    if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR){return NC_E_PROXY_SELECT_READ|WSAGetLastError();}
    char resNego[2]={'\0'};
    int nRcvd=0,nCount=0;
    while(1)
    {
    if(FD_ISSET(m_socTCP,&fdread))
    {
    //接收sock[0]发送来的数据
    do{
    nRet = recv(m_socTCP, (char*)resNego+nRcvd, 2-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nRcvd==2) break;
    }
    if(nCount++>=2000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)){return NC_E_PROXY_PROTOCOL_VERSION|WSAGetLastError();};

    // Step 3: 根据协商结果判断是否需要验证用户,如果是0x02,则需要提供验证,验证部分参考RFC1929
    if(resNego[1]==0x02)
    {
    // 需要密码验证
    char reqAuth[513]={'\0'};
    BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
    BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
    reqAuth[0]=0x01;
    reqAuth[1]=byLenUser;
    sprintf(&reqAuth[2],"%s",m_szProxyUserName);
    reqAuth[2+byLenUser]=byLenPswd;
    sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
    //Send authentication info
    int len = (int)byLenUser + (int)byLenPswd + 3;
    nRet=send(m_socTCP,(const char*)reqAuth,len,0);
    if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}
    //Now : Response to the auth request
    char resAuth[2]={'\0'};
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,resAuth+nRcvd,2-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    if (resAuth[1]!=0) return NC_E_PROXY_AUTHORIZE;
    // 密码验证通过了
    }

    // Step 4: 协商完成,开始发送连接远程服务器请求,请求报文格式如下:
      +----+-----+-------+------+----------+----------+
      |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 |  1 | 0x00  |  1 | Variable |   2   |
      +----+-----+-------+------+----------+----------+
    // CMD==0x01 表示连接, ATYP==0x01表示采用IPV4格式地址,DST.ADDR是远程服务器地址,DST.PORT是远程服务器端口
    // 如果需要接受外来连接,则需要在连接完成之后,发送CMD==0x02绑定请求,代理将为此请求绑定一个套接字接受外部连接
    char reqSubNego[10]={(char)0x05,(char)0x01,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
    *(unsigned long*)&reqSubNego[4] =m_saiServerTCP.sin_addr.S_un.S_addr;
    *(unsigned short*)&reqSubNego[8]=m_saiServerTCP.sin_port;
    nRet=send(m_socTCP,(const char*)reqSubNego,10,0);
    if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}

    // Step 5: 接收对请求的响应,响应包格式如下
      +----+-----+-------+------+----------+----------+
      |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 | 1 | 0x00  | 1   | Variable |   2   |
      +----+-----+-------+------+----------+----------+
    // VER 必须是0x05, REP==0x00表示成功,ATYP==0x01表示地址是IPV4地址,BND.ADDR 是代理为连接远程服务器绑定的地址,BND.PORT是这个套接字的端口
    char resSubNego1[5]={'\0'};
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,resSubNego1+nRcvd,5-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=5)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    if(resSubNego1[0]!=0x05||resSubNego1[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB|WSAGetLastError();};

    switch(resSubNego1[3])
    {
    case 0x01:
    {
    // IP V4
    char resSubNego2[6]={resSubNego1[4],0};
    int nRet=-1;
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    int nRet = recv(m_socTCP,&resSubNego2[1]+nRcvd,5-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=5)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    // 得到代理绑定地址
    unsigned long  ulBINDAddr = *(unsigned long*)&resSubNego2; // SOCKS BIND ADDR
    unsigned short usBINDPort = *(unsigned short*)&resSubNego2[4]; // SOCKS BIND PORT
    m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;
    m_saiProxyBindTCP.sin_port=usBINDPort;
    // 得到本机绑定地址
    int len = sizeof(m_saiHostTCP);
    getsockname(m_socTCP,(SOCKADDR*)&m_saiHostTCP,&len);
    }
    break;
    case 0x03:
    {
    // Domain name
    int nLen = resSubNego1[4]+2;
    char* presSubNego2 = new char[nLen];
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRet=0,nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,presSubNego2+nRcvd,nLen-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=nLen)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    unsigned short usBINDPort = *(unsigned short*)(presSubNego2+nLen-2); // BIND PORT;
    // 此时得到的是远程主机的Domain Name
    delete[] presSubNego2; presSubNego2=NULL;
    }
    break;
    case 0x04:
    {
    // IPV6
    AfxMessageBox("该版本不支持IPV6";
    }
    break;
    default:
    break;
    }

    // 至此,连接已经建立。在此套接字上可进行数据的收发。
    }

    2、UDP

    SOCKS V5提供了对UDP的支持,它通过在代理服务器和内网主机之间建立一个UDP中继的TCP连接,来辅助进行UDP数据包的收发。此连接有一个有效期,在此有效生命周期内,必须往代理发送UDP数据报确认连接有效,来维持此连接的有效性,否则,代理服务器超时,将会自动释放此连接的资源。
    下面简单地罗列程序实现,不涉及详细的协议规范。

    // 客户端为UDP中继建立一个相关的流套接字
    SOCKET m_socClientTCP_UdpAssociate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 连接代理服务器
    int nRet=connect(m_socClientTCP_UdpAssociate,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

    // 连接成功,开始和代理服务器协商,首先发送版本标志,方法选择报文
    const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
    nRet = send(m_socClientTCP_UdpAssociate,reqNego,4,0);
    if( nRet==SOCKET_ERROR 
    {
    DWORD dwError = WSAGetLastError();
    if (dwError!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
    }

    // 接收协商的响应
    fd_set fdread; FD_ZERO(&fdread);
    FD_SET(m_socClientTCP_UdpAssociate,&fdread);
    if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
    char resNego[2]={0};
    int nRcvd=0,nCount=0;
    if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
    {
    nRcvd = recv(m_socClientTCP_UdpAssociate, (char*)resNego+nRcvd, 2,0);
    if(nRcvd==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
    }
    if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;

    // 看是否需要密码验证
    if(resNego[1]==0x02)
    {
    // 需要密码验证
    char reqAuth[513]; memset(reqAuth,0,513);
    BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
    BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
    reqAuth[0]=0x01;
    reqAuth[1]=byLenUser;
    sprintf(&reqAuth[2],"%s",m_szProxyUserName);
    reqAuth[2+byLenUser]=byLenPswd;
    sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
    //Send authentication info
    int len = (int)byLenUser + (int)byLenPswd + 3;
    int ret=send(m_socClientTCP_UdpAssociate,(const char*)reqAuth,len,0);
    if (ret==SOCKET_ERROR) if (GetLastError()!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;

    //Now : Response to the auth request
    char resAuth[2]={'\0'};
    int nRcvd=0,nCount=0;
    do{
    ret = recv(m_socClientTCP_UdpAssociate,resAuth+nRcvd,2-nRcvd,0);
    if(ret==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE}
    if (resAuth[1]!=0)     return NEM_E_WM_CREATE_PROXYAUTHFAILED;
    // 密码验证通过了
    }

    // 开始发送向目标服务器的连接请求,其中DST.ADDR是目标服务器的地址,DST.PORT是目标服务器的UDP端口
    char reqSubNego[10]={(char)0x05,(char)0x03,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
    *(unsigned long*)&reqSubNego[4] =saiServerUDP.sin_addr.S_un.S_addr; // cmd: DEST.addr
    *(unsigned short*)&reqSubNego[8]=saiServerUDP.sin_port; // cmd: DEST.port in network octet order
    nRet=send(m_socClientTCP_UdpAssociate,(const char*)reqSubNego,10,0);
    if (nRet==SOCKET_ERROR) return NEM_E_WM_CREATE_PROXYREQFAILED;

    // 接收响应信息
    int nRecvCount = 0;
    int nRecvBufferLen = 10;
    char szRecvBuf[10];
    nRet = 0;
    if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socClientTCP_UdpAssociate,(char*)szRecvBuf+nRcvd,10-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=10)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE;}
    if (szRecvBuf[0]!=0x05||szRecvBuf[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB;}
    }
    else
    {
    return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
    }

    // 代理服务器绑定udp地址BND.ADR,一般代理服务器都是多宿主机器,因此这个绑定地址是局域网地址,代理服务器绑定udp端口BND.PORT
    // m_ulProxyUDPAddr 代理绑定地址
    // m_usUDPAssociatePort 代理绑定端口
    memmove(&m_ulProxyUDPAddr,&szRecvBuf[4],4);
    memmove(&m_usUDPAssociatePort,&szRecvBuf[8],2);

    m_bUDPAssociated = TRUE;
    // 至此,得到了代理绑定的地址和端口,客户端就可以通过它来收发UDP数据报了


    // 客户端收发实例
    // 首先创建数据报套接字,绑定套接字,得到本地数据报套接字地址,端口
    SOCKET m_socClientUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    SOCKADDR_IN saiLocal;
    memset(&saiLocal,0,sizeof(saiLocal));
    saiLocal.sin_family = AF_INET;
    saiLocal.sin_port = 0;
    saiLocal.sin_addr.S_un.S_addr = INADDR_ANY;
    // 绑定本地udp套接字地址,地址+端口由系统决定
    if (bind(m_socClientUDP, (SOCKADDR *)&saiLocal, sizeof(saiLocal)  == SOCKET_ERROR)
    getsockname(m_socClientUDP, (sockaddr*)&saiLocal, &len);
    // m_ulHostAddr 本机绑定地址
    // m_usHostPortUdp 本机绑定端口
    m_ulHostAddr = saiLocal.sin_addr.S_un.S_addr;
    m_usHostPortUdp = saiLocal.sin_port;

    // 按照格式,发送数据
    SOCKADDR_IN saiProxy;
    memset(&saiProxy,0,sizeof(saiProxy));
    saiProxy.sin_family = AF_INET;
    saiProxy.sin_addr.S_un.S_addr = m_ulProxyUDPAddr; // 代理绑定的udp地址
    saiProxy.sin_port = m_usUDPAssociatePort; // 代理绑定的udp端口

    // 每个UDP包必须携带如下所述的头:
          +----+------+------+----------+----------+----------+
          |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
          +----+------+------+----------+----------+----------+
          | 2  |  1   |  1   | Variable |    2     | Variable |
          +----+------+------+----------+----------+----------+
    // 其中 ATYP==0x01 表示采用 IPV4 地址,那么头长度就是10,DST.ADDR并不是服务器地址,而是本机绑定地址,DST.PORT是本机绑定端口
    char buf[10+2]={'0x00','0x00','0x00','0x01','0xff'};
    memmove(&buf[4],&m_ulHostAddr,4);
    *(unsigned short*)&buf[8]=m_usHostPortUDP;
    int nRet = sendto(m_socClientUDP,buf,12,0,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

    // 接收数据
    int nLen = sizeof(saiProxy);
    char buf=new char[MAX_UDPLEN];
    nRet = recvfrom(m_socClientUDP,buf,MAX_UDPLEN,0,(SOCKADDR *)&saiProxy,&nLen);
    if(nRet==SOCKET_ERROR) return SOCKET_ERROR;
    BYTE flag=0xff;
    if(memcmp(&buf[0],&flag,1)==0) return SOCKET_ERROR;
    BYTE byProxyHead[20];
    byProxyHead[0]=byProxyHead[1]=byProxyHead[2]=0;
    byProxyHead[3]=1;
    *(unsigned long*)&byProxyHead[4] = saiServerUDP.sin_addr.S_un.S_addr;
    *(unsigned short*)&byProxyHead[8] = saiServerUDP.sin_port;
    byProxyHead[10]=byProxyHead[11]=byProxyHead[12]=0;
    byProxyHead[13]=1;
    *(unsigned long*)&byProxyHead[14] = m_ulHostAddr;
    *(unsigned short*)&byProxyHead[18] = m_usHostPortUdp;

    int i=0;
    BOOL bIsForMe=FALSE;
    if(memcmp(&byProxyHead[0],&buf[i],4)==0)
    {
    unsigned long ulRetAddr = *(unsigned long*)&buf[i+4];
    if(ulRetAddr==m_ulHostAddr)
    {
    unsigned short usRetPort = ntohs((unsigned short)(*(unsigned short*)&buf[i+8]));
    if(usRetPort==m_usHostPortUdp)
    {
    bIsForMe=TRUE;
    }
    }
    i+=10;
    }
    // 客户端收发结束


    // 服务器端发送实例
    // m_ulProxyUDPAddr 代理绑定地址
    // m_usUDPAssociatePort 代理绑定端口
    // m_ulHostAddr 本机绑定地址
    // m_usHostPortUdp 本机绑定端口
    // 客户端必须把上面的m_ulProxyUDPAddr,m_usUDPAssociatePort,m_ulHostAddr,m_usHostPortUdp告知服务器,服务器通过这两个套接字进行数据的收发

    // 服务器创建数据报套接字
    SOCKET m_socUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

    // 代理的udp中继地址
    SOCKADDR_IN saiClient;
    saiClient.sin_family = AF_INET;
    saiClient.sin_addr.S_un.S_addr = m_ulProxyUDPAddr;
    saiClient.sin_port = m_usUDPAssociatePort;
    // 如果远程目标在代理服务器后面,透过代理,指定远程目标的socks信息,参照RFC1928
    char buffer[10]={'\0'};
    buffer[0]=buffer[1]=buffer[2]=0;
    buffer[3]=1; // No Fragment, It's a dependent udp, no need for socks server to arrange udp fragments

    // 目标机器的地址端口,透过代理后发向这里
    *(int*)&buffer[4]=m_ulHostAddr;
    *(unsigned short*)&buffer[8]=m_usHostPortUdp;
    BYTE buf[DATA_BUFSIZE]={'\0'};
    memmove(&buf[10],&szSendbuf[0],dwLength);
    memmove(&buf[0],&buffer[0],10);
    int nSent = sendto(m_socUDP, (const char*)&buf[0], dwLength+10, 0, (SOCKADDR*)&saiClient,sizeof(saiClient));
    // 服务器端发送结束
    Smile service,common progress!
    • 已标记为答案 Tim Li 2009年10月16日 10:00
    2009年10月9日 9:24

全部回复

  • 朋友,您好
    通过Socket5代理服务器访问网络的问题,我将以代码的形式说明并讲解你的问题。
    Socket5版本的协议说明参考 RFC1928,RFC1929
    下面简单地罗列程序实现,不涉及详细的协议规范。首先对于TCP连接,然后再讨论UDP传输。至于通过socket5的多播通讯,有兴趣可以参考MSDN 技术文章中D. Chouinard的文章。

    1、TCP:

    // 建立流套接字 
    SOCKET m_socTCP=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 连接到代理服务器
    int nRet = connect(m_socTCP,(SOCKADDR*)&m_saiProxy,sizeof(m_saiProxy));

    // Step 1: 连接代理服务器成功后,马上开始和代理协商,协商报文如下,询问服务器,版本5,是需要验证(0x02)还是不需要验证(0x00)
      +------+-------------------+------------+
      |VER   | Number of METHODS | METHODS    |
      +------+-------------------+------------+
      | 0x05 | 0x02 (有两个方法)  | 0x00 | 0x02|
      +------+-------------------+------------+
    const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
    nRet = send(m_socTCP,reqNego,4,0);

    // Setp 2: 代理服务器将返回两个字节的协商结果,接收协商结果
    fd_set fdread;FD_ZERO(&fdread);
    FD_SET(m_socTCP,&fdread);
    // Last param set to NULL for blocking operation. (struct timeval*)
    if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR){return NC_E_PROXY_SELECT_READ|WSAGetLastError();}
    char resNego[2]={'\0'};
    int nRcvd=0,nCount=0;
    while(1)
    {
    if(FD_ISSET(m_socTCP,&fdread))
    {
    //接收sock[0]发送来的数据
    do{
    nRet = recv(m_socTCP, (char*)resNego+nRcvd, 2-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nRcvd==2) break;
    }
    if(nCount++>=2000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)){return NC_E_PROXY_PROTOCOL_VERSION|WSAGetLastError();};

    // Step 3: 根据协商结果判断是否需要验证用户,如果是0x02,则需要提供验证,验证部分参考RFC1929
    if(resNego[1]==0x02)
    {
    // 需要密码验证
    char reqAuth[513]={'\0'};
    BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
    BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
    reqAuth[0]=0x01;
    reqAuth[1]=byLenUser;
    sprintf(&reqAuth[2],"%s",m_szProxyUserName);
    reqAuth[2+byLenUser]=byLenPswd;
    sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
    //Send authentication info
    int len = (int)byLenUser + (int)byLenPswd + 3;
    nRet=send(m_socTCP,(const char*)reqAuth,len,0);
    if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}
    //Now : Response to the auth request
    char resAuth[2]={'\0'};
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,resAuth+nRcvd,2-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    if (resAuth[1]!=0) return NC_E_PROXY_AUTHORIZE;
    // 密码验证通过了
    }

    // Step 4: 协商完成,开始发送连接远程服务器请求,请求报文格式如下:
      +----+-----+-------+------+----------+----------+
      |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 |  1 | 0x00  |  1 | Variable |   2   |
      +----+-----+-------+------+----------+----------+
    // CMD==0x01 表示连接, ATYP==0x01表示采用IPV4格式地址,DST.ADDR是远程服务器地址,DST.PORT是远程服务器端口
    // 如果需要接受外来连接,则需要在连接完成之后,发送CMD==0x02绑定请求,代理将为此请求绑定一个套接字接受外部连接
    char reqSubNego[10]={(char)0x05,(char)0x01,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
    *(unsigned long*)&reqSubNego[4] =m_saiServerTCP.sin_addr.S_un.S_addr;
    *(unsigned short*)&reqSubNego[8]=m_saiServerTCP.sin_port;
    nRet=send(m_socTCP,(const char*)reqSubNego,10,0);
    if (nRet==SOCKET_ERROR){return NC_E_PROXY_SEND|WSAGetLastError();}

    // Step 5: 接收对请求的响应,响应包格式如下
      +----+-----+-------+------+----------+----------+
      |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 | 1 | 0x00  | 1   | Variable |   2   |
      +----+-----+-------+------+----------+----------+
    // VER 必须是0x05, REP==0x00表示成功,ATYP==0x01表示地址是IPV4地址,BND.ADDR 是代理为连接远程服务器绑定的地址,BND.PORT是这个套接字的端口
    char resSubNego1[5]={'\0'};
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,resSubNego1+nRcvd,5-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=5)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    if(resSubNego1[0]!=0x05||resSubNego1[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB|WSAGetLastError();};

    switch(resSubNego1[3])
    {
    case 0x01:
    {
    // IP V4
    char resSubNego2[6]={resSubNego1[4],0};
    int nRet=-1;
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    int nRet = recv(m_socTCP,&resSubNego2[1]+nRcvd,5-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=5)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    // 得到代理绑定地址
    unsigned long  ulBINDAddr = *(unsigned long*)&resSubNego2; // SOCKS BIND ADDR
    unsigned short usBINDPort = *(unsigned short*)&resSubNego2[4]; // SOCKS BIND PORT
    m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;
    m_saiProxyBindTCP.sin_port=usBINDPort;
    // 得到本机绑定地址
    int len = sizeof(m_saiHostTCP);
    getsockname(m_socTCP,(SOCKADDR*)&m_saiHostTCP,&len);
    }
    break;
    case 0x03:
    {
    // Domain name
    int nLen = resSubNego1[4]+2;
    char* presSubNego2 = new char[nLen];
    if(FD_ISSET(m_socTCP,&fdread))
    {
    int nRet=0,nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socTCP,presSubNego2+nRcvd,nLen-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=nLen)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    }
    unsigned short usBINDPort = *(unsigned short*)(presSubNego2+nLen-2); // BIND PORT;
    // 此时得到的是远程主机的Domain Name
    delete[] presSubNego2; presSubNego2=NULL;
    }
    break;
    case 0x04:
    {
    // IPV6
    AfxMessageBox("该版本不支持IPV6";
    }
    break;
    default:
    break;
    }

    // 至此,连接已经建立。在此套接字上可进行数据的收发。
    }

    2、UDP

    SOCKS V5提供了对UDP的支持,它通过在代理服务器和内网主机之间建立一个UDP中继的TCP连接,来辅助进行UDP数据包的收发。此连接有一个有效期,在此有效生命周期内,必须往代理发送UDP数据报确认连接有效,来维持此连接的有效性,否则,代理服务器超时,将会自动释放此连接的资源。
    下面简单地罗列程序实现,不涉及详细的协议规范。

    // 客户端为UDP中继建立一个相关的流套接字
    SOCKET m_socClientTCP_UdpAssociate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 连接代理服务器
    int nRet=connect(m_socClientTCP_UdpAssociate,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

    // 连接成功,开始和代理服务器协商,首先发送版本标志,方法选择报文
    const char reqNego[4]={(char)0x05,(char)0x02,(char)0x00,(char)0x02};
    nRet = send(m_socClientTCP_UdpAssociate,reqNego,4,0);
    if( nRet==SOCKET_ERROR 
    {
    DWORD dwError = WSAGetLastError();
    if (dwError!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
    }

    // 接收协商的响应
    fd_set fdread; FD_ZERO(&fdread);
    FD_SET(m_socClientTCP_UdpAssociate,&fdread);
    if((nRet=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
    char resNego[2]={0};
    int nRcvd=0,nCount=0;
    if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
    {
    nRcvd = recv(m_socClientTCP_UdpAssociate, (char*)resNego+nRcvd, 2,0);
    if(nRcvd==SOCKET_ERROR) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;
    }
    if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02)) return NCM_E_WM_CREATE_PROXYCONNECTFAILED;

    // 看是否需要密码验证
    if(resNego[1]==0x02)
    {
    // 需要密码验证
    char reqAuth[513]; memset(reqAuth,0,513);
    BYTE byLenUser = (BYTE)strlen(m_szProxyUserName);
    BYTE byLenPswd = (BYTE)strlen(m_szProxyPassword);
    reqAuth[0]=0x01;
    reqAuth[1]=byLenUser;
    sprintf(&reqAuth[2],"%s",m_szProxyUserName);
    reqAuth[2+byLenUser]=byLenPswd;
    sprintf(&reqAuth[3+byLenUser],"%s",m_szProxyPassword);
    //Send authentication info
    int len = (int)byLenUser + (int)byLenPswd + 3;
    int ret=send(m_socClientTCP_UdpAssociate,(const char*)reqAuth,len,0);
    if (ret==SOCKET_ERROR) if (GetLastError()!=WSAEWOULDBLOCK) return NCM_E_WM_CREATE_PROXYREQUESTFAILED;

    //Now : Response to the auth request
    char resAuth[2]={'\0'};
    int nRcvd=0,nCount=0;
    do{
    ret = recv(m_socClientTCP_UdpAssociate,resAuth+nRcvd,2-nRcvd,0);
    if(ret==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=2)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE}
    if (resAuth[1]!=0)     return NEM_E_WM_CREATE_PROXYAUTHFAILED;
    // 密码验证通过了
    }

    // 开始发送向目标服务器的连接请求,其中DST.ADDR是目标服务器的地址,DST.PORT是目标服务器的UDP端口
    char reqSubNego[10]={(char)0x05,(char)0x03,(char)0x00,(char)0x01,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0x00};
    *(unsigned long*)&reqSubNego[4] =saiServerUDP.sin_addr.S_un.S_addr; // cmd: DEST.addr
    *(unsigned short*)&reqSubNego[8]=saiServerUDP.sin_port; // cmd: DEST.port in network octet order
    nRet=send(m_socClientTCP_UdpAssociate,(const char*)reqSubNego,10,0);
    if (nRet==SOCKET_ERROR) return NEM_E_WM_CREATE_PROXYREQFAILED;

    // 接收响应信息
    int nRecvCount = 0;
    int nRecvBufferLen = 10;
    char szRecvBuf[10];
    nRet = 0;
    if(FD_ISSET(m_socClientTCP_UdpAssociate,&fdread))
    {
    int nRcvd=0,nCount=0;
    do{
    nRet = recv(m_socClientTCP_UdpAssociate,(char*)szRecvBuf+nRcvd,10-nRcvd,0);
    if(nRet==SOCKET_ERROR){return NC_E_PROXY_RECEIVE|WSAGetLastError();}
    nRcvd += nRet;
    }
    while((nRcvd!=10)&&(++nCount<1000));
    if(nCount>=1000){return NC_E_PROXY_RECEIVE;}
    if (szRecvBuf[0]!=0x05||szRecvBuf[1]!=0x00){return NC_E_PROXY_PROTOCOL_VERSION_SUB;}
    }
    else
    {
    return NCM_E_WM_CREATE_PROXYREQUESTFAILED;
    }

    // 代理服务器绑定udp地址BND.ADR,一般代理服务器都是多宿主机器,因此这个绑定地址是局域网地址,代理服务器绑定udp端口BND.PORT
    // m_ulProxyUDPAddr 代理绑定地址
    // m_usUDPAssociatePort 代理绑定端口
    memmove(&m_ulProxyUDPAddr,&szRecvBuf[4],4);
    memmove(&m_usUDPAssociatePort,&szRecvBuf[8],2);

    m_bUDPAssociated = TRUE;
    // 至此,得到了代理绑定的地址和端口,客户端就可以通过它来收发UDP数据报了


    // 客户端收发实例
    // 首先创建数据报套接字,绑定套接字,得到本地数据报套接字地址,端口
    SOCKET m_socClientUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    SOCKADDR_IN saiLocal;
    memset(&saiLocal,0,sizeof(saiLocal));
    saiLocal.sin_family = AF_INET;
    saiLocal.sin_port = 0;
    saiLocal.sin_addr.S_un.S_addr = INADDR_ANY;
    // 绑定本地udp套接字地址,地址+端口由系统决定
    if (bind(m_socClientUDP, (SOCKADDR *)&saiLocal, sizeof(saiLocal)  == SOCKET_ERROR)
    getsockname(m_socClientUDP, (sockaddr*)&saiLocal, &len);
    // m_ulHostAddr 本机绑定地址
    // m_usHostPortUdp 本机绑定端口
    m_ulHostAddr = saiLocal.sin_addr.S_un.S_addr;
    m_usHostPortUdp = saiLocal.sin_port;

    // 按照格式,发送数据
    SOCKADDR_IN saiProxy;
    memset(&saiProxy,0,sizeof(saiProxy));
    saiProxy.sin_family = AF_INET;
    saiProxy.sin_addr.S_un.S_addr = m_ulProxyUDPAddr; // 代理绑定的udp地址
    saiProxy.sin_port = m_usUDPAssociatePort; // 代理绑定的udp端口

    // 每个UDP包必须携带如下所述的头:
          +----+------+------+----------+----------+----------+
          |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
          +----+------+------+----------+----------+----------+
          | 2  |  1   |  1   | Variable |    2     | Variable |
          +----+------+------+----------+----------+----------+
    // 其中 ATYP==0x01 表示采用 IPV4 地址,那么头长度就是10,DST.ADDR并不是服务器地址,而是本机绑定地址,DST.PORT是本机绑定端口
    char buf[10+2]={'0x00','0x00','0x00','0x01','0xff'};
    memmove(&buf[4],&m_ulHostAddr,4);
    *(unsigned short*)&buf[8]=m_usHostPortUDP;
    int nRet = sendto(m_socClientUDP,buf,12,0,(SOCKADDR*)&saiProxy,sizeof(saiProxy));

    // 接收数据
    int nLen = sizeof(saiProxy);
    char buf=new char[MAX_UDPLEN];
    nRet = recvfrom(m_socClientUDP,buf,MAX_UDPLEN,0,(SOCKADDR *)&saiProxy,&nLen);
    if(nRet==SOCKET_ERROR) return SOCKET_ERROR;
    BYTE flag=0xff;
    if(memcmp(&buf[0],&flag,1)==0) return SOCKET_ERROR;
    BYTE byProxyHead[20];
    byProxyHead[0]=byProxyHead[1]=byProxyHead[2]=0;
    byProxyHead[3]=1;
    *(unsigned long*)&byProxyHead[4] = saiServerUDP.sin_addr.S_un.S_addr;
    *(unsigned short*)&byProxyHead[8] = saiServerUDP.sin_port;
    byProxyHead[10]=byProxyHead[11]=byProxyHead[12]=0;
    byProxyHead[13]=1;
    *(unsigned long*)&byProxyHead[14] = m_ulHostAddr;
    *(unsigned short*)&byProxyHead[18] = m_usHostPortUdp;

    int i=0;
    BOOL bIsForMe=FALSE;
    if(memcmp(&byProxyHead[0],&buf[i],4)==0)
    {
    unsigned long ulRetAddr = *(unsigned long*)&buf[i+4];
    if(ulRetAddr==m_ulHostAddr)
    {
    unsigned short usRetPort = ntohs((unsigned short)(*(unsigned short*)&buf[i+8]));
    if(usRetPort==m_usHostPortUdp)
    {
    bIsForMe=TRUE;
    }
    }
    i+=10;
    }
    // 客户端收发结束


    // 服务器端发送实例
    // m_ulProxyUDPAddr 代理绑定地址
    // m_usUDPAssociatePort 代理绑定端口
    // m_ulHostAddr 本机绑定地址
    // m_usHostPortUdp 本机绑定端口
    // 客户端必须把上面的m_ulProxyUDPAddr,m_usUDPAssociatePort,m_ulHostAddr,m_usHostPortUdp告知服务器,服务器通过这两个套接字进行数据的收发

    // 服务器创建数据报套接字
    SOCKET m_socUDP=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

    // 代理的udp中继地址
    SOCKADDR_IN saiClient;
    saiClient.sin_family = AF_INET;
    saiClient.sin_addr.S_un.S_addr = m_ulProxyUDPAddr;
    saiClient.sin_port = m_usUDPAssociatePort;
    // 如果远程目标在代理服务器后面,透过代理,指定远程目标的socks信息,参照RFC1928
    char buffer[10]={'\0'};
    buffer[0]=buffer[1]=buffer[2]=0;
    buffer[3]=1; // No Fragment, It's a dependent udp, no need for socks server to arrange udp fragments

    // 目标机器的地址端口,透过代理后发向这里
    *(int*)&buffer[4]=m_ulHostAddr;
    *(unsigned short*)&buffer[8]=m_usHostPortUdp;
    BYTE buf[DATA_BUFSIZE]={'\0'};
    memmove(&buf[10],&szSendbuf[0],dwLength);
    memmove(&buf[0],&buffer[0],10);
    int nSent = sendto(m_socUDP, (const char*)&buf[0], dwLength+10, 0, (SOCKADDR*)&saiClient,sizeof(saiClient));
    // 服务器端发送结束
    Smile service,common progress!
    • 已标记为答案 Tim Li 2009年10月16日 10:00
    2009年10月9日 9:24
  • 首先感谢Mack Juesson 用户奖牌用户奖牌用户奖牌用户奖牌用户奖牌,你发的这个例子我看过了! 其中TCP方式连接代理时,在密码验证完成后,代理服务器会发回代理绑定地址。用的是如下方式获得的代理绑定地址

    // 得到代理绑定地址
    unsigned long  ulBINDAddr = *(unsigned long*)&resSubNego2; // SOCKS BIND ADDR
    unsigned short usBINDPort = *(unsigned short*)&resSubNego2[4]; // SOCKS BIND PORT
    m_saiProxyBindTCP.sin_addr.S_un.S_addr=ulBINDAddr;
    m_saiProxyBindTCP.sin_port=usBINDPort;
    // 得到本机绑定地址
    int len = sizeof(m_saiHostTCP);
    getsockname(m_socTCP,(SOCKADDR*)&m_saiHostTCP,&len);



    我不明白getsockname  这个函数是干什么用的,起什么作用,还有执行完上述代码后是不是就可以直接使用m_socTCP访问网络了?不需要在考虑代理的因素了。
    麻烦Mack Juesson 了。

    2009年10月9日 10:29
  • 高手们帮帮忙! 很急,已经研究好多天了!  多谢了!

    2009年10月10日 2:01
  • 您好
    getsockname 是获得socked地址的,通过获得的地址,就可以访问网络了。
    Smile service,common progress!
    2009年10月11日 13:07
  • 多谢Mack Juesson,我回头再试试!
    2009年10月11日 15:34