UDP Multicast
-
I'm trying to connect to a system that communicates via a UDP Multicast protocol. I need to both send and receive. It appears that this capability may be added in release 4.8, but until then does anyone have a suggestion or any experience doing UDP Multicast with Qt?
Thanks in advance.
Bryan
-
Until Qt provides native, cross-platform multicast support, you will have to manage some platform specific code. For example, if you are targeting Windows, I extended the QUdpSocket class into my own MulticastSocket class. Then I provided the APIs to join and leave multicast groups. The implementation of the join and leave methods required calls using the Winsock2 setsockopt(...) C API. The Winsock2 C API are fully documented on the MSDN.com site.
under the MinGW installation you will need to include the Winsock2 header:
[Qt DIR]\mingw\include\winsock2.hYou will also need to link to the MinGW version of the Winsock2 library:
[Qt DIR]\mingw\lib\libws2_32.a -
Unfortunately, I can release the class files in their entirety. I will post some of the relevant code snipets here for the various operations. One of the key things I have found with the Winsodk2 implementation, you will need to bind the socket, before attempting any multicast configuration operations.
In the project file (*.pro) add these lines into it:
@CONFIG += networkthis is just where the library is located on my system
LIBS += C:\bin\dev\Qt\2010.05\mingw\lib\libws2_32.a
I copied these from the Qt SDK into my local project folder
HEADERS += winsock2.h ws2tcpip.h@
In the C++ implementation here is the code to join a multicast group, make sure you bind first.
@/**
@param aGroup Multicast group address object {IPv4 + port#}
@note This function contains WinSock2 specific code (Microsoft Windows) for
subscription to a multicast group, which is not supported natively by Qt.This function accepts a multicast group IP and port # for the group to which
this socket is to subscribe.
*/
void CMulticastSocket::JoinGroup(quint32 aIP, quint16 aPort)
{
int results = 0;// Bind this socket to the requested multicast address.
// - Use the platform default binding mode.
QUdpSocket::bind( aPort );//--< Winsock2 specific code >------------------------------------
SOCKET WinSocket = socketDescriptor();
SOCKADDR_IN localIF;
struct ip_mreq mreq;// query the system for the local network interface IP address.
hostent *pHost = gethostbyname(""); // gets the localhost data.if(0 == pHost)
{
error( QAbstractSocket::UnknownSocketError );
}
else if(AF_INET == pHost->h_addrtype)
{
// for simplicity, assume that the test systems only have one network
// interface, therefore select the first IPv4 address in the list and
// store in host byte order.
mLocalIP = ntohl( * reinterpret_cast<quint32*>( *pHost->h_addr_list ) );
}// bind to this socket to the provided port number.
localIF.sin_family = AF_INET;
localIF.sin_port = htons( aPort );
localIF.sin_addr.s_addr = htonl( INADDR_ANY );
results = ::bind( WinSocket, (SOCKADDR*)&localIF, sizeof(localIF) );
/---< NOTE >---------------------------------
Since QUdpSocket overloaded the a number of
bind() method implementations, the global scope
call {::bind(...)} was required to force the
compiler to use the Winsock2 bind function.
--------------------------------------------/
if(SOCKET_ERROR == results)
results = WSAGetLastError();// subscripe to the multicast group
mreq.imr_interface.s_addr = htonl( mLocalIP );
mreq.imr_multiaddr.s_addr = htonl( aIP );
results = setsockopt(WinSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq) );if(SOCKET_ERROR == results)
results = WSAGetLastError();
//--< Winsock2 specific code >------------------------------------
}@And here is the similar code snipet for leaving a multicast group:
@/**
If this socket is currently connected to a multicast group, it send a request
(IGMP) to leave the multicast group.
*/
void CMulticastSocket::LeaveGroup()
{
//--< Winsock2 specific code >------------------------------------
SOCKET socket = socketDescriptor();// leave the currently connected multicast group
if((IP_BROADCAST == mMcastIP) && (INVALID_SOCKET != socket))
{
int results = 0;
struct ip_mreq mreq;mreq.imr_interface.s_addr = htonl( mLocalIP ); mreq.imr_multiaddr.s_addr = htonl( mMcastIP ); results = setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mreq, sizeof(mreq) ); // catch and log the error, if any if(SOCKET_ERROR == results) { results = WSAGetLastError(); error( QAbstractSocket::UnknownSocketError ); }
}
//--< Winsock2 specific code >------------------------------------
}@ -
@roninttk - sorry to bother you, but I have a question...there are a few items that I'm not sure of.
IP_BROADCAST -- is this the multicast group IP or some constant?
These appear to be class variables, but I don't have the definition or know how to initialize:
mMcastIP
mLocalIPThanks.
-
Yes, you are correct the mMcastIP and mLocalIP are class data members that are "unsigned int" variables. They hold the local interface IP address and the multicast group IP address. The IP_BROADCAST is a constant for the UDP broadcast address 255.255.255.255.