Qt5 实现简单TCP通信

         这段时间项目中用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。

一.导入工程

在工程的.pro文件中添加一句:

QT         += network

二.客户端

客户端的代码比服务器稍简单,总的来说,使用QT中的QTcpSocket类与服务器进行通信只需要以下5步:

1.创建QTcpSocket套接字对象:

QTcpSocket *pTcpClientSocket;
pTcpClientSocket= new QTcpSocket();

2.使用这个对象连接服务器:

pTcpClientSocket->connectToHost(IPaddr, Port);

3.使用write函数向服务器发送数据:

pTcpClientSocket->write(Data);

4.当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据:

connect(pTcpClientSocket, SIGNAL(readyRead()), this, SLOT(socket_Read_Data()));


void MainWindow::socket_Read_Data()
{
    QByteArray lBuffer;
    //读取缓冲区数据
    lBuffer = pTcpClientSocket->readAll();
}

或者用如下方式读取:

//在独立线程中
QString TestMessage;

while (1)
{

    if(pTcpClientSocket->waitForReadyRead(10))
    {
        //qApp->processEvents();
        TestMessage = pTcpClientSocket->readAll();
    }
}

        因为waitfor系列函数是通过readyRead()信号与bytesWritten()信号来实现的,如果产生这两个信号过快(就像上面的代码,死循环执行疯狂产生信号),会导致对应到槽函数的事件(信号到槽的执行是一种事件,我之前写过,这个事件将会到对应线程的消息队列中排队等待执行)一直在消息队列中疯狂阻塞,阻塞的结果就是消息队列不断膨胀,从而内存不断增加,直到队列到达上限导致程序崩溃。

问题解决方案

 知道原理后问题解决就很简单了,说穿了就是让线程去执行消息队列中的事件而不是一直产生,而Qt专门为这种情况制定了一个函数:qApp->processEvents(),这个函数的意思就是让调用此函数的线程执行其消息队列中的事件,直至没有事件可以执行为止。可见在死循环中加上这个函数之后,相关的内存泄露问题将迎刃而解,就像下面这样:

//在独立线程中
QString TestMessage;

while (1)
{

    if(pTcpClientSocket->waitForReadyRead(10))
    {
        qApp->processEvents();
        TestMessage = pTcpClientSocket->readAll();
    }
}

5.断开与服务器的连接(关于close()和disconnectFromHost()的区别,可以按F1看帮助)

pTcpClientSocket->disconnectFromHost();

三.服务器

        服务器除了使用到了QTcpSocket类,还需要用到QTcpSever类。即便如此,也只是比客户端复杂一点点,用到了6个步骤:

1.创建QTcpSever对象:

QTcpServer *pTcpServer;
pTcpServer = new QTcpServer();

2.侦听一个端口,使得客户端可以使用这个端口访问服务器:

pTcpServer->listen(QHostAddress::Any, Port);

3.当服务器被客户端访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接受客户端访问:

connect(pTcpServer,SIGNAL(newConnection()),this,SLOT(server_New_Connect()));
 
void MainWindow::server_New_Connect()
{
    //获取客户端连接
    QTcpSocket *pClientSocket;
    pClientSocket = pTcpServer->nextPendingConnection();
}

4.使用socket的write函数向客户端发送数据:

pClientSocket->write(Data);

5.当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据:

connect(pClientSocket , SIGNAL(readyRead()), this, SLOT(Server_Read_Data()));
 
void MainWindow::Server_Read_Data()
{
    QByteArray lBuffer;
    //读取缓冲区数据
    lBuffer = pClientSocket->readAll();
}

6.取消侦听:

pTcpServer->close();

四.总结

TCP

主要特点

1.TCP是面向连接的运输层协议。应用和曾许在使用TCP协议之前,必须首先建立TCP连接。在传输数据完毕之后,必须将已经建立好的TCP给释放。也就是说,应用进程之间的通信好像在“打电话”:通话之前首先要拨通号码建立连接,通话结束之后必须挂掉电话释放连接。

2.每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。

3.TCP提供的是可靠交付的服务。通过TCP连接传送的数据,无差错,不丢失,不重复,按照顺序到达。

4.TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能够发送数据。TCP连接的两端都设置了发送缓冲和接收缓冲区用来临时存放双向通信的数据。在发送时候,应用程序把数据传送给TCP的缓存之后,就可以去干自己的事情了,TCP会在合适的时候把数据发送出去。在接收的时候,TCP会把收到的数据放入缓存,上层应用进程在合适的时候会读取缓冲区的数据。

5.面向字节流。

TCP的连接

TCP把连接作为最基本的抽象。TCP的许多特性都和TCP是面向连接的这个基本特性有关。

前面已经讲过,每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢》

他叫做套接字(Socket),具体的定义为:端口拼接到IP地址即构成套接字。因此套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间使用冒号或者逗号隔开。例如,若IP地址是192.168.3.4 而端口号是50,那么得到的套接字就是(192.168.3.4:50)。

                                                        套接字Socket = IP地址:端口号   

每一条TCP连接唯一地被通讯两端的两个套接字所确定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工匠Sola

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值