目的
提供TCP客户端到UDP服务器的访问的数据转发。有时候我们的服务器提供UDP的数据包格式,可是由于种种原因,
我们的客户端只能通过TCP来访问。本文就是提供TCP到UDP的数据转发的功能。本代理接收TCP客户连接请求后,把数
据转发到UDP服务器,同时把UDP服务器回送的数据,转发回TCP客户。
设计
//主程序
Main()
{
beginthread(t2uMainThread());
}
//主线程
t2uMainThread(Param)
{
创建"本地监听 TCP SOCK"
while(true)
{
等待 TCP 客户端的连接
等到后,创建"目标 UDP SOCK"
创建并运行"t2u Wait Thread"
}
}
//t2u Wait Thread 线程
t2u Wait Thread (Param)
{
创建"连接 TCP SOCK"->"目标 UDP SOCK"数据转发Thread
创建"目标 UDP SOCK"->"连接 TCP SOCK"数据转发Thread
等待这两个线程结束
释放SOCK资源
}
//TCP2UDP 数据转发线程
TCP2UDP Thread(Param)
{
SOCK FROM,TO
while(read >0)
{
read(From,Buff);
Sendto(To,Buff);
}
}
//UDP2TCP 数据转发线程
UDP2TCP Thread(Param)
{
SOCK FROM,TO
while(read >0)
{
readfrom(From,Buff);
Send(To,Buff);
}
}
参考代码
参数结构
struct DATAREDIRDPARAM
{
SOCKET sock[2];
/*如果模式为t,那么此地址结构是UDP Client的地址,此地址在接收到UDP Client数据后填
充
如果模式为u,那么此地址结构为Target的地址*/
struct sockaddr_in sinudp;
BOOL sinudpisfilled;//上面的数据填充与否的标志
struct icmpheader icmphdr;
DATAREDIRDPARAM()
{
sinudpisfilled = FALSE;
}
};
//主线程
DWORD WINAPI t2umainthread(LPVOID lpvoid)
{
AGENTTCPUDPGATEWAYINFO *pasi = (AGENTTCPUDPGATEWAYINFO*)lpvoid;
AGENTTCPUDPGATEWAYINFO asi;
memcpy(&asi,pasi,sizeof(AGENTTCPUDPGATEWAYINFO));
delete pasi; pasi = NULL;
//-u
//如果模式为u,那么此地址结构为Target的地址
struct sockaddr_in sinudp;
BOOL sinudpisfilled = FALSE;//上面的数据填充与否的标志
int iRet;
struct sockaddr_in UDPLocal,TCPLocal,Target;
SOCKET sListen,s[2];//s[0]=>UDP socket s[1]=>TCP socket
HANDLE hThread[2]={NULL,NULL};
printf("/nOK!Work mode is tcp2udp.");
//目标地址结构
Target.sin_family=AF_INET;
Target.sin_addr.s_addr=inet_addr(asi.TargetIP);
Target.sin_port=htons(asi.TargetPort);
//如果工作在u模式的话,监听一个TCP port等待客户连接
//创建一个TCP socket
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if(sListen==INVALID_SOCKET)
{
ShowError("/nCreate TCP socket");
return -1;
}
//监听本地TCP port的地址结构
TCPLocal.sin_family=AF_INET;
TCPLocal.sin_port=htons(asi.LocalPort);
TCPLocal.sin_addr.s_addr=htonl(INADDR_ANY);
//bind socket
iRet=bind(sListen,(SOCKADDR *)&TCPLocal,sizeof(TCPLocal));
if(iRet != 0)
{
ShowError("bind TCP port");
_DelSock(sListen);
return -2;
}
//listen socket
if(listen(sListen,1) == SOCKET_ERROR)
{
ShowError("listen");
_DelSock(sListen);
return -3;
}
sinudp.sin_family=Target.sin_family;
sinudp.sin_addr=Target.sin_addr;
sinudp.sin_port=Target.sin_port;
sinudpisfilled = TRUE;
printf("/nListen TCP 127.0.0.1:%d ok!",asi.LocalPort);
//开始循环
while(1)
{
printf("/n/n************OK!Tcp2Udp: start new**************/n/n");
struct sockaddr_in addr;
int iSize=sizeof(addr);
//阻塞到客户连接
printf("/nTcp2Udp:Wait connect to me......:)");
s[1]=accept(sListen,(struct sockaddr *)&addr,&iSize);
if(s[1]==INVALID_SOCKET)
{
ShowError("nTcp2Udp:accept");
Sleep(5000);
continue;
}
printf("/nTcp2Udp:Accept %s:%d connect to me.",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
//创建一个UDP socket
s[0]=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s[0]==INVALID_SOCKET)
{
ShowError("/nTcp2Udp:Create UDP socket");
_DelSock(s[1]);
Sleep(5000);
continue;
}
BOOL bindok = FALSE;
int LocalTmpPort = asi.LocalTmpPort;
if(LocalTmpPort<1) LocalTmpPort = 4000;
while(LocalTmpPort <65535)
{
//监听本地UDP port的地址结构
UDPLocal.sin_family=AF_INET;
UDPLocal.sin_addr.s_addr=INADDR_ANY;
UDPLocal.sin_port=htons(LocalTmpPort);
//bind UDP socket
iRet=bind(s[0],(struct sockaddr *)&UDPLocal,sizeof(UDPLocal));
if(iRet == SOCKET_ERROR)
{
printf("/nTcp2Udp:Bind UDP port %d failed.",LocalTmpPort);
LocalTmpPort ++ ;
Sleep(50);
continue;
}
else
{
printf("/nTcp2Udp:Bind UDP port %d ok.",LocalTmpPort);
bindok = TRUE;
break;
}
}
if(!bindok)
{
_DelSock(s[0]);
_DelSock(s[1]);
Sleep(5000);
continue;
}
DATAREDIRDPARAM* pdrp = new DATAREDIRDPARAM;
pdrp->sock[0] = s[0];
pdrp->sock[1] = s[1];
s[0] = 0;
s[1] = 0;
memcpy(&pdrp->sinudp ,&sinudp,sizeof(sockaddr_in));
pdrp->sinudpisfilled = sinudpisfilled;
DWORD threadid;
HANDLE hWaitThread = CreateThread(NULL,0,t2uwaitthread,(LPVOID)pdrp,NULL,&threadid);
CloseHandle(hWaitThread);
// WaitForSingleObject(psi->hWaitThread,INFINITE);
printf("/n/n**************OK!Tcp2Udp: do next******************/n/n");
}//end of while
if(sListen!=INVALID_SOCKET) closesocket(sListen);
return 0;
}
//t2u等待线程
DWORD WINAPI t2uwaitthread(LPVOID lpvoid)
{
DATAREDIRDPARAM* pdrp = (DATAREDIRDPARAM*)lpvoid;
_AddSock(pdrp->sock[0]);
_AddSock(pdrp->sock[1]);
HANDLE hThreads[2];
DWORD id[2];
hThreads[0] = CreateThread(NULL,0,tcp2udp,(LPVOID)pdrp,NULL,&id[0]);
_AddThread(hThreads[0]);
hThreads[1] = CreateThread(NULL,0,udp2tcp,(LPVOID)pdrp,NULL,&id[1]);
_AddThread(hThreads[1]);
DWORD waiter;
waiter = WaitForMultipleObjects(2,hThreads,FALSE,INFINITE);
if(waiter == WAIT_OBJECT_0)
{
_DelThread(hThreads[0]);
_DelSock(pdrp->sock[0]);
_DelSock(pdrp->sock[1]);
WaitForSingleObject(hThreads[1],2000);
_DelThread(hThreads[1]);
}else if(waiter == WAIT_OBJECT_0+1)
{
_DelThread(hThreads[1]);
_DelSock(pdrp->sock[1]);
_DelSock(pdrp->sock[0]);
WaitForSingleObject(hThreads[0],2000);
_DelThread(hThreads[0]);
}else
{
_DelSock(pdrp->sock[1]);
_DelSock(pdrp->sock[0]);
_DelThread(hThreads[1]);
_DelThread(hThreads[0]);
}
printf("/nTcp2Udp: Socket closed./n");
delete pdrp;
ExitThread(0);
return 0;
}
//tcp 2 udp 代码
//从sock[1]=>TCP socket读
//往sock[0]=>UDP socket写
DWORD tcp2udp(LPVOID lpvoid)
{
DATAREDIRDPARAM *tudp = (DATAREDIRDPARAM*)lpvoid;
SOCKET *s = tudp->sock;
DWORD threadid=GetCurrentThreadId();
printf("/n***New TCP2UDP %d recv %d sendto %d./n",threadid,s[1],s[0]);
char incomingbuff[maxsize];
int read = 1;
int iUDPRepeat=3;//UDP发送失败后重复的次数
while(read >0)
{
read = recv(s[1],incomingbuff, maxsize,0);
if(read <=0 ) break;
printf("/nTCP2UDP Thread %d recv %d bytes.",threadid,read);
iUDPRepeat = 3;
int npos=0;
while(npos < read)
{
int nsendcount=sendto(s[0],incomingbuff+npos,read-npos,0,(SOCKADDR *)&tudp->sinudp,sizeof(tudp->sinudp));
if(nsendcount == SOCKET_ERROR)
{
ShowError("sendto");
//重复发送次数自减一
if((iUDPRepeat--)>0)
{
printf("/nTry %d times to send.",iUDPRepeat);
continue;
}
}
if(nsendcount <= 0 ) return 0;
printf("/nTCP2UDP[%d] sendto %s:%d %d bytes.",threadid,inet_ntoa(tudp->sinudp.sin_addr),ntohs(tudp->sinudp.sin_port),nsendcount);
npos += nsendcount;
}
}
printf("/nTCP2UDP %d LastError %d",threadid,GetLastError());
return 0;
}
//udp 2 tcp 代码
//往sock[1],TCP socket写
//从sock[0],UDP socket读
//
DWORD udp2tcp(LPVOID lpvoid)
{
DATAREDIRDPARAM *tudp = (DATAREDIRDPARAM*)lpvoid;
SOCKET *s = tudp->sock;
DWORD threadid=GetCurrentThreadId();
printf("/n***New UDP2TCP %d recvfrom %d send %d./n",threadid,s[0],s[1]);
char incomingbuff[maxsize];
struct sockaddr_in from;
int dwSize=sizeof(from);
int read = 1;
while(read >0)
{
read=recvfrom(s[0],incomingbuff,maxsize,0,(SOCKADDR *)&from,&dwSize);
if(read <=0 ) break;
if(tudp->sinudpisfilled != TRUE)
{
tudp->sinudp.sin_family=AF_INET;
tudp->sinudp.sin_addr=from.sin_addr;
tudp->sinudp.sin_port=from.sin_port;
tudp->sinudpisfilled=TRUE;
}
printf("/nUDP2TCP[%d] recvfrom %s:%d %d bytes.",threadid,inet_ntoa(from.sin_addr),ntohs(from.sin_port),read);
int npos=0;
while(npos < read)
{
int nsendcount = send(s[1],incomingbuff+npos,read-npos,0);
if(nsendcount <= 0 ) return 0;
printf("/nUDP2TCP Thread %d send %d bytes.",threadid,nsendcount);
npos += nsendcount;
}
}
printf("/nUDP2TCP %d LastError %d",threadid,GetLastError());
return 0;
}