我有一个使用 TCP 连接进行通信的服务器-客户端程序。多个客户端可以同时连接到服务器。我想在这个系统上实现tcp hole punching。
在客户端,它调用公共(public)服务器来查找我的服务器的公共(public) ip、端口。然后连接到它。
但是在服务器端它必须打开一个端口来连接到公共(public)服务器,并且它还必须在同一个端口上接受客户端连接请求。
我要做的是打开一个套接字并绑定(bind)到端口X,然后连接到公共(public)服务器,然后将这个套接字更改为监听状态以接受传入连接一段时间,然后开始连接到公共(public)服务器一次又一次。
这是正确的方法吗?
编辑:我有另一个想法。就是开一个新的端口,连接公用服务器。主服务器端口照常监听传入连接。当客户端要连接时,公共(public)服务器将通过新端口告诉我的服务器。它将阻止主端口监听传入连接,而是连接到客户端进行打洞。然后它连接到公共(public)服务器,它将服务器公共(public) ip 地址转发给客户端,并像往常一样返回监听传入连接。然后客户端将使用此地址连接到已打开 TCP 漏洞的服务器。
最佳答案
最好有两个套接字,并保持服务器和客户端之间的独立连接。
m_nServerTCPSocket- 用于与服务器连接和监听套接字
m_nPeerPrivateTCPSocket- 连接对端(公共(public)地址)
m_nPeerPublicTCPSocket- 与对等点连接(如果其他对等点在同一网络中,则为私有(private)地址)
- m_nListeningTCPSocket - 用于监听对端的套接字,您需要接受来自对端的连接。
m_nConnectedPeerTCPSocket-> 一旦与其他对等方连接,您就会获得此套接字。
while(end_client) { FD_ZERO(&fdRead); FD_ZERO(&fdWrite); FD_ZERO(&fdExcept); if (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket()>0) { FD_SET (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdRead); FD_SET (pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdExcept); } if (pControlMgr->GetConnectionMgr()->GetServerTCPSocket()>0) { FD_SET (pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),&fdRead); FD_SET (pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),&fdExcept); } if (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket()>0) { FD_SET (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),&fdRead); FD_SET (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),&fdExcept); } timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; nSelectRetVal = select(NULL,&fdRead,NULL,&fdExcept,&tv); if (nSelectRetVal>0) { int nRecvRetVal = 0; /* TCP Server Socket handling */ if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(), &fdRead )) { try { pRecvBuffer = new char[TCP_RECV_SIZE]; nRecvRetVal = recv(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(), pRecvBuffer,TCP_RECV_SIZE, 0); int n = WSAGetLastError(); if (nRecvRetVal>0) { int nPeerNameRetVal = getpeername(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(),(sockaddr*)&addrRemotePeer,&nSockAddrLen); if ( pControlMgr->HandlePacket(pRecvBuffer,addrRemotePeer)== -1 ) { if ( NULL != pRecvBuffer) { delete [] pRecvBuffer; pRecvBuffer = NULL; return 0 ; } } } } catch (...) { if ( NULL != pRecvBuffer ) { delete [] pRecvBuffer; pRecvBuffer = NULL; } } if ( NULL != pRecvBuffer) { delete [] pRecvBuffer; pRecvBuffer = NULL; } } /* TCP Server Socket handling */ int n; /* TCP Exception Server Socket handling */ if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetServerTCPSocket(), &fdExcept )) { /*FD_CLR(pControlMgr->GetConnectionMgr().GetServerTCPSocket (),&fdRead); FD_CLR(pControlMgr->GetConnectionMgr().GetServerTCPSocket (),&fdExcept);*/ n = WSAGetLastError(); //return 0; } if (FD_ISSET(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(),&fdRead)) { sockaddr_in addrConnectedPeer; int nAddrLen =sizeof(addrConnectedPeer) ; int nConnectedSock = accept( pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(), (sockaddr*)&addrConnectedPeer, &nAddrLen); int n1 = WSAGetLastError(); if (nConnectedSock>0) { pControlMgr->GetConnectionMgr()->SetConnectedTCPSocket(nConnectedSock); int n = pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(); continue; } } /* TCP Exception Listening Socket handling */ if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket(), &fdExcept )) { FD_CLR(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket (),&fdRead); FD_CLR(pControlMgr->GetConnectionMgr()->GetListeningTCPSocket (),&fdExcept); //return 0; } /* TCP Exception Listening Socket handling */ /* Connected Peer TCP Read Socket handling */ if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(), &fdRead )) { try { pRecvBuffer = new char[TCP_RECV_SIZE]; nRecvRetVal = recv (pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(), pRecvBuffer,TCP_RECV_SIZE, 0); if (nRecvRetVal>0) { int nPeerNameRetVal = getpeername(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(),(sockaddr*)&addrRemotePeer,&nSockAddrLen); if ( pControlMgr->HandlePacket(pRecvBuffer,addrRemotePeer)== -1 ) { if ( NULL != pRecvBuffer) { delete [] pRecvBuffer; pRecvBuffer = NULL; return 0 ; } } } } catch (...) { if ( NULL != pRecvBuffer ) { delete [] pRecvBuffer; pRecvBuffer = NULL; } } //FD_CLR(pControlMgr->GetConnectionMgr().GetConnectedTCPSocket(),&fdRead); if ( NULL != pRecvBuffer) { delete [] pRecvBuffer; pRecvBuffer = NULL; } } /* Peer TCP Read Socket handling */ /* TCP Exception Connected Socket handling */ if ( FD_ISSET(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket(), &fdExcept )) { /*FD_CLR(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket (),&fdRead); FD_CLR(pControlMgr->GetConnectionMgr()->GetConnectedTCPSocket (),&fdExcept); return 0;*/ n = WSAGetLastError(); }
创建套接字的逻辑
int CConnectionMgr::CreateSocket(const int nSockType)
{
//TODO: Add code here
if (InitWinSock() == -1)
{
return -1;
}
SetLocalIPAddress();
m_nListeningTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if ( GetListeningTCPSocket() <0 )
return -1;
if (BindSocket(GetListeningTCPSocket())<0)
return -1;
int nListenRet = listen(GetListeningTCPSocket(),SOMAXCONN);
if (nListenRet!=0)
{
return -1;
}
m_nPeerPrivateTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if (GetPeerPrivateTCPSocket()<0)
return -1;
if (BindSocket(GetPeerPrivateTCPSocket())<0)
return -1;
m_nPeerPublicTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if ( GetPeerPublicTCPSocket()<0)
return -1;
if (BindSocket(GetPeerPublicTCPSocket())<0)
return -1;
m_nServerTCPSocket = socket(AF_INET, SOCK_STREAM ,nSockType );
if (GetServerTCPSocket()<0)
return -1;
if (BindSocket(GetServerTCPSocket())<0)
return -1;
return 1;
}
关于networking - 如何控制peer上的socket[TCP Hole Punching],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13118144/