如何打开具有相同本地端口的两个 udp 客户端套接字
How to open the two udp client socket with same local port
如何打开两个具有相同本地端口的客户端套接字,如 java。
在 Java 中,我们可以在创建 DatagramPacket 时提及源端口。
我正在尝试进行 UDP 打孔。如果我做错了什么,请纠正我。
我在这里添加了我的代码。
void UDPClientConnect ( string IP , string Port )
{
WSADATA wsa;
if ( WSAStartup(MAKEWORD(2,2),&wsa) != 0 )
{
printf ( "startup failed %d\n" , WSAGetLastError() ) ;
return ;
}
int reuse = 1 ;
SOCKET s = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,(char*) &reuse, sizeof(int));
struct sockaddr_in si_other;
int slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
int p = atoi ( Port.c_str() ) ;
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(p);
si_other.sin_addr.S_un.S_addr = inet_addr( IP.c_str() );
strcpy_s ( message , "Hello" ) ;
//send the message
if ( sendto ( s , message , strlen(message) , 0 , (struct sockaddr *) &si_other , slen ) == SOCKET_ERROR)
{
printf ( "sendto() failed with error code : %d" , WSAGetLastError() ) ;
return ;
}
//receive a reply and print it
memset ( buf , '[=10=]' , BUFLEN ) ;
//try to receive some data, this is a blocking call
if ( recvfrom ( s , buf , BUFLEN , 0 , (struct sockaddr *) &si_other , &slen ) == SOCKET_ERROR )
{
printf("recvfrom() failed with error code : %d" , WSAGetLastError());
return ;
}
struct sockaddr_in localAddress;
int addrlen = sizeof(localAddress) ;
getsockname ( s , (struct sockaddr*)&localAddress , &addrlen ) ;
USHORT LocalPort = localAddress.sin_port ;
IN_ADDR localAddr = localAddress.sin_addr ;
printf("local address: %s\n", inet_ntoa( localAddress.sin_addr));
printf("local port: %d\n", (int) ntohs(localAddress.sin_port));
printf ( "\n******************************************\n\n" ) ;
int pos = 1 ;
CStringA CBuff = CStringA ( buf ) ;
string RemortPort = CBuff.Tokenize ( "-" , pos ) ;
string RemortIp = CBuff.Tokenize ( "-" , pos ) ;
reuse = 1 ;
SOCKET Sock_Reuse = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
setsockopt( Sock_Reuse , SOL_SOCKET, SO_REUSEADDR,(char*) &reuse, sizeof(int)); // optional, but recommended
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_port=htons(LocalPort);
sin.sin_addr.s_addr=INADDR_ANY;
if ( SOCKET_ERROR == connect(Sock_Reuse,(struct sockaddr *)&sin,sizeof(struct sockaddr_in)))
{
printf ( "bind failed %d" , WSAGetLastError() ) ;
}
closesocket ( Sock_Reuse ) ;
closesocket ( s ) ;
WSACleanup ( ) ;
}
我试图用相同的方法打开具有相同端口的新套接字。
检查此 Java 代码 我正尝试在 C/C++ 中这样做。这不可能??
import java.io.* ;
import java.net.* ;
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("172.24.8.110"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
}
与所有评论相反,您所要做的就是在 bind()
.
之前设置套接字选项 SO_REUSEPORT
看来 Java 代码实际上并不是在同一端口上打开两个套接字,而是关闭第一个套接字,然后在与关闭的端口相同的端口上打开一个新套接字。对于未处于连接状态的 UDP 套接字,根本不需要这样做。
如果您不更改端口,您的 C++ 代码应该能够继续使用相同的套接字,而不是创建一个新套接字。假设您想要镜像 Java 代码正在做什么,您不需要调用 connect
。只需使用 sendto
和 recvfrom
来回发送数据。
如何打开两个具有相同本地端口的客户端套接字,如 java。 在 Java 中,我们可以在创建 DatagramPacket 时提及源端口。 我正在尝试进行 UDP 打孔。如果我做错了什么,请纠正我。
我在这里添加了我的代码。
void UDPClientConnect ( string IP , string Port )
{
WSADATA wsa;
if ( WSAStartup(MAKEWORD(2,2),&wsa) != 0 )
{
printf ( "startup failed %d\n" , WSAGetLastError() ) ;
return ;
}
int reuse = 1 ;
SOCKET s = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,(char*) &reuse, sizeof(int));
struct sockaddr_in si_other;
int slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];
int p = atoi ( Port.c_str() ) ;
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(p);
si_other.sin_addr.S_un.S_addr = inet_addr( IP.c_str() );
strcpy_s ( message , "Hello" ) ;
//send the message
if ( sendto ( s , message , strlen(message) , 0 , (struct sockaddr *) &si_other , slen ) == SOCKET_ERROR)
{
printf ( "sendto() failed with error code : %d" , WSAGetLastError() ) ;
return ;
}
//receive a reply and print it
memset ( buf , '[=10=]' , BUFLEN ) ;
//try to receive some data, this is a blocking call
if ( recvfrom ( s , buf , BUFLEN , 0 , (struct sockaddr *) &si_other , &slen ) == SOCKET_ERROR )
{
printf("recvfrom() failed with error code : %d" , WSAGetLastError());
return ;
}
struct sockaddr_in localAddress;
int addrlen = sizeof(localAddress) ;
getsockname ( s , (struct sockaddr*)&localAddress , &addrlen ) ;
USHORT LocalPort = localAddress.sin_port ;
IN_ADDR localAddr = localAddress.sin_addr ;
printf("local address: %s\n", inet_ntoa( localAddress.sin_addr));
printf("local port: %d\n", (int) ntohs(localAddress.sin_port));
printf ( "\n******************************************\n\n" ) ;
int pos = 1 ;
CStringA CBuff = CStringA ( buf ) ;
string RemortPort = CBuff.Tokenize ( "-" , pos ) ;
string RemortIp = CBuff.Tokenize ( "-" , pos ) ;
reuse = 1 ;
SOCKET Sock_Reuse = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
setsockopt( Sock_Reuse , SOL_SOCKET, SO_REUSEADDR,(char*) &reuse, sizeof(int)); // optional, but recommended
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_port=htons(LocalPort);
sin.sin_addr.s_addr=INADDR_ANY;
if ( SOCKET_ERROR == connect(Sock_Reuse,(struct sockaddr *)&sin,sizeof(struct sockaddr_in)))
{
printf ( "bind failed %d" , WSAGetLastError() ) ;
}
closesocket ( Sock_Reuse ) ;
closesocket ( s ) ;
WSACleanup ( ) ;
}
我试图用相同的方法打开具有相同端口的新套接字。
检查此 Java 代码 我正尝试在 C/C++ 中这样做。这不可能??
import java.io.* ;
import java.net.* ;
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("172.24.8.110"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
}
与所有评论相反,您所要做的就是在 bind()
.
SO_REUSEPORT
看来 Java 代码实际上并不是在同一端口上打开两个套接字,而是关闭第一个套接字,然后在与关闭的端口相同的端口上打开一个新套接字。对于未处于连接状态的 UDP 套接字,根本不需要这样做。
如果您不更改端口,您的 C++ 代码应该能够继续使用相同的套接字,而不是创建一个新套接字。假设您想要镜像 Java 代码正在做什么,您不需要调用 connect
。只需使用 sendto
和 recvfrom
来回发送数据。