Qt_套接字
在網上找了好多有關套接字的博客,看了一些代碼,復制下來跑的時候總是不出來,然后在QDocument上找到了一個例子程序,就復制下來了。看代碼的時候里面用到了好的類,好像是用來保存一個網絡設置的,沒看懂,然后就吧這部分給刪了 = =。
運行的結果
源代碼
server.h
#ifndef SERVER_H #define SERVER_H#include <QDialog>class QLabel; class QPushButton; class QTcpServer;class Server : public QDialog {Q_OBJECTpublic:Server(QWidget *parent = 0);private slots:void sendFortune();private:QLabel *statusLabel;QPushButton *quitButton;QTcpServer *tcpServer;QStringList fortunes; };#endifserver.cpp
#include <QtWidgets> #include <QtNetwork>#include <stdlib.h>#include "server.h"Server::Server(QWidget *parent) : QDialog(parent), tcpServer(0) {statusLabel = new QLabel;quitButton = new QPushButton(tr("Quit"));quitButton->setAutoDefault(false);tcpServer = new QTcpServer(this);if (!tcpServer->listen()) {QMessageBox::critical(this, tr("Fortune Server"),tr("Unable to start the server: %1.").arg(tcpServer->errorString()));close();return;}QString ipAddress;QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();// use the first non-localhost IPv4 addressfor (int i = 0; i < ipAddressesList.size(); ++i) {if (ipAddressesList.at(i) != QHostAddress::LocalHost &&ipAddressesList.at(i).toIPv4Address()) {ipAddress = ipAddressesList.at(i).toString();break;}}// if we did not find one, use IPv4 localhostif (ipAddress.isEmpty())ipAddress = QHostAddress(QHostAddress::LocalHost).toString();statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n""Run the Fortune Client example now.").arg(ipAddress).arg(tcpServer->serverPort()));fortunes << tr("1")<< tr("2")<< tr("3")<< tr("4")<< tr("5")<< tr("You cannot kill time without injuring eternity.")<< tr("Computers are not intelligent. They only think they are.");connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));QHBoxLayout *buttonLayout = new QHBoxLayout;buttonLayout->addStretch(1);buttonLayout->addWidget(quitButton);buttonLayout->addStretch(1);QVBoxLayout *mainLayout = new QVBoxLayout;mainLayout->addWidget(statusLabel);mainLayout->addLayout(buttonLayout);setLayout(mainLayout);setWindowTitle(tr("Fortune Server"));}void Server::sendFortune() {QByteArray block;QDataStream out(&block, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_0);out << (quint16)0;out << fortunes.at(qrand() % fortunes.size());out.device()->seek(0);out << (quint16)(block.size() - sizeof(quint16));QTcpSocket *clientConnection = tcpServer->nextPendingConnection();connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater()));clientConnection->write(block);clientConnection->disconnectFromHost(); }main.cpp
#include <QApplication> #include <QtCore>#include <stdlib.h>#include "server.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Server server;server.show();qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));return app.exec(); }client.h
#ifndef CLIENT_H #define CLIENT_H#include <QDialog> #include <QTcpSocket>class QComboBox; class QDialogButtonBox; class QLabel; class QLineEdit; class QPushButton; class QTcpSocket; class QNetworkSession;class Client : public QDialog {Q_OBJECTpublic:Client(QWidget *parent = 0);private slots:void requestNewFortune();void readFortune();void displayError(QAbstractSocket::SocketError socketError);private:QLabel *hostLabel;QLabel *portLabel;QComboBox *hostCombo;QLineEdit *portLineEdit;QLabel *statusLabel;QPushButton *getFortuneButton;QPushButton *quitButton;QDialogButtonBox *buttonBox;QTcpSocket *tcpSocket;QString currentFortune;quint16 blockSize;//QNetworkSession *networkSession; };#endifclient.cpp
#include <QtWidgets> #include <QtNetwork>#include "client.h"Client::Client(QWidget *parent) : QDialog(parent) {hostLabel = new QLabel(tr("&Server name:"));portLabel = new QLabel(tr("S&erver port:"));hostCombo = new QComboBox;hostCombo->setEditable(true);// find out name of this machineQString name = QHostInfo::localHostName();if (!name.isEmpty()) {hostCombo->addItem(name);QString domain = QHostInfo::localDomainName();if (!domain.isEmpty())hostCombo->addItem(name + QChar('.') + domain);}if (name != QString("localhost"))hostCombo->addItem(QString("localhost"));// find out IP addresses of this machineQList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();// add non-localhost addressesfor (int i = 0; i < ipAddressesList.size(); ++i) {if (!ipAddressesList.at(i).isLoopback())hostCombo->addItem(ipAddressesList.at(i).toString());}// add localhost addressesfor (int i = 0; i < ipAddressesList.size(); ++i) {if (ipAddressesList.at(i).isLoopback())hostCombo->addItem(ipAddressesList.at(i).toString());}portLineEdit = new QLineEdit;portLineEdit->setValidator(new QIntValidator(1, 65535, this));hostLabel->setBuddy(hostCombo);portLabel->setBuddy(portLineEdit);statusLabel = new QLabel(tr("This examples requires that you run the ""Fortune Server example as well."));getFortuneButton = new QPushButton(tr("Get Fortune"));getFortuneButton->setDefault(true);getFortuneButton->setEnabled(true);quitButton = new QPushButton(tr("Quit"));buttonBox = new QDialogButtonBox;buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole);buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);tcpSocket = new QTcpSocket(this);connect(getFortuneButton, SIGNAL(clicked()),this, SLOT(requestNewFortune()));connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()));connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError)));QGridLayout *mainLayout = new QGridLayout;mainLayout->addWidget(hostLabel, 0, 0);mainLayout->addWidget(hostCombo, 0, 1);mainLayout->addWidget(portLabel, 1, 0);mainLayout->addWidget(portLineEdit, 1, 1);mainLayout->addWidget(statusLabel, 2, 0, 1, 2);mainLayout->addWidget(buttonBox, 3, 0, 1, 2);setLayout(mainLayout);setWindowTitle(tr("Fortune Client"));portLineEdit->setFocus(); }void Client::requestNewFortune() {getFortuneButton->setEnabled(false);blockSize = 0;tcpSocket->abort();tcpSocket->connectToHost(hostCombo->currentText(),portLineEdit->text().toInt()); }void Client::readFortune() {QDataStream in(tcpSocket);in.setVersion(QDataStream::Qt_4_0);if (blockSize == 0) {if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))return;in >> blockSize;}if (tcpSocket->bytesAvailable() < blockSize)return;QString nextFortune;in >> nextFortune;if (nextFortune == currentFortune) {QTimer::singleShot(0, this, SLOT(requestNewFortune()));return;}currentFortune = nextFortune;statusLabel->setText(currentFortune);getFortuneButton->setEnabled(true); }void Client::displayError(QAbstractSocket::SocketError socketError) {switch (socketError) {case QAbstractSocket::RemoteHostClosedError:break;case QAbstractSocket::HostNotFoundError:QMessageBox::information(this, tr("Fortune Client"),tr("The host was not found. Please check the ""host name and port settings."));break;case QAbstractSocket::ConnectionRefusedError:QMessageBox::information(this, tr("Fortune Client"),tr("The connection was refused by the peer. ""Make sure the fortune server is running, ""and check that the host name and port ""settings are correct."));break;default:QMessageBox::information(this, tr("Fortune Client"),tr("The following error occurred: %1.").arg(tcpSocket->errorString()));}getFortuneButton->setEnabled(true); }main.cpp
#include <QApplication> #include "client.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);Client client;client.show();return app.exec(); }分析
直接從cpp文件開始看
server.cpp
server的構造函數
Server::Server(QWidget *parent) : QDialog(parent), tcpServer(0) {//創建了一個label和按鈕對象statusLabel = new QLabel;quitButton = new QPushButton(tr("Quit"));quitButton->setAutoDefault(false);//新建一個tcpserver充當服務器tcpServer = new QTcpServer(this);//調用tcpserver的函數listen來監聽是否有客戶端連接,listen的第一個參數是客戶端的ip地址,第二個參數是監聽的端口號,若不填則為任意ip的值和一個隨機的端口號if (!tcpServer->listen()) {//如果沒有成功監聽報錯并返回QMessageBox::critical(this, tr("Fortune Server"),tr("Unable to start the server: %1.").arg(tcpServer->errorString()));close();return;}//定義了一個ip地址的鏈表//QNetworkInterface的靜態方法allAddresses返回了一個ip地址的鏈表,里面包含了所有在這臺主機上的ip地址。QString ipAddress;QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();//使用第一個不是本機ip的地址(并不知道是什么意思= =)for (int i = 0; i < ipAddressesList.size(); ++i) {if (ipAddressesList.at(i) != QHostAddress::LocalHost &&ipAddressesList.at(i).toIPv4Address()) {ipAddress = ipAddressesList.at(i).toString();break;}}//如果沒有找到就用本地主機的ipv4地址if (ipAddress.isEmpty())ipAddress = QHostAddress(QHostAddress::LocalHost).toString();//顯示服務器的ip地址和端口號statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n""Run the Fortune Client example now.").arg(ipAddress).arg(tcpServer->serverPort()));//將要隨機顯示的字符串放到字符串鏈表fortunes中fortunes << tr("1")<< tr("2")<< tr("3")<< tr("4")<< tr("5")<< tr("You cannot kill time without injuring eternity.")<< tr("Computers are not intelligent. They only think they are.");//將退出按鈕的點擊信號和關閉界面的槽關聯起來connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));//將新的連接信號和發送字符串的槽連接起來connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));//設置布局管理器QHBoxLayout *buttonLayout = new QHBoxLayout;buttonLayout->addStretch(1);buttonLayout->addWidget(quitButton);buttonLayout->addStretch(1);QVBoxLayout *mainLayout = new QVBoxLayout;mainLayout->addWidget(statusLabel);mainLayout->addLayout(buttonLayout);setLayout(mainLayout);setWindowTitle(tr("Fortune Server"));}發送字符串的函數
void Server::sendFortune() {//定義了一個字節數組QByteArray block;//定義了一個數據流QDataStream out(&block, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_0);out << (quint16)0;//將字符鏈表里隨機一個字符串放入到流里面out << fortunes.at(qrand() % fortunes.size());out.device()->seek(0);out << (quint16)(block.size() - sizeof(quint16));//定義一個套接字用來發送這個流//QTcpServer的nextPendingConnection函數就就是用來返回正在與服務器相連的套接字相對應的一個套接字。QTcpSocket *clientConnection = tcpServer->nextPendingConnection();connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater()));//將剛才的流通過套接字的write函數發送到客戶端clientConnection->write(block);clientConnection->disconnectFromHost(); }client.cpp
Client::Client(QWidget *parent) : QDialog(parent) {//初始化兩個label和一個下拉框hostLabel = new QLabel(tr("&Server name:"));portLabel = new QLabel(tr("S&erver port:"));hostCombo = new QComboBox;hostCombo->setEditable(true);// 找到本機的名稱QString name = QHostInfo::localHostName();if (!name.isEmpty()) {hostCombo->addItem(name);QString domain = QHostInfo::localDomainName();if (!domain.isEmpty())hostCombo->addItem(name + QChar('.') + domain);}if (name != QString("localhost"))hostCombo->addItem(QString("localhost"));// 找出本機的ip地址并添加,和服務器的類似QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();for (int i = 0; i < ipAddressesList.size(); ++i) {if (!ipAddressesList.at(i).isLoopback())hostCombo->addItem(ipAddressesList.at(i).toString());}for (int i = 0; i < ipAddressesList.size(); ++i) {if (ipAddressesList.at(i).isLoopback())hostCombo->addItem(ipAddressesList.at(i).toString());}portLineEdit = new QLineEdit;portLineEdit->setValidator(new QIntValidator(1, 65535, this));hostLabel->setBuddy(hostCombo);portLabel->setBuddy(portLineEdit);statusLabel = new QLabel(tr("This examples requires that you run the ""Fortune Server example as well."));getFortuneButton = new QPushButton(tr("Get Fortune"));getFortuneButton->setDefault(true);getFortuneButton->setEnabled(true);quitButton = new QPushButton(tr("Quit"));buttonBox = new QDialogButtonBox;buttonBox->addButton(getFortuneButton, QDialogButtonBox::ActionRole);buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);//初始化套接字,用于和主機通訊tcpSocket = new QTcpSocket(this);//將點擊按鈕和獲得字符串關聯起來connect(getFortuneButton, SIGNAL(clicked()),this, SLOT(requestNewFortune()));//將退出按鈕和關閉窗口關聯起來connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));//將套接字的獲取到新的數據流信號和讀取數據槽關聯起來connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()));//將套接字的錯誤與錯誤函數關聯起來connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError)));//設置布局管理器QGridLayout *mainLayout = new QGridLayout;mainLayout->addWidget(hostLabel, 0, 0);mainLayout->addWidget(hostCombo, 0, 1);mainLayout->addWidget(portLabel, 1, 0);mainLayout->addWidget(portLineEdit, 1, 1);mainLayout->addWidget(statusLabel, 2, 0, 1, 2);mainLayout->addWidget(buttonBox, 3, 0, 1, 2);setLayout(mainLayout);setWindowTitle(tr("Fortune Client"));portLineEdit->setFocus(); }requestnewfortune函數
void Client::requestNewFortune() {//初始化數據塊大小的值blockSize = 0;//終止當前的連接并重置套接字tcpSocket->abort();//連接到主機,如果找到主機名稱,套接字就會發出找到hostFound()信//號并開始連接,如果連接成功就會發出connected()信號并進入連接狀態tcpSocket->connectToHost(hostCombo->currentText(),portLineEdit->text().toInt()); }讀取字符串函數
void Client::readFortune() {//qt中的套接字繼承了QIODevice,所以可以類似于讀取文件的方式來讀取內容QDataStream in(tcpSocket);in.setVersion(QDataStream::Qt_4_0);//bytesAvailable()函數是返回套接字中數據流的大小if (blockSize == 0) {if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))return;in >> blockSize;}if (tcpSocket->bytesAvailable() < blockSize)return;//將套接字中的內容寫入到字符串中QString nextFortune;in >> nextFortune;if (nextFortune == currentFortune) {QTimer::singleShot(0, this, SLOT(requestNewFortune()));return;}currentFortune = nextFortune;statusLabel->setText(currentFortune); }總結
- 上一篇: PDF内存太大怎么压缩?三个方法教你如何
- 下一篇: QNX Hypervisor —— 虚拟