Qt中網(wǎng)絡(luò)編程的實(shí)現(xiàn)
由于我沒(méi)有系統(tǒng)的分享一些簡(jiǎn)單的計(jì)算機(jī)網(wǎng)絡(luò)有關(guān)的,下面只是簡(jiǎn)單講講tcp/ip協(xié)議簇和udp
一、tcp/IP協(xié)議簇與udp
1、TCP/IP協(xié)議族
TCP/IP實(shí)際上是一個(gè)協(xié)同工作的通信家族,為網(wǎng)絡(luò)通信提供通路。為方便討論TCP/IP協(xié)議族,大體上分為三部分:
①、Internet協(xié)議(IP)。
②、傳輸控制協(xié)議(TCP)和用戶(hù)數(shù)據(jù)報(bào)協(xié)議(UDP)。
③、處于TCP和UDP之上的一組應(yīng)用協(xié)議。它們包括:Telnet,文件傳送協(xié)議(FTP),域名服務(wù)協(xié)議(DNS)和簡(jiǎn)單的郵件傳送程序(SMTP)等。

2、udp
udp協(xié)議(用戶(hù)數(shù)據(jù)報(bào)協(xié)議),它與TCP協(xié)議完全相反。提供不可靠、無(wú)連接和基于數(shù)據(jù)報(bào)的服務(wù)。不可靠意味著UDP協(xié)議無(wú)法保證數(shù)據(jù)從發(fā)送端正確的發(fā)送到接收端。如果數(shù)據(jù)在中途丟失,或者目的端通過(guò)數(shù)據(jù)校驗(yàn)發(fā)現(xiàn)數(shù)據(jù)錯(cuò)誤而將其丟棄,則UDP協(xié)議的應(yīng)用程序通常要自己處理數(shù)據(jù)確認(rèn)、超時(shí)重傳等邏輯性。
3、常用的通訊協(xié)議小結(jié)
1.3.1、tcp/ip
tcp只需要知道它是一種通訊方式就可以了,還有一個(gè)udp,那這兩者之間的關(guān)系是什么。TCP/IP協(xié)議是一個(gè)協(xié)議簇。里面包括很多協(xié)議的。UDP只是其中的一個(gè)。之所以命名為T(mén)CP/IP協(xié)議,因?yàn)門(mén)CP,IP協(xié)議是兩個(gè)很重要的協(xié)議,就用他兩命名了,tcp是打電話(huà),udp是發(fā)短信。
Ip(網(wǎng)絡(luò)之間互連的協(xié)議,外文是Internet Protocol的外語(yǔ)縮寫(xiě),中文縮寫(xiě)為“網(wǎng)協(xié)”。縮寫(xiě)為IP),通過(guò)設(shè)置ip地址就可以去訪(fǎng)問(wèn)網(wǎng)絡(luò),用的最多的ip協(xié)議是ipv4(ip協(xié)議v版本4),還有一個(gè)版本為ipv6,ipv4不夠用了,Ipv4版本是32位的,一般分成4段,內(nèi)存中就是一個(gè)無(wú)符號(hào)32位的整數(shù),ipv6的話(huà)就是一個(gè)64位的整數(shù),通過(guò)位數(shù)就知道ipv4和ipv6的區(qū)別,能保存多少個(gè)的地址。只不過(guò)用戶(hù)并不需要去搞清楚。
現(xiàn)在常用的ip是127.0.0.1這個(gè)樣子,點(diǎn)分格式(一個(gè)字符串)。點(diǎn)所隔開(kāi)的區(qū)間就是一個(gè)字符。Ip地址有ABC三類(lèi)地址。前三段是用來(lái)確定路由器,確定主機(jī)連上外圍網(wǎng)上的哪一個(gè)路由,最后一段用來(lái)確定主機(jī),確定主機(jī)是這個(gè)路由器上的第多少臺(tái),最多255臺(tái),0一般是用來(lái)做網(wǎng)關(guān)的。
ip對(duì)應(yīng)的還有一個(gè)子網(wǎng)掩碼
子網(wǎng)掩碼(subnet mask)又叫網(wǎng)絡(luò)掩碼、地址掩碼、子網(wǎng)絡(luò)遮罩,它是一種用來(lái)指明一個(gè)IP地址的哪些位標(biāo)識(shí)的是主機(jī)所在的子網(wǎng),以及哪些位標(biāo)識(shí)的是主機(jī)的位掩碼。子網(wǎng)掩碼不能單獨(dú)存在,它必須結(jié)合IP地址一起使用。子網(wǎng)掩碼只有一個(gè)作用,就是將某個(gè)IP地址劃分成網(wǎng)絡(luò)地址和主機(jī)地址兩部分。子網(wǎng)掩碼--屏蔽一個(gè)IP地址的網(wǎng)絡(luò)部分的"全1"比特模式。
對(duì)于A類(lèi)地址來(lái)說(shuō),默認(rèn)的子網(wǎng)掩碼是255.0.0.0;
對(duì)于B類(lèi)地址來(lái)說(shuō)默認(rèn)的子網(wǎng)掩碼是255.255.0.0;
對(duì)于C類(lèi)地址來(lái)說(shuō)默認(rèn)的子網(wǎng)掩碼是255.255.255.0。
子網(wǎng)掩碼,一般是255.255.255.0。
ip地址的前三段來(lái)確定路由器,最后一段是主機(jī)位置。所以子網(wǎng)掩碼理解為子網(wǎng)遮罩編碼。
1.3.2、Socket
pc機(jī)對(duì)應(yīng)在網(wǎng)絡(luò)上就是一臺(tái)主機(jī),在這臺(tái)Pc機(jī)上面會(huì)有多個(gè)進(jìn)程需要訪(fǎng)問(wèn)網(wǎng)絡(luò),所以需要在Pc機(jī)的操作系統(tǒng)上面去有處理網(wǎng)絡(luò)的東西,前人就定了一個(gè)“套接字”來(lái)專(zhuān)門(mén)處理網(wǎng)絡(luò)(源IP地址和目的IP地址以及源端口號(hào)和目的端口號(hào)的組合稱(chēng)為套接字)。把一個(gè)主機(jī)拆分為N個(gè)網(wǎng)絡(luò)端口(Port)一共會(huì)有65536個(gè),short的最大范圍,在這些端口當(dāng)中,要注意0-5000的端口一般不用,用來(lái)給操作系統(tǒng)的進(jìn)程來(lái)使用的。一般會(huì)用靠后一點(diǎn)的端口,這樣比較安全,當(dāng)然還有一些端口,比如8080端口也會(huì)用的比較多,一個(gè)進(jìn)程只能占用一個(gè)端口,不能多進(jìn)程占用同一個(gè)端口的情況,一個(gè)進(jìn)程可以占用多個(gè)端口的,或者嚴(yán)謹(jǐn)一點(diǎn),同一時(shí)刻一個(gè)端口只能由一個(gè)進(jìn)程使用。網(wǎng)絡(luò)上的兩個(gè)程序通過(guò)一個(gè)雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個(gè)連接的一端稱(chēng)為一個(gè)socket。
建立網(wǎng)絡(luò)通信連接至少要一對(duì)端口號(hào)(socket)。socket本質(zhì)是編程接口(API),對(duì)TCP/IP的封裝,TCP/IP也要提供可供程序員做網(wǎng)絡(luò)開(kāi)發(fā)所用的接口,這就是Socket編程接口。通常也稱(chēng)作"套接字",用于描述IP地址和端口,是一個(gè)通信鏈的句柄,可以用來(lái)實(shí)現(xiàn)不同虛擬機(jī)或不同計(jì)算機(jī)之間的通信。
1.3.3、tcp通信模型
c/s模型,客戶(hù)端(c)/服務(wù)器(s)模型,一個(gè)服務(wù)器來(lái)對(duì)應(yīng)多個(gè)客戶(hù)端的處理,一對(duì)多的關(guān)系。以下步驟沒(méi)有特殊指明,服務(wù)器和客戶(hù)端是都需要有的步驟:
1.準(zhǔn)備工作,根據(jù)自己使用語(yǔ)言所有庫(kù)函數(shù)導(dǎo)入;
2. 確定版本信息,要確定socket版本,ip是有v4和v6兩個(gè)版本的;
3. 創(chuàng)建socket,使用socket函數(shù)
4. 初始化協(xié)議地址簇 ;
5. 綁定,使用bind函數(shù),把協(xié)議地址簇和socket綁定在一起,客戶(hù)端不要綁定;
6. 服務(wù)器端有,需要監(jiān)聽(tīng) listen函數(shù),客戶(hù)端不需要這一步;
7. 服務(wù)器端需要接受連接,客戶(hù)端需要連接服務(wù)器;
8. 連接完成之后,開(kāi)始通訊,收發(fā)數(shù)據(jù);
9. 通訊完成后關(guān)閉socket;
二、Qt中的tcp(這里只展示代碼)
開(kāi)始前在項(xiàng)目的.pro文件中加入這個(gè)network

1、tcpsever
tcpsever.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QNetworkInterface>//網(wǎng)絡(luò)信息
#include <QHostAddress>//id地址
#include <QTcpServer> //tcp協(xié)議
#include <QTcpSocket> //socket套接字
#include <QDebug>
#include <QMessageBox>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_listen_clicked();
void on_pushButton_send_clicked();
void newconnectslot();//連接
void readyRead_Slot();//讀取信息
void disconnected_Slot();//斷開(kāi)
private slots:
QString list_all_IPV4();
private:
Ui::Widget *ui;
//2、設(shè)置服務(wù)端和接收客戶(hù)端的對(duì)象
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
};
#endif // WIDGET_Htcpsever.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//3、創(chuàng)建服務(wù)器對(duì)象
tcpSocket=NULL;
tcpServer=new QTcpServer(this);
//5、有客戶(hù)端連接服務(wù)器發(fā)送信號(hào)
connect(tcpServer,
SIGNAL(newConnection()),
this,
SLOT(newconnectslot()));
QMessageBox::information(this,"本機(jī)聯(lián)網(wǎng)端口顯示",this->list_all_IPV4());
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_listen_clicked()
{
//4、開(kāi)始監(jiān)聽(tīng)
QString sever_Address = ui->lineEdit_address->text();
quint16 port = ui->lineEdit_port->text().toInt();
QHostAddress host = QHostAddress(sever_Address);
if(!tcpServer->isListening()){
//監(jiān)聽(tīng)綁定的ip地址
if(!tcpServer->listen(host,port))
{
qDebug()<<tcpServer->errorString();
return;
}else{
qDebug()<<"監(jiān)聽(tīng)成功";
ui->pushButton_listen->setText("停止監(jiān)聽(tīng)");
}
}else{
tcpServer->close();
ui->pushButton_listen->setText("開(kāi)始監(jiān)聽(tīng)");
}
}
QString Widget::list_all_IPV4(){
QString str;
QList<QHostAddress> list=QNetworkInterface::allAddresses(); //獲取本機(jī)的所有網(wǎng)卡的ip地址
foreach (QHostAddress address, list)
{
if(address.isNull())
continue;
QAbstractSocket::NetworkLayerProtocol portocol=address.protocol();
//只提取IPv4地址
if(portocol!=QAbstractSocket::IPv4Protocol)
continue;
str = str +'\n\t'+address.toString() + '\n\t\t';
}
return str;
};
void Widget::newconnectslot(){
//6、接受客戶(hù)端
tcpSocket = tcpServer->nextPendingConnection();
QString client_Info = "客戶(hù)端:" + tcpSocket->peerAddress().toString()
+" "+
"端口號(hào):" + QString::number(tcpSocket->peerPort());
ui->textBrowser_clientInfo->setText(client_Info);
//發(fā)送信號(hào)和讀取關(guān)聯(lián)
connect(tcpSocket,
SIGNAL(readyRead()),
this,
SLOT(readyRead_Slot()));
//斷開(kāi)信號(hào)關(guān)聯(lián)客戶(hù)端
connect(tcpSocket,
SIGNAL(disconnected()),
this,
SLOT(disconnected_Slot()));
};
void Widget::on_pushButton_send_clicked()
{
if(tcpSocket != nullptr)
{
if(tcpSocket->isWritable())
{
QString send = ui->plainTextEdit_sendInfo->toPlainText();
QByteArray sendarr = send.toLocal8Bit();//本地字符集與Unicode的轉(zhuǎn)換
tcpSocket->write(sendarr);
}
}
}
void Widget::readyRead_Slot(){
if(tcpSocket != nullptr)
{
if(tcpSocket->isReadable())
{
QByteArray recvAll = tcpSocket->readAll();//將數(shù)據(jù)全部讀取
QString str = str.fromLocal8Bit(recvAll.data());
ui->textBrowser_recv->append(str);
}
}
};
void Widget::disconnected_Slot(){
QMessageBox::information(this,"Client Close Signal","有客戶(hù)離開(kāi)");
};2、tcpclient
tcpclient,h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QNetworkInterface>//網(wǎng)絡(luò)信息
#include <QHostAddress>//id地址
#include <QTcpServer> //tcp協(xié)議
#include <QTcpSocket> //socket套接字
#include <QDebug>
#include <QMessageBox>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_listen_clicked();
void on_pushButton_send_clicked();
void readyRead_Slot();//讀取信息
void disconnected_Slot();//斷開(kāi)
private:
Ui::Widget *ui;
QTcpSocket *client;
bool socket_state;
};
#endif // WIDGET_Htcpclient.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
client = new QTcpSocket(this);
socket_state = false;
connect(client,
SIGNAL(disconnected()),
this,
SLOT(disconnected_Slot()));
connect(client,
SIGNAL(readyRead()),
this,
SLOT(readyRead_Slot()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_listen_clicked()
{
QString ipAddress = ui->lineEdit_address->text();
qint16 port = ui->lineEdit_port->text().toInt();
if(!socket_state)
{
client->connectToHost(ipAddress,port);
if(client->waitForConnected(3000)){//等待3s,連不上會(huì)返回假
ui->pushButton_listen->setText("斷開(kāi)連接");
socket_state = true;
}else{
qDebug()<<client->errorString();
return;
}
}else{
client->close();
QMessageBox::information(this,"消息提示","已經(jīng)離開(kāi)!",QMessageBox::Yes);
ui->pushButton_listen->setText("連接");
socket_state = false;
}
}
void Widget::readyRead_Slot(){
QByteArray data=client->readAll();
QString str=str.fromLocal8Bit(data.data());
ui->textBrowser_recv->append(str);
};
void Widget::disconnected_Slot(){
qDebug()<<"離開(kāi)";
}
void Widget::on_pushButton_send_clicked()
{
QString datastr = ui->plainTextEdit_sendInfo->toPlainText();
QByteArray da = datastr.toLocal8Bit();
if(client->isOpen() && client->isValid()){
client->write(da);
}
}
三、QT中的Udp
初始操作同TCP操作
udp_test.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
//1、包含相關(guān)的頭文件
#include <QHostAddress>
#include <QUdpSocket>
#include <QDebug>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButtonSend_clicked();
void readyReadSlot();
void on_pushButtonCLose_clicked();
private:
Ui::Widget *ui;
//2、定義udp對(duì)象
QUdpSocket *udpSocket;
};
#endif // WIDGET_Hudp_test.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//3、創(chuàng)建對(duì)象
udpSocket=new QUdpSocket(this);
//4、關(guān)聯(lián)讀取的信號(hào)與槽
connect(udpSocket,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButtonSend_clicked()
{
udpSocket->writeDatagram(ui->plainTextEdit_sendInfo->toPlainText().toLocal8Bit(),//內(nèi)容
QHostAddress(ui->lineEditIp->text()),//發(fā)送ip
ui->lineEditPort->text().toInt());//發(fā)送的地址
}
void Widget::on_pushButtonCLose_clicked()
{
udpSocket->bind(ui->lineEditPort_2->text().toInt());
}
void Widget::readyReadSlot(){
quint64 size = udpSocket->bytesAvailable();//讀取發(fā)過(guò)來(lái)的消息大小
QByteArray ba;
ba.resize(size);
QHostAddress address;
quint16 port;
udpSocket->readDatagram(ba.data(),size,&address,&port);
QString str = QString::fromLocal8Bit(ba.data());
ui->textEdit_recvInfo->append(str);
}
到此這篇關(guān)于Qt中網(wǎng)絡(luò)編程的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Qt網(wǎng)絡(luò)編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言中isalnum()函數(shù)和isalpha()函數(shù)的對(duì)比使用
這篇文章主要介紹了C語(yǔ)言中isalnum()函數(shù)和isalpha()函數(shù)的對(duì)比使用,都可以判斷是否為字母但isalnum的判斷還包括數(shù)字,需要的朋友可以參考下2015-08-08
C++多態(tài)虛析構(gòu)和純虛析構(gòu)的實(shí)現(xiàn)
本文主要介紹了C++多態(tài)虛析構(gòu)和純虛析構(gòu)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09
C++如何實(shí)現(xiàn)簡(jiǎn)單的計(jì)時(shí)器詳解
因?yàn)樽罱e著無(wú)聊就想著要不用C++寫(xiě)點(diǎn)什么東西,仔細(xì)想了想其實(shí)自己的C++學(xué)的也不怎么好,寫(xiě)個(gè)簡(jiǎn)單的計(jì)時(shí)器吧!所以下面這篇文章主要介紹了利用C++如何實(shí)現(xiàn)簡(jiǎn)單的計(jì)時(shí)器,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-01-01
C++詳細(xì)講解模擬實(shí)現(xiàn)位圖和布隆過(guò)濾器的方法
位圖(bitset)是一種常用的數(shù)據(jù)結(jié)構(gòu),常用在給一個(gè)很大范圍的數(shù),判斷其中的一個(gè)數(shù)是不是在其中。在索引、數(shù)據(jù)壓縮方面有很大的應(yīng)用。布隆過(guò)濾器是由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。布隆過(guò)濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中2022-06-06
利用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易版掃雷
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易版掃雷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-02-02
詳解C++ 拷貝構(gòu)造函數(shù)和賦值運(yùn)算符
本文主要介紹了拷貝構(gòu)造函數(shù)和賦值運(yùn)算符的區(qū)別,以及在什么時(shí)候調(diào)用拷貝構(gòu)造函數(shù)、什么情況下調(diào)用賦值運(yùn)算符。最后,簡(jiǎn)單的分析了下深拷貝和淺拷貝的問(wèn)題。有需要的朋友可以看下2016-12-12

