您的位置:首页 > 理论基础 > 计算机网络

Qt5网络与通信

2015-11-19 21:45 477 查看
在应用程序开发中网络编程非常重要,目前互联网通信的TCP/IP协议,自上而下分为应用层、传输层、网际层和网络接口层这四层。实际编写网络应用程序时只使用到

传输层和应用层,所涉及的协议主要包括UDP、TCP、FTP和HTTP等。

10.1获取本机网络信息

在网络应用中,进场需要获得本机的主机名、IP地址和硬件地址等网络信息。运用QHostInfo、QNetworkInterface、QNetworkAddressEntry可获得本机的网络信息。

运行效果如下:





networkinformation.h

#ifndef NETWORKINFORMATION_H

#define NETWORKINFORMATION_H


#include <QWidget>

#include <QLabel>

#include <QLineEdit>

#include <QPushButton>

#include <QGridLayout>

#include <QMessageBox>


class NetworkInformation : public QWidget

{

Q_OBJECT


public:

NetworkInformation(QWidget*parent = 0);

~NetworkInformation();

void getHostInformation();

public slots:

void slotHostDetailInformation();

private:

QLabel*hostLabel;

QLineEdit*hostNameLineEdit;

QLabel*ipLabel;

QLineEdit*ipLineEdit;

QPushButton*detailBtn;

QGridLayout*mainLayout;

};


#endif // NETWORKINFORMATION_H


networkinformation.cpp

#include "networkinformation.h"

#include <QHostInfo>

#include <QNetworkInterface>


NetworkInformation::NetworkInformation(QWidget*parent)

: QWidget(parent)

{

hostLabel = new QLabel(tr("主机名:"));

hostNameLineEdit = new QLineEdit;

ipLabel = new QLabel(tr("IP 地址:"));

ipLineEdit = new QLineEdit;

detailBtn = new QPushButton(tr("详情"));

mainLayout = new QGridLayout(this);

mainLayout->addWidget (hostLabel, 0, 0);

mainLayout->addWidget (hostNameLineEdit, 0, 1);

mainLayout->addWidget (ipLabel, 1, 0);

mainLayout->addWidget (ipLineEdit, 1, 1);

mainLayout->addWidget (detailBtn, 2, 0, 1, 2);

getHostInformation ();

connect (detailBtn, SIGNAL(clicked(bool)), this, SLOT(slotHostDetailInformation()));

}


NetworkInformation::~NetworkInformation()

{


}

/*

* QString localHostName = QHostInfo::localHostName ():获得本机主机名。QHostInfo提供了一系列有关网络信息的静态函数,

* 可以根据主机名获得分配的IP地址,也可以根据IP地址获得相应的主机名

*

* QHostInfo hostInfo = QHostInfo::fromName (localHostName):根据主机名获得相关信息,包括IP地址等。QHostInfo::

* fromName()函数通过主机名查找IP地址信息。

*

* if(!listAdress.isEmpty ()){...}获得的主机IP地址列表可能为空。在不为空的情况下使用第一个IP地址。

*/

void NetworkInformation::getHostInformation ()

{

QString localHostName = QHostInfo::localHostName ();

hostNameLineEdit->setText (localHostName);

QHostInfo hostInfo = QHostInfo::fromName (localHostName);

QList<QHostAddress> listAdress = hostInfo.addresses ();

if(!listAdress.isEmpty ())

{

ipLineEdit->setText (listAdress.first ().toString ());

}

}

/*

* QNetworkInterface类提供了一个主机IP地址和网络接口的列表

*

* interface.name():获得网络接口的名称

* interface.hardwareAddress():获得网络接口的硬件地址

* interface.addressEntries():每个网络接口包括0个或多个IP地址,每个IP地址有选择性地与一个子网掩码和一个广播地址相关联。

* QNetworkAddressEntry类存储了被网络接口支持的一个IP地址,同时还包括与之相关的子网掩码和广播地址

*

* QMessageBox::information

* (

QWidget*parent,                       //消息框的父窗口指针

const QString& title,                 //消息框的标题栏

const QString& text,                  //消息框的文字提示信息

StandardButtonsbuttons=Ok,            //同Question消息框的注释内容

StandardButton defaultButton=NoButton //同Question消息框的注释内容

);


*/

void NetworkInformation::slotHostDetailInformation ()

{

QString detail = "";

QList<QNetworkInterface> list = QNetworkInterface::allInterfaces ();


for(int i = 0; i < list.count (); i++)

{

QNetworkInterface interface = list.at (i);

detail = detail + tr("设备") + interface.name () + "\n";

detail = detail + tr("硬件地址") + interface.hardwareAddress () + "\n";


QList<QNetworkAddressEntry> entryList = interface.addressEntries ();

for(int j = 0; j  < entryList.count (); j++)

{

QNetworkAddressEntry entry = entryList.at(j);

detail = detail + "\t" + tr("IP 地址:") + entry.ip ().toString () + "\n";

detail = detail + "\t" + tr("子网掩码") + entry.netmask ().toString () + "\n";

detail = detail + "\t" + tr("广播地址") + entry.broadcast ().toString () + "\n";

}

}

QMessageBox::information (this, tr("Detail"), detail);


}

10.2基于UDP的网络广播程序

用户数据报协议(User Data Protocol,UDP)是一种简单轻量级、不可靠、面向数据报、无连接的传输层协议,可以应用在可靠性不是十分重要的场合,如短消息、广

播信息等。

适合应用的情况有以下几种:

网络数据大多为短消息。

拥有大量客户端。

对数据安全性无特殊要求。

网络负担非常重,但对响应速度要求高。

10.2.1 UDP协议工作原理

如下图所示,UDP客户端向UDP服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层IP协议规定的64KB;UDP服务器同样以报

文形式作出响应。如果服务器未收到此请求,客户端不会重发,因此报文的传输是不可靠的。



例如,常用的聊天工具--腾讯QQ软件就是使用UDP协议发送协议消息的,因此有时会出现收不到消息的情况。

10.2.2 UDP编程模型

基于UDP协议的经典编程模型,程序编程的通信流程如图所示。



可以看出,在UDP方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。类似地,服务器也不从客户端接收链接,只负责调用接收函数,

等待来自某客户端的数据到达。

Qt中通过QUdpSocket类实现UDP协议的编程。接下来通过一个实例,介绍如何实现基于UDP协议的广播应用,它由UDP服务器和UDP客户端两部分组成。

10.2.3 UDP服务器编程

udpserver.h

#ifndef UDPSERVER_H

#define UDPSERVER_H


#include <QDialog>

#include <QLabel>

#include <QLineEdit>

#include <QPushButton>

#include <QVBoxLayout>

#include <QUdpSocket>

#include <QTimer>


class UdpServer : public QDialog

{

Q_OBJECT


public:

    UdpServer(QWidget*parent = 0);

~UdpServer();

public slots:

void StartBtnClicked();

void timeout();

private:

    QLabel*TimerLabel;

    QLineEdit*TextLineEdit;

    QPushButton*StartBtn;

    QVBoxLayout*mainLayout;

int port;                   //UDP端口号

bool isStarted;

    QUdpSocket*udpSocket;

    QTimer*timer;

};



#endif // UDPSERVER_H

udpserver.cpp

#include "udpserver.h"


UdpServer::UdpServer(QWidget*parent)

: QDialog(parent)

{

setWindowTitle (tr("UDP Server"));

TimerLabel = new QLabel(tr("计时器:"));

TextLineEdit = new QLineEdit;

StartBtn = new QPushButton("开始");


mainLayout = new QVBoxLayout(this);

mainLayout->addWidget (TimerLabel);

mainLayout->addWidget (TextLineEdit);

mainLayout->addWidget (StartBtn);

connect (StartBtn, SIGNAL(clicked(bool)), this, SLOT(StartBtnClicked()));


port = 6666;                        //设置UDP的端口号参数,服务器定时向此端口发送广播信息

isStarted = false;

udpSocket = new QUdpSocket(this);   //创建一个QUdpSocket

timer = new QTimer(this);

connect (timer, SIGNAL(timeout()), this, SLOT(timeout()));

}


UdpServer::~UdpServer()

{


}

/*

* StartBtnClicked()函数

*/

void UdpServer::StartBtnClicked ()

{

if(!isStarted)

{

StartBtn->setText (tr("停止"));

timer->start (1000);

isStarted = true;

}

else

{

StartBtn->setText (tr("开始"));

timer->stop ();

    isStarted = false;

}

}

/*

* timeout()函数完成了向端口发送广播信息的功能

*

* QHostAddress::Broadcast指定向广播地址发送

*/

void UdpServer::timeout ()

{

QString msg = TextLineEdit->text ();

int length = 0;

if(msg == "")

{

return ;

}

if(length = udpSocket->writeDatagram (msg.toLatin1 (),

msg.length (), QHostAddress::Broadcast, port) != msg.length ())

{

return;

}


}

10.2.4 UDP客户端编程

udpclient.h

#ifndef UDPCLIENT_H

#define UDPCLIENT_H


#include <QDialog>

#include <QTextEdit>

#include <QPushButton>

#include <QVBoxLayout>

#include <QUdpSocket>


class UdpClient : public QDialog

{

Q_OBJECT


public:

    UdpClient(QWidget*parent = 0);

~UdpClient();

public slots:

void CloseBtnClicked();

void dataReceived();

private:

    QTextEdit*ReciveTextEdit;

    QPushButton*closeBtn;

    QVBoxLayout*mainLayout;

int port;       //UDP端口

    QUdpSocket*udpSocket;

};



#endif // UDPCLIENT_H

udpclient.cpp

#include "udpclient.h"

#include <QMessageBox>


/*

* connect (udpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())): 链接QIODevice的readyRead()信号。

* QUdpSocket也是一个I/O设备,从QIODevice继承而来,当有数据到达I/O设备时,发出readyRead()信号。

*/

UdpClient::UdpClient(QWidget*parent)

: QDialog(parent)

{

setWindowTitle (tr("UDP Client"));

ReciveTextEdit = new QTextEdit;

closeBtn = new QPushButton(tr("close"), this);

mainLayout = new QVBoxLayout(this);

mainLayout->addWidget (ReciveTextEdit);

mainLayout->addWidget (closeBtn);

connect (closeBtn, SIGNAL(clicked()), this, SLOT(CloseBtnClicked()));

port = 6666;

udpSocket = new QUdpSocket(this);

connect (udpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));


bool result = udpSocket->bind (port);   //绑定到指定的端口上

if(!result)

{

QMessageBox::information (this, tr("error"), tr("udp socked create error!"));

return;

}

}


UdpClient::~UdpClient()

{


}

/*

* udpSocket->hasPendingDatagrams ():判断UdpSocket中是否有数据报可读

* hasPendingDatagrams ()方法在在至少有一个数据报可读时返回true,否则返回false。

*

* QByteArray datagram;

* datagram.resize (udpSocket->pendingDatagramSize ());

* udpSocket->readDatagram (datagram.data (), datagram.size ());

* 实现读取第一个数据报,pendingDatagramSize()可以获得第一个数据报的长度

*

*/

void UdpClient::dataReceived ()

{

while(udpSocket->hasPendingDatagrams ())

{

QByteArray datagram;

datagram.resize (udpSocket->pendingDatagramSize ());

udpSocket->readDatagram (datagram.data (), datagram.size ());

QString msg = datagram.data ();

ReciveTextEdit->insertPlainText (msg);

}

}


void UdpClient::CloseBtnClicked ()

{

close();

}


服务器、客户端的运行界面





10.3 基于TCP的网络聊天室程序

传输控制协议(Transmission Control Protocol,TCP)是一种可靠、面向连接、面向数据流的传输协议,许多高层应用协议(包括HTTP、FTP等)都是以它为基础的,

TCP协议非常适合数据的连续传输。

TCP协议与UDP协议的差别建表

比较项TCPUDP
是否连接面向连接无连接
传输可靠性可靠不可靠
流量控制提供不提供
工作方式全双工可以全双工
应用场合大量数据少量数据
速度
10.3.1 TCP协议工作原理

TCP协议能够为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地送达网络上的其他计算机。因此,对可靠性要求高的数据通信系统往往使用TCP协议

传输数据,但在正式收发数据前,通信双方必须先建立连接。



10.3.2 TCP编程模型

首先启动服务器,一段时间后启动客户端,它与此服务器经历三次握手后建立连接。此后的一段时间内,客户端向服务器发送一个请求,服务器处理这个请求,并为客户端发回一个响应。这个过程一直持续下去,直到客户端为服务器发一个文件结束符,并关闭客户端连接,接着服务器也关闭服务器端的连接,结束运行或等待一个新的客户端连接。

Qt中通过QTcpSocket类和QTcpServer类实现TCP协议的编程。下面介绍如何实现一个基于TCP协议的网络聊天室应用,它同样也由客户端和服务器两部分组成。



TcpServer

tcpserver.h

#ifndef TCPSERVER_H

#define TCPSERVER_H


#include <QDialog>

#include <QLabel>

#include <QPushButton>

#include <QListWidget>

#include <QGridLayout>

#include <QLineEdit>

#include "server.h"


class TcpServer : public QDialog

{

Q_OBJECT


public:

    TcpServer(QWidget*parent = 0, Qt::WindowFlags f = 0);

~TcpServer();

private:

    QListWidget*ContentListWidget;

    QLabel*PortLabel;

    QLineEdit*PortLineEdit;

    QPushButton*CreateBtn;

QGridLayout*mainLayout;

int port;

    Server*server;

public slots:

void slotCreateServer();

void updateServer(QString, int);

};



#endif // TCPSERVER_H

tcpserver.cpp

#include "tcpserver.h"


TcpServer::TcpServer(QWidget*parent, Qt::WindowFlags f)

: QDialog(parent)

{

setWindowTitle (tr("TCP Server"));

ContentListWidget = new QListWidget;

PortLabel = new QLabel(tr("端口:"));

PortLineEdit = new QLineEdit;

CreateBtn = new QPushButton(tr("创建聊天室"));

mainLayout = new QGridLayout(this);

mainLayout->addWidget (ContentListWidget, 0, 0, 1 , 2);

mainLayout->addWidget (PortLabel, 1, 0);

mainLayout->addWidget (PortLineEdit, 1, 1);

mainLayout->addWidget (CreateBtn, 2, 0, 1, 2);


port = 8010;

PortLineEdit->setText (QString::number (port));

connect (CreateBtn, SIGNAL(clicked()), this, SLOT(slotCreateServer()));

}


TcpServer::~TcpServer()

{


}

/*

* 创建一个TCP服务器

* connect (server, SIGNAL(updateServer(QString,int)), this, SLOT(updateServer(QString,int)))

*/

void TcpServer::slotCreateServer ()

{

server = new Server(this, port);

connect (server, SIGNAL(updateServer(QString,int)), this, SLOT(updateServer(QString,int)));

CreateBtn->setEnabled (false);

}


void TcpServer::updateServer (QString msg, int length)

{

ContentListWidget->addItem (msg.left (length));

}


tcpclientsocket.h

#ifndef TCPCLIENTSOCKET_H

#define TCPCLIENTSOCKET_H


#include <QTcpSocket>


class TcpClientSocket : public QTcpSocket

{

Q_OBJECT        //添加宏(Q_OBJECT)是为了实现信号与槽的通信

public:

    TcpClientSocket(QObject*parent = 0);

signals:

void updateClients(QString, int);

void disconnected (int);

protected slots:

void dataReceived();

void slotDisconnected();

};



#endif // TCPCLIENTSOCKET_H

tcpclientsocket.cpp

#include "tcpclientsocket.h"


/*

* connect (this, SIGNAL(readyRead()), this, SLOT(dataReceived())):readyRead()是QIODevice的signal,由

* QTcpSocket继承而来。QIODevice是所有输入/输出设备的一个抽象类,其中定义了基本的接口,在Qt中,QTcpSocket也被看成一个

* QIODevice,readyRead()信号在有数据到来时发出。

*

* connect (this, SIGNAL(disconnected()), this, SLOT(slotDisconnected())): disconnected()信号在断开连接时发出。

*/

TcpClientSocket::TcpClientSocket(QObject*parent)

{

connect (this, SIGNAL(readyRead()), this, SLOT(dataReceived()));

connect (this, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));

}

/*

* 当有数据到来时,触发dataReceived()函数,从套接字中将有效数据取出,然后发出updateClients()信号。updateClients()信号

* 是通知服务器向聊天室内的所有成员广播信息。

*/

void TcpClientSocket::dataReceived ()

{

while(bytesAvailable () > 0)

{

int length = bytesAvailable ();

char buf[1024];

read(buf, length);


QString msg = buf;

emit updateClients(msg,length);

}

}

/*

* 断开socket描述符

*/

void TcpClientSocket::slotDisconnected ()

{

emit disconnected (this->socketDescriptor ());

}


server.h

#ifndef SERVER_H

#define SERVER_H


#include <QTcpServer>

#include <QObject>

#include "tcpclientsocket.h"

/*

* QList<TcpClientSocket*> TcpClientSocketList用来保存与每个客户端连接的TcpClientSocket

*/

class Server : public QTcpServer

{

Q_OBJECT    //添加宏是为了实现信号与槽的通信

public:

    Server(QObject*parent = 0, int port = 0);

QList<TcpClientSocket*> tcpClientSocketList;

signals:

void updateServer(QString, int);

public slots:

void updateClients(QString, int);

void slotDisconnected(int);

protected:

void incomingConnection(int socketDescriptor);

};


#endif // SERVER_H


server.cpp

#include "server.h"


/*

* listen(QHostAddress::Any, port)在指定的端口对任意地址进行监听

* QHostAddress定义了几种特殊的IP地址,如QHostAddress::NULL表示一个空地址;QHostAddress::LocalHost表示IPv4的本机

* 地址127.0.0.1;QHostAddress::LocallHostIPv6表示IPv6的本机地址;QHostAddress::Broadcast表示广播地址

* 255.255.255.255;QHostAddress::Any表示IPv4的任意地址0.0.0.0;QHostAddress::AnyIPv6表示IPv6的任意地址。

*/

Server::Server(QObject*parent, int port)

:QTcpServer(parent)

{

listen(QHostAddress::Any, port);

}

/*

* TcpClientSocket*tcpClientSocket = new TcpClientSocket(this):

* 创建一个新的TcpClientSocket与客户端通信

*

* connect (tcpClientSocket, SIGNAL(updateClients(QString, int)),

* this, SLOT(updateClients(QString,int))): 连接TcpClientSocket的updateClients信号。

*

* connect (tcpClientSocket, SIGNAL(disconnected(int)),

* this, SLOT(slotDisconnected(int))): 连接TcpClientSocket的disconnected信号。

*

* tcpClientSocket->setSocketDescriptor (socketDescriptor): 将新创建的TcpClientSocket的

* 套接字描述符指定为参数socketDescriptor

*

* tcpClientSocketList.append (tcpClientSocket):将TcpClientSocket加入客户端套接字列表以便管理。

*/

void Server::incomingConnection (int socketDescriptor)

{

    TcpClientSocket*tcpClientSocket = new TcpClientSocket(this);

connect (tcpClientSocket, SIGNAL(updateClients(QString, int)),

this, SLOT(updateClients(QString,int)));

connect (tcpClientSocket, SIGNAL(disconnected(int)),

this, SLOT(slotDisconnected(int)));

tcpClientSocket->setSocketDescriptor (socketDescriptor);

tcpClientSocketList.append (tcpClientSocket);

}


/*

* emit updateServer (msg, length): 发出updateServer信号,用来通知服务器对话框更新相应的显示状态

*

* for(int i = 0; i < TcpClientSocketList.count (); i++): 实现信息的广播,tcpClientSocketList

* 中保存了所有与服务器相连的TcpClientSocket对象。

*/

void Server::updateClients (QString msg, int length)

{

emit updateServer (msg, length);

for(int i = 0; i < tcpClientSocketList.count (); i++)

{

        QTcpSocket*item = tcpClientSocketList.at (i);

if(item->write (msg.toLatin1 (), length) != length)

{

continue;

}

}

}

/*

* slotDisconnected()函数实现从TcpClientSocketList列表中将断开连接的TcpClientSocket对象删除的功能。

*/

void Server::slotDisconnected (int descriptor)

{

for(int i = 0; i < tcpClientSocketList.count (); i++)

{

        QTcpSocket*item = tcpClientSocketList.at (i);

if(item->socketDescriptor () == descriptor)

{

tcpClientSocketList.removeAt (i);

return;

}

}

return;

}



TcpClient


tcpclient.h

#ifndef TCPCLIENT_H

#define TCPCLIENT_H


#include <QDialog>

#include <QListWidget>

#include <QLabel>

#include <QLineEdit>

#include <QPushButton>

#include <QGridLayout>

#include <QTcpSocket>

#include <QHostAddress>


class TcpClient : public QDialog

{

Q_OBJECT


public:

    TcpClient(QWidget*parent = 0, Qt::WindowFlags f = 0);

~TcpClient();


private:

    QListWidget*contenListWidget;

    QLineEdit*sendLineEdit;

    QPushButton*sendBtn;

    QLabel*userNameLabel;

    QLineEdit*userNameLineEdit;

    QLabel*serverIPLabel;

    QLineEdit*serverIPLineEdit;

    QLabel*portLabel;

    QLineEdit*portLineEdit;

    QPushButton*enterBtn;

QGridLayout*mainLayout;

bool status;

int port;

    QHostAddress*serverIP;

QString userName;

    QTcpSocket*tcpSocket;


public slots:

void slotEnter();

void slotConnected();

void slotDisConnected();

void dataReceived();

void slotSend();

};


#endif // TCPCLIENT_H


tcpclient.cpp

#include "tcpclient.h"

#include <QMessageBox>


TcpClient::TcpClient(QWidget*parent, Qt::WindowFlags f)

: QDialog(parent)

{

setWindowTitle (tr("TCP Client"));

contenListWidget = new QListWidget;


sendLineEdit = new QLineEdit;

sendBtn = new QPushButton(tr("发送"));


userNameLabel = new QLabel(tr("用户名:"));

userNameLineEdit = new QLineEdit;


serverIPLabel = new QLabel(tr("服务器地址:"));

serverIPLineEdit = new QLineEdit;


portLabel = new QLabel(tr("端口:"));

portLineEdit = new QLineEdit;


enterBtn = new QPushButton(tr("进入聊天室"));

mainLayout = new QGridLayout(this);

mainLayout->addWidget (contenListWidget, 0, 0, 1, 2);

mainLayout->addWidget (sendLineEdit, 1, 0);

mainLayout->addWidget (sendBtn, 1, 1);

mainLayout->addWidget (userNameLabel, 2, 0);

mainLayout->addWidget (userNameLineEdit, 2, 1);

mainLayout->addWidget (serverIPLabel, 3, 0);

mainLayout->addWidget (serverIPLineEdit, 3, 1);

mainLayout->addWidget (portLabel, 4, 0);

mainLayout->addWidget (portLineEdit, 4, 1);

mainLayout->addWidget (enterBtn, 5, 0, 1, 2);


status = false;

port = 8010;

portLineEdit->setText (QString::number (port));

serverIP = new QHostAddress();


connect (enterBtn, SIGNAL(clicked(bool)), this, SLOT(slotEnter()));

connect (sendBtn, SIGNAL(clicked(bool)), this, SLOT(slotSend()));


sendBtn->setEnabled (false);

}


TcpClient::~TcpClient()

{


}

/*

* status表示当前的状态,true表示已经进入聊天室,false表示已经离开聊天室。根据status的状态决定是执行“进入”还是“离开”

* serverIP->setAddress (ip): 用来判断给定的IP地址是否能够被正确解析

* tcpSocket->connectToHost (*serverIP, port):与TCP服务器端连接,连接成功后发出connected()信号

* QString msg = userName + tr(":Leave Char room"):构造一个离开聊天室的消息

*/

void TcpClient::slotEnter ()

{

if(!status)

{

/*完成输入合法性检验*/

QString ip = serverIPLineEdit->text ();

if(!serverIP->setAddress (ip))

{

QMessageBox::information (this, tr("error"), tr("server ip address error!"));

return;

}

if(userNameLineEdit->text () == "")

{

QMessageBox::information (this, tr("error"), tr("user name is error!"));

return;

}

userName = userNameLineEdit->text ();

/*创建一个QTcpSocket类对象,并将信号/槽连接起来*/

tcpSocket = new QTcpSocket(this);

connect (tcpSocket, SIGNAL(connected()), this, SLOT(slotConnected()));

connect (tcpSocket, SIGNAL(disconnected()), this, SLOT(slotDisConnected()));

connect (tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReceived()));


tcpSocket->connectToHost (*serverIP, port);

status = true;

}

else

{

int length = 0;

QString msg = userName + tr(":Leave Char room");

if(length = tcpSocket->write (msg.toLatin1 (), msg.length ()) != msg.length ())

{

    return ;

}

tcpSocket->disconnectFromHost ();

    status = false;

}

}


void TcpClient::slotSend ()

{

if(sendLineEdit->text () == "")

{

return;

}

QString msg = userName + ":" + sendLineEdit->text ();


tcpSocket->write (msg.toLatin1 (), msg.length ());

sendLineEdit->clear ();

}


void TcpClient::slotConnected ()

{

sendBtn->setEnabled (true);

enterBtn->setText (tr("离开"));


int length = 0;

QString msg = userName + tr(":Enter Chat Room");

if((length = tcpSocket->write (msg.toLatin1 (), msg.length ())) != msg.length ())

{

return;

}

}


void TcpClient::slotDisConnected ()

{

sendBtn->setEnabled (false);

enterBtn->setText (tr("进入聊天室"));

}


void TcpClient::dataReceived ()

{

while(tcpSocket->bytesAvailable () > 0)

{

QByteArray datagram;

datagram.resize (tcpSocket->bytesAvailable ());

tcpSocket->read (datagram.data (), datagram.size ());

QString msg = datagram.data ();

contenListWidget->addItem (msg.left (datagram.size ()));

}

}


10.4 Qt网络应用开发初步

myHTTP

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include <QtNetwork>


/*

* 首先创建一个QNetworkAccessManager类的实例,它用来发送网络请求和接收应答。然后关联了管理器finished()信号和自定义的

* 槽,每当网络应答结束时都会发送一个信号。最后使用了get()函数来发送一个网络请求,网络请求使用了QNetworkRequest类表示,

* get()函数返回一个QNetworkReply对象。

* 初始时隐藏下载进度条

*/

MainWindow::MainWindow(QWidget*parent) :

QMainWindow(parent),

ui(new Ui::MainWindow)

{

ui->setupUi(this);


manger = new QNetworkAccessManager(this);

connect (manger, SIGNAL(finished(QNetworkReply)), this, SLOT(replyFinished(QNetworkReply*)));

manger->get (QNetworkRequest(QUrl("http://www.baidu.com")));

ui->progressBar->hide ();

}


MainWindow::~MainWindow()

{

delete ui;

}

/*

* QNetworkReply继承自QIODevice类,所以可以像操作一般的I/O设备一样操作该类。这里使用了readAll()函数来读取所有的应答数据

* 在完成数据的读取后,需要使用deleteLater()删除reply对象。

*/

void MainWindow::replyFinished (QNetworkReply*reply)

{

QString all = reply->readAll ();

ui->textBrowser->setText (all);

reply->deleteLater ();

}

/*

* get()函数发送网络请求,进行了QNetworkReply对象的几个信号和自定义槽的关联。其中,readyRead()信号继承自QIODevice类,

* 每当有新的数据可以读取时,都会发送该信号;每当网络请求的下载进度更新时都会发送downloadProgress()信号,用于更新进度条:

* 每当应答处理结束时,都会发送finished()信号,该信号与前面程序中QNetworkAccessManager类的finished()信号作用相同,

* 只不过是发送者不同,参数也不同而已。

*/

void MainWindow::startRequest (QUrl url)

{

reply = manger->get(QNetworkRequest(url));

connect (reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));

connect (reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDataReadProgress(qint64,qint64)));

connect (reply, SIGNAL(finished()), this, SLOT(httpFinished()));

}

/*

* 首先判断是否创建了文件。如果是,则读取返回的所有数据,然后写入文件中。该文件是在后面的“下载”按钮的单击信号的槽中创建并打开的。

*/

void MainWindow::httpReadyRead ()

{

if(file)

{

file->write (reply->readAll ());

}

}


void MainWindow::updateDataReadProgress (qint64 bytesRead, qint64 totalButes)

{

ui->progressBar->setMaximum (totalButes);

ui->progressBar->setValue (bytesRead);

}


void MainWindow::httpFinished ()

{

ui->progressBar->hide ();

file->flush ();

file->close ();

reply->deleteLater ();

delete file;

file = 0;

}


void MainWindow::on_pushButton_clicked ()

{

url = ui->lineEdit->text();

QFileInfo info(url.path());

QString fileName(info.fileName ());

file = new QFile(fileName);

if(!file->open (QIODevice::WriteOnly))

{

qDebug() << "file open error!";

    delete file;

    file = 0;

return ;

}

startRequest (url);

ui->progressBar->setValue (0);

ui->progressBar->show ();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: