UDP通信实例(1)--不使用bind函数

前几天处理一个关于UDP的项目,同一个程序里要使用两个UDP通信的套接字。我原计划分别使用2个QT的QUDPSocket类,结果发现使用两个QUDPSocket,造成其中一个QUDPSocket不能正常通信。所以只好用C++原生 的网络通信函数结合QThread完成UDP通信。从这件事之后,我意识到网络通信最好的选择是采用原生C++函数。从这篇博客开始,我将针对UDP通信给出编程实例,供大家参考。

本篇的例子介绍在linux平台下,不使用bind函数,实现UDP通信。提到udp和tcp通信,我以前首先想到的是如下三步:

1 建立套接字

2 绑定IP和端口

3 假如是TCP客户端,还要connect

事实上,对于UDP来说,第二步也可以省略。对于TCP客户端而言,第二步也是不必要的(后面的博客还会给具体例子)。

事实上,即使不调用bind,套接字也会拥有一个端口,只是这个端口不是由程序员指定的。既然拥有端口,这个套接字也就可以收发数据。下面的代码展示如何在不使用bind的情况下,与命令行的nc程序通信。nc占用的端口号是8080

UDP类的头文件"udpanonymous.h"

#ifndef UDPANONYMOUS_H
#define UDPANONYMOUS_H

#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

class udpAnonymous
{
public:
    udpAnonymous();
    ~udpAnonymous();

    static udpAnonymous *   pGetInstance(void);
    int                     m_skt;
    struct sockaddr_in      m_sinDst;//destination to receive msg
    bool                    bInit(char * pAddrIP, int iPort);
    bool                    bSend(char *, int);
};

#endif // UDPANONYMOUS_H

 UDP的cpp文件:

#include "udpanonymous.h"

/*ref: https://lobert.iteye.com/blog/1769618*/
udpAnonymous * g_pUdpAnynms = NULL;
udpAnonymous::udpAnonymous()
{
    /* socket returns -1 if failed. see "man socket"*/
    m_skt = socket(PF_INET,SOCK_DGRAM,0);
    g_pUdpAnynms = this;
}

bool udpAnonymous::bInit(char * pAddrIP, int iPort)
{
    memset(&m_sinDst,0,sizeof(struct sockaddr_in));

    /*****************************************************
     *  nt inet_pton(int af, const char *src, void *dst);
        这个函数转换字符串到网络地址,第一个参数af是地址簇,
        第二个参数*src是来源地址,第三个参数* dst接收转换后的数据
        若成功则为1,若输入不是有效的表达格式则为0,若出错则为-1
        http://www.cnblogs.com/loanhicks/p/7368151.html
        **************************************************/
    if(inet_pton(AF_INET,pAddrIP,&(m_sinDst.sin_addr))==1)
    {
        m_sinDst.sin_family = AF_INET;
        m_sinDst.sin_port = htons(iPort);
        return true;
    }
    else
    {
        return false;
    }
}

udpAnonymous::~udpAnonymous()
{
    close(m_skt);
}

bool udpAnonymous::bSend(char * pData, int iLen)
{
    /*********************************
     * https://lobert.iteye.com/blog/1769618
     * int sendto ( int s , const void * msg, int len, unsigned int flags, const
        struct sockaddr * to , int tolen ) ;
        sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,
        如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据内容,参数flags 一般设0,
        详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。
        参数tolen为sockaddr的结果长度。
        成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。*/
    if(-1 != m_skt)
    {
        int iRet = sendto(m_skt,(void *)pData, iLen, 0,
               (struct sockaddr *)&m_sinDst,sizeof(struct sockaddr_in));
        if(-1 == iRet)
            return false;
        else
            return true;
    }
    else
    {
        return false;
    }
}

udpAnonymous * udpAnonymous::pGetInstance(void)
{
    return g_pUdpAnynms;
}

 mainwindow的cpp文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "udpanonymous.h"

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

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

void MainWindow::on_pushButton_clicked()
{
    udpAnonymous * pUDP = udpAnonymous::pGetInstance();
    if(pUDP)
    {
        QString qstrIP=ui->edtIP->text();
        QString qstrPort = ui->edtPort->text();
        int iPort = qstrPort.toInt();
        bool b = pUDP->bInit(qstrIP.toLatin1().data(), iPort);
        if(b)
        {
            QString qstrMsg = ui->edtMsg->text();
            pUDP->bSend(qstrMsg.toLatin1().data(), qstrMsg.size());
        }
    }
}

 通信效果:

以上代码可在我的资源里下载。上面介绍的是从一个没有bind语句的UDP处向一个已知端口发送数据。下面讨论一下这个已知端口是否能反过来向对方,也就是向着没有bind的UDP处发数据。

假如不使用bind,则程序员不能指定其端口号。既然端口号未知,似乎没有bind的UDP是不能接收数据的。但是,利用recvfrom函数是可以查出发送方的IP和端口号的。也就是说,接收方一旦收到了数据,也就知道了发送方的地址和端口,也就可以向这个“端口不明”的UDP处发送消息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>