0

I have a problem with a c++ socket.
I'm using CAsyncSocket from MFC that i want to join a multicast group.
Also I need to have multiple listener on this group and here is where i get in trouble.
I found some examples on the web but it doesn't seems to work.
Here is my code:

//create socket on port 17233   
BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);

//set reuse socket option  
BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

//join multicast group
ip_mreq m_mrMReq;           // Contains IP and interface of the host group
m_mrMReq.imr_multiaddr.s_addr = inet_addr((LPCSTR)"224.30.0.1");    /* group addr */ 
m_mrMReq.imr_interface.s_addr = htons(INADDR_ANY);      /* use default */

int uRes =setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq));

There are no errors when i run this.
But when i try to run another instance of the app it fails to create a new socket on that port because the port is in use.

I have done this in C# and it worked fine like this:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
s.Bind(ipep);
IPAddress ip = IPAddress.Parse(mcastGroup);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, IPAddress.Any));
s.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastTimeToLive, int.Parse("1"));

So if any body sees a problem with my code or have some tips i will gladly appreciated.

EDIT 1:
Is CAsyncSocket a TCP socket?

EDIT 2: After reading Can two applications listen to the same port?
I think i made a confusion. I need a Multicast UDP port that can be access by multiple application using SO_REUSEADDR

Edit for Clarification:

BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ)

Creates an UDP socket and bind's to to port 17223.
For SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET); to work you need to set it before binding as @Hasturkun said.
The final working code looks like this:

    BOOL bRet = Socket(SOCK_DGRAM, FD_READ);
    if(bRet != TRUE)
    {
        UINT uErr = GetLastError();
        std::cout<<"Error:"<<uErr<<std::endl;
        return FALSE;
    }else{
        std::cout<<"Create sock: OK"<<std::endl;
    }

    //add reuse
    BOOL bMultipleApps = TRUE;      /* allow reuse of local port if needed */
    SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

    //bind
    bRet = Bind(17233, NULL);
    if(bRet != TRUE)
    {
        UINT uErr = GetLastError();
        std::cout<<"Error(BIND):"<<uErr<<std::endl;
    }else{
        std::cout<<"BIND sock: OK"<<std::endl;
    }

Thanks,
Gabriel

;

Community
  • 1
  • 1
Gabriel
  • 1,435
  • 3
  • 17
  • 24
  • I guess you should close this question and open another one, since the subject has changed. – Rafael Colucci Apr 12 '11 at 12:58
  • The question was "how can i open multiple sockets on the same port using SO_REUSEADDR" and the answer is (thanks to Hasturkun) by binding the socket after the socket option is set. – Gabriel Apr 12 '11 at 16:43

3 Answers3

2

You should be able to separate the creation of the socket from the binding, create the socket using Socket, eg.

BOOL bRet = Socket(SOCK_DGRAM, FD_READ);

Then bind it with Bind after setting the sockopt

BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);

bRet = Bind(17233, NULL);
Hasturkun
  • 35,395
  • 6
  • 71
  • 104
  • that is exactly what I was looking for... except there is a problem .. when I call bRet = Bind(17233, NULL); it returns FLASE with error 10022(invalid parameter) – Gabriel Apr 12 '11 at 14:06
  • @Gabriel: I've updated my answer, you need to create the socket using Socket. I expected Create(0..) to not bind from some reason. – Hasturkun Apr 12 '11 at 14:10
1

This happens, i guess, because you are binding a client socket to a specific port and address. Maybe on its constructor:

BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);

You should not binding a client socket to an address. Let windows manage this for you. You should have a option to not create the socket passing a specific port, or if you do not, you should create the socket using another port.

Also, the BOOL bMultipleApps = TRUE; option does not work the way you think it does. It sets a linger option in the socket, but once created and listening, the socket (i mean the socket port) cannot be used in other applications no mather what you do.

Check this out: so-linger-and-closing-socketswinsock

EDIT:

I also dont know that the value of port in your c# code:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);

Are you sure that port does not get a different value every time you run the app?

As I said, try to create the socket in a different port to see what happens. Google for so_linger to know what it means.

EDIT 2:

Take a look at: Can two application listen to the same port?

EDIT 3:

Maybe your c# code:

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);

is binding the address to a different NIC. Do you have 2 nics at the same computer? If you do, you can bind the same port in both of them.

EDIT 4:

Example of using UDP sockets: Sending & Receiving UDP Datagrams with MFC's CAsyncSocket

Community
  • 1
  • 1
Rafael Colucci
  • 6,018
  • 4
  • 52
  • 121
  • if I dont call Create(bind the socket) i cant call SetSockOpt – Gabriel Apr 12 '11 at 12:28
  • I did not say you should no create. I just said that you are trying to use the same port in 2 applications. Thats not possible. – Rafael Colucci Apr 12 '11 at 12:30
  • So c# s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); is different from SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET); ? – Gabriel Apr 12 '11 at 12:32
  • I dont think so, but i am not 100% sure because I am not a c# programmer. Give it a try: change the socket port when you run the second app to see what happens. – Rafael Colucci Apr 12 '11 at 12:34
  • if i change the socket port it works. my problem is i can run to listeners on the same port – Gabriel Apr 12 '11 at 12:37
  • IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port); port=17233 I am sure that is the same port , i can open as many instances of app(listener) that i want and then when i send something with the sender all off those instances receive the data – Gabriel Apr 12 '11 at 12:41
  • No you cant. You cant have 2 sockets opened at the same port. Ports once used are reserved and theres nothing you can do to have 2 apps running at the same port. If it is a client socket, you should change the port, but if it is a socket server you better re-think your code. – Rafael Colucci Apr 12 '11 at 12:41
  • Hmm CAsyncSocket is a TCP socket? i need a udp multicast – Gabriel Apr 12 '11 at 12:48
  • It probably is, but i am not sure. I will google that and get back to you. – Rafael Colucci Apr 12 '11 at 12:50
  • Ok, found it. It can create UDP multicast but its not the wayt you are doing. check this out: http://simplesamples.info/MFC/UDPSendReceive.php or http://www.codeproject.com/KB/cpp/UDP_with_CAsyncSocket.aspx – Rafael Colucci Apr 12 '11 at 12:53
  • Edit 4 is from where i started... it doesn't work with SO_REUSEADDR – Gabriel Apr 12 '11 at 12:59
  • It it fully possible to use the same port for UDP. I.e. have multiple applications binding to the same port. However, one must create things for reuse or this will not work. – murrekatt Apr 12 '11 at 13:37
  • It is possible for UDP, but not for TCP which is what he is using. – Rafael Colucci Apr 12 '11 at 13:45
  • I'm not using TCP. BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ); creates an UDP socket – Gabriel Apr 12 '11 at 14:37
1

If boost is an option for you, consider using Asio for this. It is very straight-forward and this example shows a simple multicast receiver.

The important part for multiple listeners is:

socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));

If you're unclear what your application is doing, just run netstat and you'll see e.g. the sockets and how they are bound (IP, port and protocol):

netstat -an

...and look for the port you're interested in. If you run multiple applications listening to the same port you should see multiple entries for the same port with UDP as protocol.

murrekatt
  • 5,961
  • 5
  • 39
  • 63