Socket编程,如何通过代理连接互联网上的服务器?
我写了个服务器,用的是MFC的CSocket,当服务器和客户端同在一个局或网,或都在公网上,都可以成功连接,但如果服务器在公网上,客户端在局域网,局域网通过代理上网,这个时候就连接不上了。请问有没有办法解决? 问题点数:50、回复次数:15Top
1 楼yang79tao()回复于 2005-02-25 21:34:32 得分 0
dingTop
2 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-02-26 08:53:07 得分 0
要看你是TCP连接,还是UDP连接,是http代理、socks5代理,还是什么其他的。Top
3 楼yang79tao()回复于 2005-02-26 09:38:06 得分 0
TCP连接,http代理、socks5代理均可,两者都有。Top
4 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-02-26 10:39:06 得分 0
客户端程序是你写的吗?如果不是,代理相对与服务器应该是透明的,一般不会出现不用代理能够连上,用代理连不上的问题,建议你跟踪一下代码,以便发现连不上的具体原因。Top
5 楼chenjieread(苦学VC++中...)回复于 2005-02-26 10:39:47 得分 0
呵呵,很感兴趣啊!!!大家继续讨论哦Top
6 楼yang79tao()回复于 2005-02-26 15:49:16 得分 0
情况是这样的:
客户和服务器端都是我写的,服务器端放在公网上,客户端放在通过代理能上外网的某局域网的一台机器上,客户端连接不上服务器。我回去看看返回的错误代码吧。Top
7 楼yang79tao()回复于 2005-02-26 19:01:41 得分 0
错误代码当然是:WSAEHOSTUNREACH,解释为:no route to host,
我想这样的情况应该是先按照Socket5代理协议把要连接的请求发到代理服务器上才行啊,可是我一点也不懂Socket5代理协议或是HTTP代理协议,哪位高手能不能帮个忙啊!发贴这么长时间了!Top
8 楼kugou123(酷狗)(彪悍的人生,不需要解释 www.xiaozhou.net)回复于 2005-02-26 20:39:28 得分 10
http://www.xiaozhou.net/ReadNews.asp?NewsID=881Top
9 楼yang79tao()回复于 2005-02-27 19:04:42 得分 0
dingTop
10 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-02-28 09:18:24 得分 0
基本可以确定是你代理的部分出问题了,我这儿收集了些资料,希望对你有帮助。
http://archive.socks.permeo.com/protocol/socks4.protocol
http://www.cnpaf.net/rfc/rfc1928.txt
如果协议发生冲突,以rfc1928为准。
另外,你可以使用一些软件在你自己的机器上架设代理服务器。Top
11 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-02-28 09:19:22 得分 40
(转载,出处忘了)
穿透代理服务器编程
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。
正文
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。
//使用到的结构
struct sock4req1
{
char VN;
char CD;
unsigned short Port;
unsigned long IPAddr;
char other[1];
};
struct sock4ans1
{
char VN;
char CD;
};
struct sock5req1
{
char Ver;
char nMethods;
char Methods[255];
};
struct sock5ans1
{
char Ver;
char Method;
};
struct sock5req2
{
char Ver;
char Cmd;
char Rsv;
char Atyp;
char other[1];
};
struct sock5ans2
{
char Ver;
char Rep;
char Rsv;
char Atyp;
char other[1];
};
struct authreq
{
char Ver;
char Ulen;
char Name[255];
char PLen;
char Pass[255];
};
struct authans
{
char Ver;
char Status;
};
//通过Socks4方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[100];
memset(buff,0,100);
struct sock4req1 *m_proxyreq;
m_proxyreq = (struct sock4req1 *)buff;
m_proxyreq->VN = 4;
m_proxyreq->CD = 1;
m_proxyreq->Port = ntohs(GetPort());
m_proxyreq->IPAddr = inet_addr(GetServerHostName());
ClientSock.Send(buff,9);
struct sock4ans1 *m_proxyans;
m_proxyans = (struct sock4ans1 *)buff;
memset(buff,0,100);
ClientSock.Receive(buff,100);
if(m_proxyans->VN != 0 || m_proxyans->CD != 90)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}
//通过Socks5方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[600];
struct sock5req1 *m_proxyreq1;
m_proxyreq1 = (struct sock5req1 *)buff;
m_proxyreq1->Ver = 5;
m_proxyreq1->nMethods = 2;
m_proxyreq1->Methods[0] = 0;
m_proxyreq1->Methods[1] = 2;
ClientSock.Send(buff,4);
struct sock5ans1 *m_proxyans1;
m_proxyans1 = (struct sock5ans1 *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_proxyans1->Ver != 5 || (m_proxyans1->Method!=0 && m_proxyans1->Method!=2))
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}
if(m_proxyans1->Method == 2)
{
int nUserLen = strlen(g_ProxyInfo.m_strProxyUser);
int nPassLen = strlen(g_ProxyInfo.m_strProxyPass);
struct authreq *m_authreq;
m_authreq = (struct authreq *)buff;
m_authreq->Ver = 1;
m_authreq->Ulen = nUserLen;
strcpy(m_authreq->Name,g_ProxyInfo.m_strProxyUser);
m_authreq->PLen = nPassLen;
strcpy(m_authreq->Pass,g_ProxyInfo.m_strProxyPass);
ClientSock.Send(buff,513);
struct authans *m_authans;
m_authans = (struct authans *)buff;
memset(buff,0,600);
ClientSock.Receive(buff,600);
if(m_authans->Ver != 1 || m_authans->Status != 0)
{
m_sError = _T("代理服务器用户验证不成功!");
ClientSock.Close();
return FALSE;
}
}
struct sock5req2 *m_proxyreq2;
m_proxyreq2 = (struct sock5req2 *)buff;
m_proxyreq2->Ver = 5;
m_proxyreq2->Cmd = 1;
m_proxyreq2->Rsv = 0;
m_proxyreq2->Atyp = 1;
unsigned long tmpLong = inet_addr(GetServerHostName());
unsigned short port = ntohs(GetPort());
memcpy(m_proxyreq2->other,&tmpLong,4);
memcpy(m_proxyreq2->other+4,&port,2);
ClientSock.Send(buff,sizeof(struct sock5req2)+5);
struct sock5ans2 *m_proxyans2;
memset(buff,0,600);
m_proxyans2 = (struct sock5ans2 *)buff;
ClientSock.Receive(buff,600);
if(m_proxyans2->Ver != 5 || m_proxyans2->Rep != 0)
{
m_sError = _T("通过代理连接主站不成功!");
ClientSock.Close();
return FALSE;
}
//通过HTTP方式代理
if( !ClientSock.Connect( g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort) )
{
m_sError = _T("不能连接到代理服务器!");
ClientSock.Close();
return FALSE;
}
char buff[600];
sprintf( buff, "%s%s:%d%s","CONNECT ",GetServerHostName(),GetPort()," HTTP/1.1 User-Agent: MyApp/0.1 ");
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 FALSE;
}
我们一般先与代理服务器连通,然后向代理服务器发送代理验证的用户名和密码(如果需要,如Socks5代理),验证成功后,再向代理服务器发送需要连接的目的地址和端口。以上代码仅用于TCP连接,如果在内部网侦听或通过UDP协议发送信息,可查阅RFC1829等文档资料。
Top
12 楼fisker0303(天塌了,地陷了,小花狗不见了.)回复于 2005-02-28 09:19:41 得分 0
(转载,出处忘了)
用socks5进行udp发送数据的过程:
你的目的是要和服务器做UDP的数据传送。
步骤:
1,和代理建立tcp联接,(你已经完成)。
2,向代理发送版本的请求信息, 我的实现:
void CCommunicator::SendVer()
{
int datasize = 6;
char tempbuf[6];
tempbuf[0]=5;
tempbuf[1]=4;//标示后面所根的字接数
tempbuf[2]=0;
tempbuf[3]=1;
tempbuf[4]=2;
tempbuf[5]=3;
int senddatalen;
senddatalen=send(m_sock,(char*)tempbuf,6,0);
}
这一步,你已经返回成功,是吗?如果失败,断开建立的tcp联接,如果成功,如果需要用户验证则进行步骤3,否则进行4.
3,如果需要用户验证,则类似:
BOOL CCommunicator::SendUserTest()
{
int usernamelen=0;
int userpasslen=0;
usernamelen=m_strTestUserName.GetLength();
userpasslen=m_strTestUserPass.GetLength();
char tempbuf[100];
tempbuf[0]=5;
tempbuf[1]=usernamelen;//标示后面所根的字接数
strcpy(&tempbuf[2],m_strTestUserName);
tempbuf[2+usernamelen]=userpasslen;
strcpy((char*)&tempbuf [3+usernamelen],m_strTestUserPass);
int senddatalen;
int len;
len=usernamelen+userpasslen+3;
senddatalen=send(m_sock,(char*)tempbuf,len,0);
} 如果失败,断开建立的tcp联接, 如果用户返回成功,步骤4.
4,发送请求的协议类似:
void CCommunicator::SendRequestUDP()
{
int const datasize=10;
BYTE tempbuf[datasize]; tempbuf[0]=5;
tempbuf[1]=3;//标示UDP连接
tempbuf[2]=0;
tempbuf[3]=1;
tempbuf[4]=0;
tempbuf[5]=0;
tempbuf[6]=0;
tempbuf[7]=0;
*((SHORT*)(&(tempbuf[8])))=m_uBindUDPPort; //UDP在客户端绑定的端口,就是你本地机器的做udp数据传送的端口调用
//socket函数后,再调用bind()来邦定一个端口。
char temp;
temp=tempbuf[8];
tempbuf[8]=tempbuf[9];
tempbuf[9]=temp;
int senddatalen=send(m_sock,(char*)tempbuf,datasize,0);
}
如果失败,断开建立的tcp联接,如果返回成功,验证完毕!步骤5
5,真正的数据传送,用代理传送的时候,数据包的前面加上10个字节类似:
void CCommunicator::CopyDataHead(BYTE * ptempbuf)
{
struct in_addr addr;
addr.s_addr=inet_addr(“202.220.33.333”);//这个ip是服务器端的ip
ptempbuf[0]=0;
ptempbuf[1]=0;
ptempbuf[2]=0;
ptempbuf[3]=1;
ptempbuf[4]=(char)addr.S_un.S_un_b.s_b1;
ptempbuf[5]=(char)addr.S_un.S_un_b.s_b2;
ptempbuf[6]=(char)addr.S_un.S_un_b.s_b3;
ptempbuf[7]=(char)addr.S_un.S_un_b.s_b4;
*((SHORT*)(&(ptempbuf[8])))=m_uServerUDPPort;//服务器的端口,就是你最终要发到那个服务器的端口,也就是你的qq服务器。
char temp;
temp=ptempbuf[8];
ptempbuf[8]=ptempbuf[9];
ptempbuf[9]=temp;
}
真正发送的时候类似:
int CCommunicator::SendBufferUDP(LPBYTE lpBuf,int nLen)
{
BYTE tempbuf[1000];
int iHeadData=0;
struct sockaddr_in her;
her.sin_family=AF_INET;
her.sin_addr.s_addr=inet_addr(m_szProxyAddr);//代理服务器
her.sin_port=htons(m_uSocksPort);//发送请求的时候返回的代理服务器端的端口,记住,这是最重要的。
CopyDataHead(tempbuf);
iHeadData=10;
nLen=nLen+10;
int addr_len;
addr_len=sizeof(struct sockaddr);
CopyMemory((char*)&tempbuf[iHeadData],lpBuf,nLen);
int returndatalen=sendto(m_socket,(char *)tempbuf,nLen,0,(struct sockaddr *)&her,addr_len);
}Top
13 楼louifox(兰陵笑笑生)回复于 2005-02-28 10:20:20 得分 0
dingTop
14 楼gdy119(夜风微凉)回复于 2005-02-28 13:14:59 得分 0
看一下过代理的文章Top
15 楼T97102003(池塘里的水手)回复于 2005-02-28 13:21:37 得分 0
upTop




