多點傳播也是建立在UDP上面的,是以在寫多點傳播的時候,隻需要先寫出UDP,後面就好辦啦。UDP跟廣播相比,不會造成帶寬負擔,多點傳播是向一個虛拟組發送資料,在一個組裡面的成員才可以接收到資料。是一種很實用的網絡通訊方式。
首先需要一個虛拟組,一個D類IP,D類IP範圍為224~239,這裡的這個IP是虛拟的,不要傻傻的去ping它,ping不通。這裡就相當于一個給一個組取了個編号。往這個組裡發消息,加入這個組的成員才能接受。跟廣播一樣,也是一對多,但很明顯多點傳播比廣播多了一些限制性,不會像廣播一樣向所有位址發資料。
網絡程式設計也就這麼點,嚴格按照這些步驟。如果出錯了,無非就是IP弄錯了、端口錯了,多些耐心,多調試幾次。剛開始我也經常出錯,錯的越多,了解的就會越深。
先來一個mySocket.h頭檔案,把該包含的都保函進來
這裡包含了Windows下跟Linux下的頭檔案,需要添加一個宏,根據自己的目标機自行修改啦。
#pragma once
#include <stdio.h>
#include <iostream>
using namespace std;
#ifndef WINDOWS //預先定義宏WINDOWS,在Windows vs下項目右鍵,屬性裡面添加
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>//close()
#include<netinet/in.h>//struct sockaddr_in
#include<arpa/inet.h>//inet_ntoa
#else
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#endif
先寫一個Server服務端, 跟UDP一樣
1.初始化 //Windows下必要,Linux下沒有
2.socket傳回UDP句柄(也叫檔案描述符)
3.bind //監聽本機端口
4.加入多點傳播
5.收發資料
#include "mySocket.h"
#ifndef WINDOWS
int m_sock; //Linux下套接字類型
int broadcast = 1;
#else
SOCKET m_sock; //windows下套接字類型
bool broadcast = true;
#endif
int Init_Socket(const char *address, int port)
{
#ifdef WINDOWS //如果定義了WINDOWS
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData); //windows下必須要初始化,不然socket會失敗
#endif
if ((m_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket failed");
return -1;
}
sockaddr_in myServerAddr;
myServerAddr.sin_family = AF_INET;
myServerAddr.sin_port = htons(8234);
//myServerAddr.sin_addr.s_addr = inet_addr(address);
myServerAddr.sin_addr.s_addr = inet_addr(INADDR_ANY);
if (bind(m_sock, (sockaddr*)&myServerAddr, sizeof(myServerAddr)))
{
perror("bind failed");
return -1;
}
/**加入多點傳播**/
struct ip_mreq myMreq;
myMreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7"); //加入的組
myMreq.imr_interface.s_addr = inet_addr(INADDR_ANY); //把本機加入到這個組
if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&myMreq, sizeof(myMreq)) < 0)
{
perror("setsockopt failed");
return -1;
}
return 0;
}
void run()
{
char buf[1024] = {0};
sockaddr_in myServerAddr;
myServerAddr.sin_family = AF_INET;
myServerAddr.sin_port = htons(8234);
myServerAddr.sin_addr.s_addr = inet_addr("234.5.6.7");
#ifndef WINDOWS
socklen_t len = sizeof(myServerAddr);
#else
int len = sizeof(myServerAddr);
#endif
while (1)
{
memset(buf, 0, 1024);
if (recvfrom(m_sock, buf, sizeof(buf), 0, (sockaddr*)&myServerAddr, &len) < 0)
perror("recvfrom failed");
printf("buf=%s\n", buf);
}
}
int main()
{
if (Init_Socket("", 8234) == 0)
run();
getchar();
return 0;
}
先寫一個Client用戶端。這裡用戶端很簡單,建立UDP,然後向改組發送資料
1.初始化 //Windows下必要,Linux下沒有
2.socket傳回UDP句柄(也叫檔案描述符)
3.向指定組發送資料
#include "mySocket.h"
#ifndef WINDOWS
int m_sock; //Linux下套接字類型
#else
SOCKET m_sock; //windows下套接字類型
#endif
int Init_Socket(const char *address, int port)
{
#ifdef WINDOWS //如果定義了WINDOWS
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData); //windows下必須要初始化,不然socket會失敗
#endif
if ((m_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket failed");
return -1;
}
return 0;
}
void SendMsg(const char *Msg, int length)
{
struct sockaddr_in multicastAddr;
multicastAddr.sin_family = AF_INET;
multicastAddr.sin_port = htons(8234);
multicastAddr.sin_addr.s_addr = inet_addr("234.5.6.7"); //D類位址,虛拟的,向這個位址發送消息,組内的成員都會接收到資料
if (sendto(m_sock, Msg, length, 0, (sockaddr*)&multicastAddr, sizeof(multicastAddr)) < 0)
perror("sendto failed");
}
int main()
{
if (Init_Socket("", 8765) == 0)
SendMsg("abcd", 5);
return 0;
}