bala
bala

Reputation: 275

How to open the two udp client socket with same local port

How to open two client socket with the same local port like java. In Java we can mention the source port while creating DatagramPacket. I am trying to do UDP hole punching. Correct me if i done anything wrong.

I have added my code here.

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 , '\0' , 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 ( ) ;

}

In the same method I am trying to open the new socket with same port.

Check this Java Code I am trying to do like this in C/C++. It is not Possible ??

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();
}

}

Upvotes: 0

Views: 1530

Answers (2)

dbush
dbush

Reputation: 223699

It seems the Java code is not in fact opening two sockets on the same port, but closing the first socket then opening a new one on the same port as the one that was closed. For a UDP socket not in a connected state, that shouldn't be necessary at all.

If you're not changing the port, your C++ code should be able to continue to use the same socket instead of making a new one. Assuming you want to mirror what the Java code is doing, you shouldn't need to call connect. Just use sendto and recvfrom to send data back and forth.

Upvotes: 0

user207421
user207421

Reputation: 310860

Contrary to all the commentary, all you have to do is set the socket option SO_REUSEPORT prior to the bind().

Upvotes: 3

Related Questions