UDP通信实例(4) --组播模式下,利用SO_REUSEADDR实现两个套接字占用同一个端口

众所周知,一个IP提供65536个端口。假如某个端口被一个套接字占用,其他套接字就不能 再占用这个端口了。但是根据https://blog.csdn.net/fz835304205/article/details/16980163/ 的描述,在UDP组播模式下,利用SO_REUSEADDR可以实现两个不同的套接字使用同一个端口。以下是代码实例:

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include "thrdudp.h"
#include "udp2.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    thrdUDP1 udp1;
	thrdUDP2 udp2;
    udp1.start();
	udp2.start();
    w.show();



    return a.exec();
}

下面的类thrdUDP1和thrdUDP2使用的是同一个IP地址和端口号7004

thrdUDP1.h

#ifndef THRDUDP_H
#define THRDUDP_H

#include <stdio.h>
#include <WinSock2.h>
#include <ws2tcpip.h>
#include <QThread>

class thrdUDP1 : public QThread
{
    Q_OBJECT
public:
    explicit thrdUDP1(QObject *parent = 0);
    int         m_Socket;

    void        vSend(void);
protected:
    void        run();
};

#endif // THRDUDP_H

thrdUDP1.cpp

#include "thrdudp.h"
#include "mainwindow.h"

extern MainWindow * g_pMainWin;
thrdUDP1 * g_pUDP1 = NULL;
#pragma comment(lib, "Ws2_32.lib")
thrdUDP1::thrdUDP1(QObject *parent) : QThread(parent)
{
    g_pUDP1 = this;
}

void thrdUDP1::run()
{
        WSAData wsaData;
        int iRet = WSAStartup(MAKEWORD(2,2), &wsaData);

        bool m_bBind;
        struct sockaddr_in m_sinOwn;
        m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
        if(m_Socket >= 0)
        {
            int iOptVal = 1;
            setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&iOptVal, sizeof(iOptVal));
            memset(&m_sinOwn, 0, sizeof(m_sinOwn));
            m_sinOwn.sin_family = AF_INET;
            m_sinOwn.sin_addr.s_addr = inet_addr("192.168.8.8");
            m_sinOwn.sin_port = htons(7004);

            if(bind(m_Socket, (struct sockaddr *)&m_sinOwn, sizeof(struct sockaddr_in)) == 0)
            {
                m_bBind = true;
            }
            else
            {
                m_bBind = false;
            }
        }
        else
        {
            m_bBind = false;
        }

        if(m_bBind)
        {
            struct ip_mreq m_req;
            m_req.imr_multiaddr.s_addr = inet_addr("225.0.0.23");
            m_req.imr_interface.s_addr = htonl(INADDR_ANY);
            int err = setsockopt(m_Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&m_req, sizeof(m_req));
            if(0 == err)
            {
                printf("starting\n");
                while(true)
                {
                    char arrRet[20] = {0};
                    recv(m_Socket, arrRet, 20, 0);
                    g_pMainWin->vUpdateEdt1(arrRet);
                }
            }
        }

        if(m_Socket > 0)
            closesocket(m_Socket);
        WSACleanup();
}

void thrdUDP1::vSend(void)
{
    sockaddr_in s;
    s.sin_family = AF_INET;
    s.sin_port = htons(4001);
    s.sin_addr.S_un.S_addr = inet_addr("225.0.0.23");
    ::sendto(m_Socket, "456", 3, 0, (sockaddr *)&s, sizeof(s));
}

thrdUDP2.cpp

#include "udp2.h"
#include "mainwindow.h"

extern MainWindow * g_pMainWin;
thrdUDP2 * g_pUDP2 = NULL;
#pragma comment(lib, "Ws2_32.lib")
thrdUDP2::thrdUDP2(QObject *parent) : QThread(parent)
{
    g_pUDP2 = this;
}

void thrdUDP2::run()
{
    bool m_bBind;
	WSAData wsaData;
	int iRet = WSAStartup(MAKEWORD(2,2), &wsaData);

	struct sockaddr_in m_sinOwn;
    m_Socket = socket(AF_INET, SOCK_DGRAM, 0);
	if(m_Socket >= 0)
	{
		int iOptVal = 1;
		setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&iOptVal, sizeof(iOptVal));
		memset(&m_sinOwn, 0, sizeof(m_sinOwn));
		m_sinOwn.sin_family = AF_INET;
        m_sinOwn.sin_addr.s_addr = inet_addr("192.168.8.8");
        m_sinOwn.sin_port = htons(7004);

		if(bind(m_Socket, (struct sockaddr *)&m_sinOwn, sizeof(struct sockaddr_in)) == 0)
		{
			m_bBind = true;
		}
		else
		{
			m_bBind = false;
		}
	}
	else
	{
		m_bBind = false;
	}

	if(m_bBind)
	{
		struct ip_mreq m_req;
        m_req.imr_multiaddr.s_addr = inet_addr("225.0.0.23");
		m_req.imr_interface.s_addr = htonl(INADDR_ANY);
		int err = setsockopt(m_Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&m_req, sizeof(m_req));
		if(0 == err)
		{
			printf("starting\n");
			while(true)
			{
				char arrRet[20] = {0};
				recv(m_Socket, arrRet, 20, 0);
                g_pMainWin->vUpdateEdt2(arrRet);
			}
		}
	}

	if(m_Socket > 0)
		closesocket(m_Socket);
	WSACleanup();
}

void thrdUDP2::vSend(void)
{
    sockaddr_in s;
    s.sin_family = AF_INET;
    s.sin_port = htons(4001);
    s.sin_addr.S_un.S_addr = inet_addr("225.0.0.23");
    ::sendto(m_Socket, "123", 3, 0, (sockaddr *)&s, sizeof(s));
}

mainwindow.cpp

#include "thrdudp.h"
#include "udp2.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow * g_pMainWin = NULL;
extern  thrdUDP1 * g_pUDP1;
extern  thrdUDP2 * g_pUDP2;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    g_pMainWin = this;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::vUpdateEdt1(char * pData)
{
    ui->Edt1->setText(QString(pData));
}

void MainWindow::vUpdateEdt2(char * pData)
{
    ui->Edt2->setText(QString(pData));
}

void MainWindow::on_pushButton_clicked()
{
    g_pUDP1->vSend();
}

void MainWindow::on_pushButton_2_clicked()
{
    g_pUDP2->vSend();
}

效果:

从另一个计算机发送数据:

两个套接字都收到了数据:

同样,两个套接字也都可以向网络助手发送信息

发布了148 篇原创文章 · 获赞 46 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/liji_digital/article/details/90084034