網站首頁 編程語言 正文
TCP簡介:
Transmission Control Protocol,傳輸控制協議 。用于數據傳輸的低層網絡協議,多個物聯網協議都是基于TCP協議的。它是一個面向數據流和連接的可靠傳輸協議。
TCP頭部格式:
QTcpSocket類為TCP提供了一個接口,繼承自QAbstractSocket。可實現POP3、SMTP、NNTP等標準的網絡協議,也可以實現自定義的網絡協議。異步工作,依靠事件循環來檢測到來的數據,并且自動刷新輸出的數據。而QAbstractSocket繼承自QIODevice,故該類具備文件的讀寫功能,可以使用QTextStream和QDataStream。
QHostAddress QAbstractSocket::peerAddress () const? 獲取主機的IP地址
quint16 QAbstractSocket::peerPort () const? 獲取主機的端口號
qint64 QIODevice::write ( const QByteArray & byteArray ) ?//寫入數據,即通過TCP發送數據。
QByteArray QIODevice::read ( qint64 maxSize ) ? //讀取數據,最多讀取maxSize。即獲取TCP接收的存放在緩沖區的數據
QByteArray QIODevice::readAll ()? //獲取TCP存放在緩沖區可讀取的所有數據。
從一個QTcpSocket中讀取數據前,必須先調用qint64 QIODevice::bytesAvailable () const 函數來確保已經有足夠的數據可用。
涉及到的信號:
void QAbstractSocket::connected () [signal] ?當連接建立成功發射連接信號,指示一個已建立的新連接。
void QAbstractSocket::error ( QAbstractSocket::SocketError socketError ) [signal] ?連接發生了錯誤,就會發送error()信號,參數指示發生了什么錯誤。
void QAbstractSocket::disconnected () [signal] ?斷開一個已經存在的連接時,發射斷開信號。
void QAbstractSocket::stateChanged ( QAbstractSocket::SocketState socketState ) [signal] ?狀態改變都會發射stateChanged()信號。
void QIODevice::bytesWritten ( qint64 bytes ) [signal] ?表示數據寫入完成,對應的可以調用bytesToWrite()方法了解寫入了多少字節的數據。
void QIODevice::readyRead () [signal] ?表示有數據可以讀取,對應的可以調用bytesAvailable()方法了解可以讀取多少字節的數據。
一個簡單的TCP客戶端和服務端程序,單連接。
客戶端程序:
#ifndef QTTCPCLIENT_H
#define QTTCPCLIENT_H
?
#include <QObject>
#include <QAbstractSocket>
?
class QTcpSocket; //前置聲明
?
//客戶端程序 ?單連接,即一個客戶端一個服務端
class QtTcpClient : public QObject
{
? ? Q_OBJECT
public:
? ? explicit QtTcpClient(QObject *parent = 0);
? ? ~QtTcpClient();
?
? ? void sendMessage(); //發送信息
?
private slots:
? ? void readMessage(); ?//獲取返回的信息
? ? void displayError(QAbstractSocket::SocketError); ?//獲取連接發生的錯誤
?
?
private:
?
? ? QTcpSocket *tcpSocket; ?//tcp連接
?
? ? quint16 blockSize; ?//發送數據的大小
};
?
#endif // QTTCPCLIENT_H
#include "qttcpclient.h"
#include <QtNetwork>
#include <QDataStream>
#include <QString>
#include <QByteArray>
#include <QIODevice>
#include <QObject>
#include <QDebug>
?
QtTcpClient::QtTcpClient(QObject *parent) :
? ? QObject(parent)
{
? ? tcpSocket=new QTcpSocket(this);
? ? //建立信號連接,readyRead表示有數據過來,需要讀取
? ? connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readMessage()));
? ? //建立信號連接,error(QAbstractSocket::SocketError)連接發生錯誤或關閉時會發射此信號
? ? connect(tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
?
? ? blockSize=0;
? ? tcpSocket->abort();//終止已有的連接
?
? ? tcpSocket->connectToHost(QHostAddress(QString("127.0.0.1")),6666);//建立新的連接
?
? ? qDebug()<<"client run......"<<endl;
}
?
QtTcpClient::~QtTcpClient()
{
? ? delete tcpSocket;
? ? tcpSocket=NULL;
}
?
void QtTcpClient::sendMessage()
{
? ? QByteArray block;
? ? QDataStream out(&block,QIODevice::WriteOnly);
?
? ? out.setVersion(QDataStream::Qt_4_0);
? ? out<<(quint16)0;
? ? out<<QString("hi server this is my first connect!!!");
? ? out.device()->seek(0);//定位到數據的開頭
? ? out<<(quint16)(block.size()-sizeof(quint16)); //添加數據大小信息到數據開頭
?
? ? tcpSocket->write(block); //發送數據
?
}
?
void QtTcpClient::readMessage()
{
? ? QString message;
? ? QDataStream in(tcpSocket);
? ? in.setVersion(QDataStream::Qt_4_0);
?
? ? if(blockSize==0)
? ? {
? ? ? ? //判斷接收的數據是否大于兩字節,也就是文件的大小信息所占的空間
? ? ? ? //如果是則保存到blockSize中,否則直接返回,繼續接收數據。
? ? ? ? if(tcpSocket->bytesAvailable()<(int)sizeof(quint16))
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
?
? ? ? ? in>>blockSize;
? ? }
? ? //如果沒有接收完全部數據,則返回繼續接收
? ? if(tcpSocket->bytesAvailable()<blockSize)
? ? {
? ? ? ? return;
? ? }
? ? //將接收的數據存放到變量中
? ? in>>message;
?
? ? qDebug()<<message;
?
? ? this->sendMessage();
?
? ? //斷開連接
? ? tcpSocket->disconnectFromHost();
}
?
void QtTcpClient::displayError(QAbstractSocket::SocketError)
{
? ? switch(tcpSocket->error())
? ? {
? ? case QAbstractSocket::RemoteHostClosedError: ?//遠程服務端關閉連接錯誤
? ? ? ? tcpSocket->disconnectFromHost();
? ? ? ? qDebug()<<"client close now";
? ? ? ? break;
? ? default:
? ? ? ? qDebug()<<"error id: "<<tcpSocket->error()<<endl;
? ? ? ? qDebug()<<"error message: "<<tcpSocket->errorString()<<endl;
? ? ? ? break;
? ? }
}
?
#include <QCoreApplication>
#include "qttcpclient.h"
?
int main(int argc, char *argv[])
{
? ? QCoreApplication a(argc, argv);
?
? ? QtTcpClient tcpclient_t;
? ??
? ? return a.exec();
}
服務端程序:
#ifndef QTTCPSERVER_H
#define QTTCPSERVER_H
?
#include <QObject>
#include <QAbstractSocket>
?
class QTcpServer; //前置聲明
class QTcpSocket;
?
//服務端程序 ?單連接,即一個客戶端一個服務端
class QtTcpServer : public QObject
{
? ? Q_OBJECT
public:
? ? explicit QtTcpServer(QObject *parent = 0);
? ? ~QtTcpServer();
?
private slots:
? ? void sendMessage();//發送信息
? ? void readMessage();//獲取返回的信息
? ? void displayError(QAbstractSocket::SocketError);//獲取連接發生的錯誤
?
private:
? ? QTcpServer *tcpServer; //tcp服務端
?
? ? QTcpSocket *clientConnect;//來自客戶端的連接
? ? quint16 blockSize; ?//接收數據的大小
};
?
#endif // QTTCPSERVER_H
?
?
#include "qttcpserver.h"
#include <QtNetwork>
#include <QDataStream>
#include <QString>
#include <QByteArray>
#include <QIODevice>
#include <QObject>
#include <QDebug>
?
QtTcpServer::QtTcpServer(QObject *parent) :
? ? QObject(parent)
{
? ? blockSize=0;
? ? tcpServer=new QTcpServer(this);
?
? ? //開始監聽
? ? if(!tcpServer->listen(QHostAddress(QString("127.0.0.1")),6666))
? ? {
? ? ? ? qDebug()<<tcpServer->serverError()<<endl;
? ? ? ? qDebug()<<tcpServer->errorString()<<endl;
? ? ? ? qApp->exit();
? ? }
? ? //建立信號連接,每來一個新的連接,就發送服務端信息
? ? connect(tcpServer,SIGNAL(newConnection()),this,SLOT(sendMessage()));
?
? ? qDebug()<<"server run....."<<endl;
}
?
QtTcpServer::~QtTcpServer()
{
? ? delete tcpServer;
? ? tcpServer=NULL;
?
? ? delete clientConnect;
? ? clientConnect=NULL;
}
?
void QtTcpServer::sendMessage()
{
? ? QByteArray block;
? ? QDataStream out(&block,QIODevice::WriteOnly);
?
? ? out.setVersion(QDataStream::Qt_4_0);
? ? out<<(quint16)0;
? ? out<<QString("hello client the connect build!!!");
? ? out.device()->seek(0);
? ? out<<(quint16)(block.size()-sizeof(quint16));
?
? ? clientConnect=tcpServer->nextPendingConnection();//獲取客戶端的連接
? ? tcpServer->close();
?
? ? //關聯套接字的disconnected()和deleteLater(),表明當連接斷開時刪除該套接字
? ? connect(clientConnect,SIGNAL(disconnected()),clientConnect,SLOT(deleteLater()));
?
? ? clientConnect->write(block);
?
? ? connect(clientConnect,SIGNAL(readyRead()),this,SLOT(readMessage()));
? ? connect(clientConnect,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
?
}
?
void QtTcpServer::readMessage()
{
? ? QString message;
? ? QDataStream in(clientConnect);
? ? in.setVersion(QDataStream::Qt_4_0);
?
? ? if(blockSize==0)
? ? {
? ? ? ? if(clientConnect->bytesAvailable()<(int)sizeof(quint16))
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
?
? ? ? ? in>>blockSize;
? ? }
?
? ? if(clientConnect->bytesAvailable()<blockSize)
? ? {
? ? ? ? return;
? ? }
?
? ? in>>message;
?
? ? qDebug()<<message;
?
}
?
void QtTcpServer::displayError(QAbstractSocket::SocketError)
{
? ? switch(clientConnect->error())
? ? {
? ? case QAbstractSocket::RemoteHostClosedError:
? ? ? ? clientConnect->disconnectFromHost(); //disconnectFromHost函數會一直等待套接字將所有數據發送完畢,然后關閉該套接字,并發射disconnected信號
? ? ? ? qDebug()<<"server connect close"<<endl;
? ? ? ? break;
? ? default:
? ? ? ? qDebug()<<"error id: "<<clientConnect->error()<<endl;
? ? ? ? qDebug()<<"error message: "<<clientConnect->errorString()<<endl;
? ? ? ? clientConnect->disconnectFromHost();
? ? ? ? qDebug()<<"server connect close"<<endl;
? ? ? ? break;
? ? }
}
?
#include <QCoreApplication>
#include "qttcpserver.h"
?
int main(int argc, char *argv[])
{
? ? QCoreApplication a(argc, argv);
?
? ? QtTcpServer tcpserver_t;
? ??
? ? return a.exec();
}
運行結果:
基于TCP的文件傳輸程序:
客戶端程序:
#ifndef CLIENT_H
#define CLIENT_H
#include <QAbstractSocket>
#include <QDialog>
#include <QFile>
#include <QTcpSocket>
#include <QString>
#include <QByteArray>
?
namespace Ui {
class Client;
}
?
class Client : public QDialog
{
? ? Q_OBJECT
? ??
public:
? ? explicit Client(QWidget *parent = 0);
? ? ~Client();
?
private slots:
? ? void openFile();
? ? void send();
? ? void startTransfer();
? ? void updateClientProgress(qint64);
? ? void displayError(QAbstractSocket::SocketError);
? ??
? ? void on_pushButton_open_clicked();
? ? void on_pushButton_send_clicked();
?
private:
? ? Ui::Client *ui;
?
? ? QTcpSocket *tcpClient; //tcp連接
? ? QFile *localFile; ? ? ?//要發送的文件
? ? qint64 totalBytes; ? ? //發送數據的總大小
? ? qint64 bytesWritten; ? //已經發送的數據大小
? ? qint64 bytesToWrite; ? //剩余的數據大小
? ? qint64 payloadSize; ? ?//每次發送數據的大小
? ? QString fileName; ? ? ?//保存文件路徑
? ? QByteArray outBlock; ? //數據緩沖區,即存放每次要發送的數據塊
};
?
#endif // CLIENT_H
?
?
#include "client.h"
#include "ui_client.h"
#include <QtNetwork>
#include <QFileDialog>
#include <QDebug>
?
Client::Client(QWidget *parent) :
? ? QDialog(parent),
? ? ui(new Ui::Client)
{
? ? ui->setupUi(this);
?
? ? //初始化變量
? ? this->payloadSize=64*1024; ? //64KB,每次發送的數據塊大小為64KB
? ? this->totalBytes=0;
? ? this->bytesWritten=0;
? ? this->bytesToWrite=0;
?
? ? this->tcpClient=new QTcpSocket(this);
?
? ? //當連接服務器成功時,發送connected()信號,開始傳送文件
? ? connect(this->tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));
? ? //每次發送成功后發送bytesWritten(qint64))信號,告訴已成功發送的數據塊大小,并更新進度條
? ? connect(this->tcpClient,SIGNAL(bytesWritten(qint64)),this,SLOT(updateClientProgress(qint64)));
? ? //接收tcp連接發生的錯誤
? ? connect(this->tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
?
? ? ui->pushButton_send->setEnabled(false);
}
?
Client::~Client()
{
? ? delete ui;
}
?
void Client::openFile()
{
? ? this->fileName=QFileDialog::getOpenFileName(this);
? ? if(!this->fileName.isEmpty())
? ? {
? ? ? ? ui->pushButton_send->setEnabled(true);
? ? ? ? ui->label_state->setText(QString("打開文件 %1 成功").arg(this->fileName));
? ? }
}
?
void Client::send()
{
? ? ui->pushButton_send->setEnabled(false);
?
? ? this->bytesWritten=0;
? ? ui->label_state->setText(QString("連接中..."));
? ? //連接服務器
? ? this->tcpClient->connectToHost(ui->lineEdit_host->text(),ui->lineEdit_port->text().toInt());
}
?
void Client::startTransfer()
{
? ? this->localFile=new QFile(this->fileName);
? ? //打開文件
? ? if(!this->localFile->open(QFile::ReadOnly))
? ? {
? ? ? ? qDebug()<<"client: open file error!"<<endl;
? ? ? ? return;
? ? }
?
? ? //獲取打開文件的大小
? ? this->totalBytes=this->localFile->size();
?
? ? QDataStream sendOut(&this->outBlock,QIODevice::WriteOnly);
? ? sendOut.setVersion(QDataStream::Qt_4_0);
? ? //獲取文件名(去掉文件前面的路徑)
? ? QString currentFileName=this->fileName.right(this->fileName.size()-this->fileName.lastIndexOf('/')-1);
? ? //保留總大小信息空間,文件名大小信息空間,然后輸入文件名
? ? sendOut<<qint64(0)<<qint64(0)<<currentFileName;
? ? //總大小變量為總大小信息、文件名大小信息、文件名和實際文件大小的總和
? ? this->totalBytes+=this->outBlock.size();
? ? //返回outBlock的開始,填入總大小信息
? ? sendOut.device()->seek(0);
? ? //填入各個項的大小信息以及文件名
? ? sendOut<<this->totalBytes<<qint64(this->outBlock.size()-sizeof(qint64)*2);
? ? //發送完文件頭結構后剩余數據的大小
? ? this->bytesToWrite=this->totalBytes-this->tcpClient->write(this->outBlock);
?
? ? ui->label_state->setText(QString("已連接"));
? ? this->outBlock.resize(0);
}
?
void Client::updateClientProgress(qint64 numBytes)
{
? ? //更新已經發送數據的大小
? ? this->bytesWritten+=(int)numBytes;
? ? //如果已經發送了數據
? ? if(this->bytesToWrite>0)
? ? {
? ? ? ? //每次發送payloadSize大小的數據,不足就發送剩余數據大小
? ? ? ? this->outBlock=this->localFile->read(qMin(this->bytesToWrite,this->payloadSize));
? ? ? ? //發送完一次數據后還剩余數據的大小
? ? ? ? this->bytesToWrite-=(int)this->tcpClient->write(this->outBlock);
? ? ? ? //清空發送緩沖區
? ? ? ? this->outBlock.resize(0);
? ? }
? ? else
? ? {
? ? ? ? //如果沒有發送任何數據,就關閉文件
? ? ? ? this->localFile->close();
? ? }
?
? ? //更新進度條
? ? ui->progressBar->setMaximum(this->totalBytes);
? ? ui->progressBar->setValue(this->bytesWritten);
?
? ? //發送完畢
? ? if(this->bytesWritten==this->totalBytes)
? ? {
? ? ? ? ui->label_state->setText(QString("傳送文件 %1 成功").arg(this->fileName));
? ? ? ? this->localFile->close(); //關閉文件
? ? ? ? this->tcpClient->close(); //關閉tcp連接
? ? }
}
?
void Client::displayError(QAbstractSocket::SocketError)
{
? ? qDebug()<<this->tcpClient->errorString()<<endl;
? ? this->tcpClient->close();
? ? ui->progressBar->reset();
? ? ui->label_state->setText(QString("客戶端已就緒!"));
? ? ui->pushButton_send->setEnabled(true);
}
?
void Client::on_pushButton_open_clicked()
{
? ? ui->progressBar->reset();
? ? ui->label_state->setText(QString("狀態:等待文件打開!"));
? ? this->openFile();
}
?
void Client::on_pushButton_send_clicked()
{
? ? this->send();
}
?
?
#include <QApplication>
#include "client.h"
#include <QTextCodec>
?
int main(int argc, char *argv[])
{
? ? QApplication a(argc, argv);
?
? ? QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
? ? QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
? ? QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
?
? ? Client w;
? ? w.show();
? ??
? ? return a.exec();
}
服務器程序:
#ifndef SERVER_H
#define SERVER_H
?
#include <QDialog>
#include <QFile>
#include <QTcpSocket>
#include <QTcpServer>
#include <QAbstractSocket>
#include <QString>
#include <QByteArray>
?
namespace Ui {
class Server;
}
?
class Server : public QDialog
{
? ? Q_OBJECT
? ??
public:
? ? explicit Server(QWidget *parent = 0);
? ? ~Server();
?
private slots:
? ? void start();
? ? void acceptConnection();
? ? void updateServerProgress();
? ? void displayError(QAbstractSocket::SocketError socketError);
?
? ? void on_pushButton_clicked();
?
private:
? ? Ui::Server *ui;
?
? ? QTcpServer tcpServer; //服務器監聽
? ? QTcpSocket *tcpServerConnection; //來自客戶端的連接
?
? ? qint64 totalBytes; ?//存放總大小信息
? ? qint64 bytesReceived; //已收到的數據大小
? ? qint64 fileNameSize; //存放文件名的大小信息
?
? ? QString fileName; ?//存放文件名
? ? QFile *localFile; ?//本地文件
? ? QByteArray inBlock; ?//數據緩沖區
};
?
#endif // SERVER_H
?
#include "server.h"
#include "ui_server.h"
#include <QtNetwork>
#include <QDebug>
?
Server::Server(QWidget *parent) :
? ? QDialog(parent),
? ? ui(new Ui::Server)
{
? ? ui->setupUi(this);
? ? //有新的連接到來,發射newConnection()信號,獲取新的連接
? ? connect(&this->tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
}
?
Server::~Server()
{
? ? delete ui;
}
?
void Server::start()
{
? ? //建立監聽
? ? if(!this->tcpServer.listen(QHostAddress(QString("127.0.0.1")),6666))
? ? {
? ? ? ? qDebug()<<this->tcpServer.errorString()<<endl;
? ? ? ? close();
? ? ? ? return;
? ? }
?
? ? ui->pushButton->setEnabled(false);
? ? //初始化變量
? ? this->totalBytes=0;
? ? this->bytesReceived=0;
? ? this->fileNameSize=0;
?
? ? ui->label->setText(QString("監聽"));
? ? ui->progressBar->reset();
}
?
void Server::acceptConnection()
{
? ? //獲取來自客戶端的連接
? ? this->tcpServerConnection=this->tcpServer.nextPendingConnection();
? ? //建立信號連接
? ? connect(this->tcpServerConnection,SIGNAL(readyRead()),this,SLOT(updateServerProgress()));
? ? connect(this->tcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
?
? ? ui->label->setText(QString("接收連接"));
?
? ? this->tcpServer.close();
}
?
void Server::updateServerProgress()
{
? ? QDataStream in(this->tcpServerConnection);
? ? in.setVersion(QDataStream::Qt_4_0);
? ? //如果接收到的數據小于16個字節,保存到來的文件頭結構
? ? if(this->bytesReceived<=sizeof(qint64)*2)
? ? {
? ? ? ? if((this->tcpServerConnection->bytesAvailable()>=sizeof(qint64)*2)&&(this->fileNameSize==0))
? ? ? ? {
? ? ? ? ? ? //接收數據總大小信息和文件名大小信息
? ? ? ? ? ? in>>this->totalBytes>>this->fileNameSize;
? ? ? ? ? ? this->bytesReceived+=sizeof(qint64)*2;
? ? ? ? }
?
? ? ? ? if((this->tcpServerConnection->bytesAvailable()>=this->fileNameSize)&&(this->fileNameSize!=0))
? ? ? ? {
? ? ? ? ? ? //接收文件名,并建立文件
? ? ? ? ? ? in>>this->fileName;
? ? ? ? ? ? ui->label->setText(QString("接收文件 %1 ......").arg(this->fileName));
? ? ? ? ? ? this->bytesReceived+=this->fileNameSize;
? ? ? ? ? ? this->localFile=new QFile(this->fileName);
? ? ? ? ? ? if(!this->localFile->open(QFile::WriteOnly))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? qDebug()<<"server: open file error"<<endl;
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? }
? ? //開始接收文件里面的數據
? ? if(this->bytesReceived<this->totalBytes)
? ? {
? ? ? ? this->bytesReceived+=this->tcpServerConnection->bytesAvailable();
? ? ? ? this->inBlock=this->tcpServerConnection->readAll();
? ? ? ? this->localFile->write(this->inBlock);
? ? ? ? this->inBlock.resize(0);
? ? ?}
?
? ? ui->progressBar->setMaximum(this->totalBytes);
? ? ui->progressBar->setValue(this->bytesReceived);
? ? //接收數據完成時
? ? if(this->bytesReceived==this->totalBytes)
? ? {
? ? ? ? this->tcpServerConnection->close();
? ? ? ? this->localFile->close();
? ? ? ? ui->pushButton->setEnabled(true);
? ? ? ? ui->label->setText(QString("接收文件 %1 成功").arg(this->fileName));
? ? }
}
?
void Server::displayError(QAbstractSocket::SocketError socketError)
{
? ? qDebug()<<this->tcpServerConnection->errorString();
? ? this->tcpServerConnection->close();
? ? ui->progressBar->reset();
? ? ui->label->setText(QString("服務端就緒"));
? ? ui->pushButton->setEnabled(true);
}
?
void Server::on_pushButton_clicked()
{
? ? start();
}
?
?
#include <QApplication>
#include "server.h"
#include <QTextCodec>
?
int main(int argc, char *argv[])
{
? ? QApplication a(argc, argv);
?
? ? QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
? ? QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
? ? QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
?
? ? Server w;
? ? w.show();
? ??
? ? return a.exec();
}
運行結果:
原文鏈接:https://blog.csdn.net/qq_33232152/article/details/104204386
相關推薦
- 2022-07-10 TypeError: Cannot read property ‘forceUpdate‘ of u
- 2022-12-27 Python實現ATM簡單功能的示例詳解_python
- 2022-11-20 Go語言操作Excel利器之excelize類庫詳解_Golang
- 2022-10-22 PostgreSql生產級別數據庫安裝要注意事項_PostgreSQL
- 2022-07-26 正則表達式規則
- 2022-06-06 一文搞懂Redis中String數據類型_Redis
- 2022-07-03 C語言中二級指針解析(指向指針的指針)_C 語言
- 2022-09-30 python實現圖像邊緣檢測_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支