TCP to UDP 数据转发 .

目的
    提供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;
}

你可能感兴趣的:(TCP to UDP 数据转发 .)