三、Linux和Windows以及QT下的网络编程的组播

 Windows系统下的组播发送

//==============send.h==================
#ifndef SEND_H_
#define SEND_H_

#include <string>
#include <WinSock.h>              //windows 网络的函数所在的头文件
using namespace std;
class Send
{
public:
	Send(void);
public:
	~Send(void);

public:                                              
	/* 对连接进行初始化  strIPAddress:广播的ip地址  strPort:    端口号*/ 
	bool InitSocket(const string strIPAddress,const string strPort);
	void CleanSocket();	//清理socket

	bool SendStringData(const string strMessage);	//发送字符串数据
	bool SendStructeData(const Person person);      //发送指定结构体数据(已Person为例)

private:
	void InitSockAddress(const string strIPAddress,const string strPort);
private:
	SOCKET m_socket;       //socket
	sockaddr_in m_sockLocalAddress; //本地sock地址
	sockaddr_in m_sockDesAddress;   //目的sock地址
};
#endif  //SEND_H_
//========Send.cpp================
#include <iostream>
#include "Send.h"
using namespace std;
Send::Send(void)
{
	m_socket = INVALID_SOCKET;
	WSAData ws; 

	//每个Winsock程序必须使用WSAStartup载入合适的Winsock动态链接库
	if (WSAStartup(MAKEWORD(1,1),&ws)!=0)
	{
		cout<<"WSAStartup failed! Error: "<<WSAGetLastError()<<endl;
	}
}

Send::~Send(void)
{
	WSACleanup();
}

bool Send::InitSocket(const string strIPAddress,const string strPort)
{	
	//创建套接字,ipv4,报文,udp协议
	m_socket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	//创建socket失败
	if (INVALID_SOCKET == m_socket)
	{
		cout<<"failed to create socket"<<endl;
		return false;
	}

	//初始化sock地址
	InitSockAddress(strIPAddress,strPort);

	// 绑定
	if (bind (m_socket, 
		(struct sockaddr FAR *) &m_sockLocalAddress, 
		sizeof (m_sockLocalAddress)) == SOCKET_ERROR) 
	{
		//报错		
		cout<<"Binding socket failed! Error: "<<WSAGetLastError()<<endl;
		closesocket (m_socket);	
		return false;
	}

	int iOptVal=64; //1秒
	// 设置组播存活时间
	if (setsockopt (m_socket,IPPROTO_IP,3,(char FAR *)&iOptVal,sizeof (int)) == SOCKET_ERROR)
	{
		//报错
		cout<<"setsockopt failed! Error:"<<WSAGetLastError()<<endl;
		closesocket (m_socket);
		return false;
	}
	return true;
}

void Send::CleanSocket()
{
	shutdown(m_socket,0x01);
	closesocket(m_socket);
}
bool Send::SendStringData(const string strMessage)
{
	if (sendto (m_socket, 
		(char *)&strMessage,
		sizeof(strMessage),
		0,
		(struct sockaddr FAR *) &m_sockDesAddress,
		sizeof (m_sockDesAddress)) == SOCKET_ERROR)
	{
		//报错
		cout<<"sendto failed! Error: %d"<<WSAGetLastError ()<<endl;
		closesocket (m_socket);
		return false;
	}
	else
		return true;
}


bool Send::SendStructeData(const Person person)
{

	if (sendto (m_socket,(char *)&person,sizeof(person),0,(struct sockaddr FAR *) &m_sockDesAddress,sizeof (m_sockDesAddress)) == SOCKET_ERROR)
	{
		//报错
		cout<<"sendto failed! Error: %d"<<WSAGetLastError ()<<endl;
		closesocket (m_socket);
		return false;
	}
	else
		return true;
}
void Send::InitSockAddress(const string strIPAddress,const string strPort)
{
	//本地sock地址设置
	m_sockLocalAddress.sin_family = AF_INET;     //ipv4地址类型
	m_sockLocalAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	m_sockLocalAddress.sin_port = htons(0);   
	memset(m_sockLocalAddress.sin_zero,0,8);

	//目的sock地址设置
	m_sockDesAddress.sin_family = AF_INET;	//IPv4版本
	m_sockDesAddress.sin_port = htons (atol(strPort.c_str()));  //端口
	m_sockDesAddress.sin_addr.s_addr = inet_addr (strIPAddress.c_str());	//地址

}

 Windows之组播接收

//==================receive.h===================
#ifndef	RECEIVE_H_
#define RECEIVE_H_

#include <string>
#include <WinSock.h>

using namespace std;
class Receive
{
public:
	Receive(void);
public:
	~Receive(void);

public:
	//初始化socket
	bool InitSocket(const string strIPAddress,const string strPort);

	//接受string数据
	bool ReceiveStringData(string& strMessage);

	//接受结构体数据
	bool ReceiveStructeData();

	//关闭socket
	void CloseSocket();

private:
	SOCKET m_socket; //socket;
	sockaddr_in m_sockLocalAddress;
	sockaddr_in m_sockReceiveAddress;
};

#endif  //RECEIVE_H_
//===================receive.cpp================
#include <iostream>
#include "Receive.h"

using namespace std;
Receive::Receive(void)
{
	m_socket =INVALID_SOCKET;

	//初始化winsock
	WSAData ws;

	if (WSAStartup(MAKEWORD(1,1),&ws))
	{
		cout<<"WSAStartup failed"<<WSAGetLastError()<<endl;
	}
}

Receive::~Receive(void)
{
	WSACleanup();
}

bool Receive::InitSocket(const string strIPAddress,const string strPort)
{
	
	struct ip_mreq mreq;  // 用于表示组播组地址的结构

	// 创建数据报类型的socket
	if ((m_socket = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) 
	{
		//报错
		cout<<"Allocating socket failed! Error:"<<WSAGetLastError()<<endl;

		return FALSE;
	}

	// 设定本地Socket地址信息
	m_sockLocalAddress.sin_family = AF_INET;//IPv4版本
	m_sockLocalAddress.sin_port = htons (atol(strPort.c_str()));  	//端口
	m_sockLocalAddress.sin_addr.s_addr = htonl (INADDR_ANY);	//地址

	// 绑定
	if (bind (m_socket, 
		(struct sockaddr FAR *) &m_sockLocalAddress, 
		sizeof (m_sockLocalAddress)) == SOCKET_ERROR) 
	{
		//报错
		cout<<"Binding socket failed! Error: "<<WSAGetLastError()<<endl;
		closesocket (m_socket);
		return FALSE;
	}

	//组播地址
	mreq.imr_multiaddr.s_addr = inet_addr (strIPAddress.c_str());
	//透明所有协议
	mreq.imr_interface.s_addr = INADDR_ANY;

	//设置套接字选项,加入一个多播组
	if (setsockopt (m_socket, 
		IPPROTO_IP, 
		IP_ADD_MEMBERSHIP, 
		(char FAR *)&mreq, 
		sizeof (mreq)) == SOCKET_ERROR)
	{
		//报错

		cout<<"setsockopt failed! Error: "<<WSAGetLastError()<<endl;
		closesocket (m_socket);
		return FALSE;
	}

	return true;


}


bool Receive::ReceiveStringData(string& strMessage)
{

	m_sockReceiveAddress.sin_family = AF_INET;

	int iRecvLen = sizeof(m_sockReceiveAddress);

	// 从组播组接收数据报
	if (recvfrom (m_socket, 
		//接收数据的缓冲区
		(char *)&strMessage,
		//缓冲区长度
		100, 
		//接收数据的方式
		0,          
		(struct sockaddr FAR *)&m_sockReceiveAddress,
		&iRecvLen) == SOCKET_ERROR)
	{
		//报错		
		cout<<"recvfrom failed! Error: "<<WSAGetLastError()<<endl;
		closesocket (m_socket);
		return FALSE;
	}
	else
	{	
		return true;
	}
}

void Receive::CloseSocket()
{
	// 禁用套接字
	shutdown (m_socket, 0x00);

	// 关闭套接字
	closesocket (m_socket);
}

Windows 下的 main.c 

#include <iostream>
#include "Send.h"
#include "Receive.h"

using namespace std;

int main()
{
	Send send;
    Receive receive;

	send.InitSocket("224.0.1.2","7838");  
	receive.InitSocket("224.0.1.2","7838");
    if(1){
	    while(1)
	    {

		    if (send.SendStringData("dddd"))
		    {
			    cout<<"send success"<<endl;
	    	}

	    }
	    send.CleanSocket();
    }else{
        while (1)
	    {
		    receive.ReceiveStringData(strMessage);
		    cout<<strMessage<<endl;	
	    }
	    receive.CloseSocket();
    }
}

QT之组播通信

/*(Multicast)在发送者和每一接收者之间实现点对多点网络连接。\
如果一台发送者同时给多个的接收者传输相同的数据,也只需复制一份的相同数据包。\
它提高了数据传送效率。减少了骨干网络出现拥塞的可能性。*/

udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::Any, 9999, QUdpSocket::ShareAddress);
udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2"));

//=========receive============
QHostAddress ip;
quint16 port;
udpSocket->readDatagram(buf,sizeof(buf),&ip,&port);

//=========receive============
QString str = "zzczzczzczzczzczzczzc!";
clientsocket->writeDatagram(str.toUtf8(),QHostAddress("224.0.0.2"),9999);

Linux之组播通信 服务端

//========================Linux 组播实现========================
//linux中对struct ip_mreqn 结构体的定义
struct ip_mreqn {
		struct in_addr	imr_multiaddr;			/* IP multicast address of group */
		struct in_addr	imr_address;			/* local IP address of interface */
		int 			imr_ifindex;			/* Interface index */
};

//----server.c------
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 8000
#define CLIENT_PORT 9000
#define MAXLINE 1500
#define GROUP "239.0.0.2"
//239.0.0.0~239.255.255.255
int main(void)
{
    int sockfd;
    struct sockaddr_in serveraddr, clientaddr;
    char buf[MAXLINE] = "multicast\n";
    struct ip_mreqn group;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);                /*构造用于UDP通信的套接字*/
    
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;                        /* IPv4 */
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);         /*本地任意IP INADDR_ANY = 0 */
    serveraddr.sin_port = htons(SERVER_PORT);

    bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    inet_pton(AF_INET, GROUP, &group.imr_multiaddr);        /*设置组播组的地址*/
    inet_pton(AF_INET, "0.0.0.0", &group.imr_address);      /* 本地任意IP 自动分配有效IP*/
    group.imr_ifindex = if_nametoindex("eth0");             /* 给出网卡名,转换为对应编号:eth0 --> 编号         ,,  命令:ip ad */

    setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group, sizeof(group));  /*获取组播权限*/

    bzero(&clientaddr, sizeof(clientaddr));                 /* 构造client 地址 IP+端口号*/
    clientaddr.sin_family = AF_INET;
    inet_pton(AF_INET, GROUP, &clientaddr.sin_addr.s_addr); /* IPv4  239.0.0.2+9000 */
    clientaddr.sin_port = htons(CLIENT_PORT);

    int i = 0;
    while (1) {
        sprintf(buf, "multicast %d\n", i++);
        //fgets(buf, sizeof(buf), stdin);
        sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&clientaddr, sizeof(clientaddr));
        sleep(1);
    }
    close(sockfd);
    return 0;
}

Linux之组播通信 客户端

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

#define SERVER_PORT 8000
#define CLIENT_PORT 9000
#define GROUP "239.0.0.2"

int main(int argc, char *argv[])
{
    struct sockaddr_in localaddr;
    int confd;
    ssize_t len;
    char buf[BUFSIZ];

    struct ip_mreqn group;                                                  /*组播结构体*/
    confd = socket(AF_INET, SOCK_DGRAM, 0);
    bzero(&localaddr, sizeof(localaddr));                                   /* 初始化*/
    localaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "0.0.0.0" , &localaddr.sin_addr.s_addr);
    localaddr.sin_port = htons(CLIENT_PORT);

    bind(confd, (struct sockaddr *)&localaddr, sizeof(localaddr));

    inet_pton(AF_INET, GROUP, &group.imr_multiaddr);                        /* 设置组播组地址*/
    inet_pton(AF_INET, "0.0.0.0", &group.imr_address);                      /*使用本地任意IP添加到组播组*/
    group.imr_ifindex = if_nametoindex("eth0");                             /* 设置网卡名 编号 ip ad */    
    setsockopt(confd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));/* 将client加入组播组*/
    while (1) {
        len = recvfrom(confd, buf, sizeof(buf), 0, NULL, 0);
        write(STDOUT_FILENO, buf, len);
    }
    close(confd);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值