每个人都有不同的认知规律和习惯, 有的人喜欢搞一套严密的大理论, 论述起来滔滔不绝, 不管自己懂不懂, 反正读者/听者是没搞懂。 有的人喜欢从实践出发, 没看到代码, 不运行一下, 不看到结果, 就不太舒服。 我感觉, 我偏向后者, 必须有一个结果作用于我, 我才有感触。
比如初学C语言, 我也很不喜欢老师总在讲什么原码, 反码和补码, 讲什么 32767 + 1 为什么等于-32768, 讲什么m.nf%控制输出的具体含义. 我更喜欢搞个阶乘运行一下来玩玩, 搞个简单的界面问答系统感知一下, 搞个排序或者汉诺塔什么的玩玩。 等玩到一定程度, 再回去学那些略显枯燥的无聊知识。
好吧, 不扯了, 毕竟每个人的学习习惯不一样。
在本文中, 我就不大讲特讲组播了, 至于组播概念和原理, 度娘谷哥会告诉你, 请自学去, 其实也很简单。当然, 如果后续有必要涉及, 我也会介绍一下。 现在仅仅来实战一下组播。
(有必要说明一下, 下面两个程序必须运行在相同的机器上才有效)
发送程序为:
-
#include <stdio.h>
-
#include <winsock2.h>
-
#include <ws2tcpip.h>
-
#pragma comment(lib, "ws2_32.lib")
-
int main()
-
{
-
WSADATA wsaData;
-
WSAStartup(MAKEWORD(2, 2), &wsaData);
-
SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
-
int n = 0; // 注意, 这个n值很重要, 下面我会讲到
-
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&n, sizeof(n));
-
sockaddr_in addr;
-
addr.sin_addr.S_un.S_addr = inet_addr("234.2.2.2");
-
addr.sin_family = AF_INET;
-
addr.sin_port = htons(8888);
-
static int i = 0;
-
while(1)
-
{
-
char buf[100] = {0};
-
sprintf(buf, "blablablabla:%d", i++);
-
sendto(sock, buf, strlen(buf) + 1, 0, (sockaddr*)&addr, sizeof(sockaddr));
-
Sleep(500);
-
}
-
closesocket(sock);
-
WSACleanup();
-
return 0;
-
}
运行它。
加入组播的接收程序为:
-
#include <stdio.h>
-
#include <winsock2.h>
-
#include <ws2tcpip.h>
-
#pragma comment(lib, "ws2_32.lib")
-
int main()
-
{
-
WSADATA wsaData;
-
WSAStartup(MAKEWORD(2, 2), &wsaData);
-
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
-
sockaddr_in addr;
-
addr.sin_family = AF_INET;
-
addr.sin_addr.S_un.S_addr = INADDR_ANY;
-
addr.sin_port = htons(8888);
-
bind(sock, (sockaddr*)&addr, sizeof(addr));
-
// 加入组播啦
-
ip_mreq multiCast;
-
multiCast.imr_interface.S_un.S_addr = INADDR_ANY;
-
multiCast.imr_multiaddr.S_un.S_addr = inet_addr("234.2.2.2");
-
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multiCast, sizeof(multiCast));
-
int len = sizeof(sockaddr);
-
while(true)
-
{
-
char buf[100] = {0};
-
recvfrom(sock, buf, sizeof(buf) - 1, 0, (sockaddr*)&addr, &len);
-
printf("%s\n",buf);
-
}
-
closesocket(sock);
-
WSACleanup();
-
return 0;
-
}
运行它。
结果如下(两个进程通信了):
上面我们说过, 如上两个程序必须运行在同一电脑上才有效, 那要运行在不同的电脑上, 该怎么办呢? 我们注意到, 在发送程序中有int n = 0; 这个n为零表示发送端和接收端必须位于同一机器上, 如果n为1, 那么发送端和接收端就可以位于不同机器上了, 只需要他们位于同一个子网内即可。 实战过程如下: 假设pc0, pc1, pc2, pc3...在同一个子网内,将发送端的n改为 1且, 运行在pc0上, 然后在pc1, pc2, pc3...上运行接收端, 可以发现, pc1, pc2, pc3都接收到了组播消息, 与我们预期的结果吻合。
主题
局域网内的两台机器如果隔有路由器,那么这两台机器之间不能进行广播通信,但是我们可以换成组播的通信的方式,达到相互通信的效果。
一 服务器端
QUdpSocket udp_socket; udp_socket.bind(QHostAddress::Any, udp_listen_port, QUdpSocket::ReuseAddressHint); QHostAddress mcast_addr("224.0.0.17"); udp_socket.setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0);//禁止本机接收 udp_socket.joinMulticastGroup(mcast_addr);//这句是关键,加入组播地址
至此,我们已经完成了服务器的绑定并加入了组播组的工作。
二 客户端
QHostAddress mcast_addr("224.0.0.17");//组播地址与服务器相同 QUdpSocket udp_socket; udp_socket.writeDatagram(datagram, mcast_addr, UDP_SEND_PORT);//向服务器发送数据(UDP_SEND_PORT与服务器的监听端口相同)