PDA

View Full Version : MULTICAST with QT 4.1 and above.



jlarsj
17th August 2006, 15:32
Hi everyone,

I have a simple question : has someone actually managed to write a multicast packet receiver app using ONLY the Qt library 4.1 and above, in other words using pure Qt code ?

If this is the case I would be very interested to know how it works :)

Best regards,

Julien.

ball
18th August 2006, 04:08
I don't know what you mean by a 'multi-cast packet receiver' here. But if you want to make a server, use QTcpServer and a class member of QTcpSocket* list to maintain the client connection. Then you can do whatever you want to manage all client connections.

jlarsj
18th August 2006, 15:53
Hi,

well thanks for your answer. I might be not very clear due to my level of english.

Obviously you don't know what MULTICAST is, to make a long story short, MULTICAST is a network scheme using UDP so TCP might be quite unuseful here. With multicast you "broadcast" UDP packets through the network, but the difference with broadcasting is when you setup your client ( or your server ) you have to specify a class D IP address ( 224.0.0.0 -> 239.255.255.255 ). Using that address you specify if you want to joint the multicast group on a given port, and the filtering I do believe is done at the level of you NIC card that let go the UDP packet if you are not a member of the group, in other words less congestion on the network devices ( not on the network though ) than Broadcast.

Anyway the thing is I am developping a tiny MULTICAST CLIENT app and I wanted to know if someone has done it using piure QT code, no BSD lib ( Linux or Windows ). Using BSD lib its working fine, I just wanted to know if Qt libs handle Multicast scheme by itself or not.

But thanks for your answer, I have posted the same message on other groups : no answer...

wysota
18th August 2006, 18:01
Qt uses BSD sockets to do its job. You can even set a "pure" BSD socket (using QAbstractSocket::setSocketDescriptor), so you can create a bsd socket, set the options you need and make a Q*Socket out of it. I have never used multicasting but if it only needs setting a proper multicast address, then Qt should handle it out of the box.

jlarsj
18th August 2006, 20:44
Hi Wysota,

Well, I have been programming those small Multicast handlers both under Linux and Windows. Actually Winsock is based also on the BSD "Like" socket lib ( Not MFC, just Winsock ), and they use the same system calls.

Well I tried using QUdpSocket but it doesn't catch any Multicasted packet. Here a simple example of code provided by Trolltech:




QUdpSocket udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 24001);

while (udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;

udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);

processTheDatagram(datagram);
}




The problem here is pretty obvious : where do you join the multicast group ????

So I tried to put in the bind() function a QHostAddress containing the multicast address, but the bind function fails each time.

So, I don't know I do believe that Qt doesn't handle multicast by itself ?? Sad isn't it ;)

yuriy
22nd August 2006, 00:22
I had the same issue a while ago and used setsockopt to set multicast option. The code looks like this:

udpSendingSocket = new QUdpSocket;
if (!udpSendingSocket->bind(sendPort, QUdpSocket::ShareAddress))
std::cout <<"send bind failed\n";
sendingFd = udpSendingSocket->socketDescriptor();

if (sendingFd != -1)
{
/* set up destination address */
// struct sockaddr_in sendAddr;
memset(&sendAddr,0,sizeof(sendAddr));
sendAddr.sin_family=AF_INET;
sendAddr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
sendAddr.sin_port=htons(sendPort);

// set TTL
unsigned int ttl = 1; // restricted to the same subnet
if (setsockopt(sendingFd, IPPROTO_IP, IP_MULTICAST_TTL, (unsigned int*)&ttl, sizeof(ttl) ) < 0)
{
std::cout << "TTL failed\n";
}
}

Can Qt add a multicast option in QUdpSocket class?

tiva
9th January 2007, 12:37
Hello Friends,

I was also trying to build a UDP multicast based messaging tool and happen to stumble using the QUdpSocket class especially Multicasting. I tried class B type of addressing i.e., 192.168.100.255 and Qt responds positively. But I'am afraid it is similar to 255.255.255.255(broadcast address) within the same segment!

The famous 'psi' project forums posts about "JEP-33 (Extended Stanza Addressing)" for multicasting. But couldn't get much info about how to blend JEP-33 and Qt4.

When can we expect Qt to add UDP multicasting feature :D

regards
-gks

tiva
10th January 2007, 13:45
Somehow managed to do multicasting :p

Some info for my novice brothern!!
Unicasting is sending data to single host. Broadcasting is sending data to all hosts on the network. Multicasting lies in between these two. It is sending data to group of hosts. This group is identified by the multicast address.

Every host on the network has an IP Address. IP Address is divided into 5 classes. Each class contains specific range of IP addresses.

Class A >> 0.0.0.0 - 126.255.255.255
Class B >> 128.0.0.0 - 191.255.255.255
Class C >> 192.0.0.0 - 223.255.255.255
Class D >> 224.0.0.0 - 239.255.255.255
Class E >> 240.0.0.0 - 255.255.255.255

Class D address is called multicast address. Each group on the network has unique multicast address associated with it. In order to create the group you can choose any address in Class D. Its safer to use any address starting from 225.0.0.0 to 239.255.255.255.



include These files..

#ifdef Q_OS_WIN
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#ifdef Q_OS_UNIX
#endif



These members are required :-

#ifdef Q_OS_WIN
struct sockaddr_in TivaSinStruct;
int TivaSocketId;
ip_mreq TivaMreq;
#endif
#ifdef Q_OS_UNIX

#endif



//TivaUdpSocket is a QUdpSocket
//TivaPort is some valid port number..here i've used 3838
//Configuring the socket to receive Multicast Packet.


TivaUdpSocket.bind(TivaPort,QUdpSocket::ShareAddre ss);
int TivaSendingFd = TivaUdpSocket.socketDescriptor();

#ifdef Q_OS_WIN
if(TivaSendingFd != -1)
{

struct sockaddr_in TivaSendAddr;
memset(&TivaSendAddr,0,sizeof(TivaSendAddr));
TivaSendAddr.sin_family=AF_INET;
TivaSendAddr.sin_addr.s_addr=inet_addr("238.38.38.38"); //Chosen Broadcast address!!
TivaSendAddr.sin_port=htons(TivaPort);


ip_mreq mreq;
memset(&mreq,0,sizeof(ip_mreq));
mreq.imr_multiaddr.s_addr = inet_addr("238.38.38.38"); // group addr
mreq.imr_interface.s_addr = htons(INADDR_ANY); // use default

//Make this a member of the Multicast Group
if(setsockopt(TivaSendingFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char far *)&mreq,sizeof(mreq)) < 0)
{


QMessageBox::about(this,"Tiva","TivaNet Memship Error!");

}
// set TTL (Time To Live)
unsigned int ttl = 38; // restricted to 38 hops
if (setsockopt(TivaSendingFd, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&ttl, sizeof(ttl) ) < 0)
{

QMessageBox::about(this,"Tiva","TimeTo Live Error!");

}

}




//Set up a socket for sending multicast data


TivaSocketId = socket(AF_INET, SOCK_DGRAM, 0);

TivaSinStruct.sin_family = AF_INET;
TivaSinStruct.sin_port = htons(TivaPort);
TivaSinStruct.sin_addr.s_addr = inet_addr("238.38.38.38");
unsigned int ttl = 38; // 38 hops allowed
setsockopt(TivaSocketId, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&ttl, sizeof(ttl) );

memset(&TivaMreq,0,sizeof(ip_mreq));
TivaMreq.imr_multiaddr.s_addr = inet_addr("238.38.38.38"); // group addr
TivaMreq.imr_interface.s_addr = htons(INADDR_ANY); // use default

setsockopt(TivaSocketId, IPPROTO_IP, IP_ADD_MEMBERSHIP, \
(char far *)&TivaMreq,sizeof(TivaMreq));

#endif




//Sending multicast data
//OMsg is a QString


#ifdef Q_OS_WIN
sendto(TivaSocketId, OMsg.toAscii(), OMsg.toAscii().size(), 0, (struct sockaddr *)&TivaSinStruct, sizeof(TivaSinStruct));
#endif


Receiving multicast data


connect(&TivaUdpSocket, SIGNAL(readyRead()), this, SLOT(tiva_readTivaNetPacket()));



//tiva_readTivaNetPacket()



QString OInMessage;
QHostAddress PeerIp;
quint16 por=TivaPort;

while (TivaUdpSocket.hasPendingDatagrams())
{

QByteArray datagram;
datagram.resize(TivaUdpSocket.pendingDatagramSize( ));
TivaUdpSocket.readDatagram(datagram.data(), datagram.size(),&PeerIp,&por);
OInMessage=datagram.data();
TivaMessageAction(OInMessage,PeerIp);
}




Hope You find it useful :D