天天看點

跨平台UDP多點傳播(多點傳播)程式設計

    多點傳播也是建立在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;
}
           

繼續閱讀