概念
TCP/IP协议在一定程度上参考了OSI的体系结构。OSI模型共有七层,从下到上分别是物理层、数据链路层、网络层、运输层、会话层、表示层和应用层。但是这显然是有些复杂的,所以在TCP/IP协议中,它们被简化为了四个层次。来自百度
Tcp通信的特点
1 面向连接:是指发送数据之前必须在两端建立连接,“三次握手” 2.提供可靠的服务:Tcp通过校验和,使用重传控制、流量控制和拥塞控制 3.每条传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式 4…面向字节流 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。 套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
效果
QT提供了QTcpSocket类,可以方便的实现一个客户端; .h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnClearRec_clicked();
void receiveData();
void ReadError(QAbstractSocket::SocketError);
void on_btn_Connect_clicked();
void on_btn_DisConnect_clicked();
void on_btnSend_clicked();
private:
Ui::Widget *ui;
QTcpSocket *m_Socket = nullptr;
};
#endif
.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QNetworkProxy>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->btn_DisConnect->setEnabled(false);
m_Socket = new QTcpSocket(this);
m_Socket->setProxy(QNetworkProxy::NoProxy);
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(receiveData()));
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(ReadError(QAbstractSocket::SocketError)));
connect(m_Socket, &QTcpSocket::connected,[&]{
ui->textEdit_Receive->append(QStringLiteral("连接成功"));
});
connect(m_Socket, &QTcpSocket::disconnected,[&]{
ui->textEdit_Receive->append(QStringLiteral("断开连接"));
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnClearRec_clicked()
{
ui->textEdit_Receive->clear();
}
void Widget::receiveData()
{
QByteArray buffer = m_Socket->readAll();
if(!buffer.isEmpty())
{
ui->textEdit_Receive->append(buffer);
}
}
void Widget::ReadError(QAbstractSocket::SocketError)
{
m_Socket->disconnectFromHost();
ui->textEdit_Receive->append(m_Socket->errorString());
}
void Widget::on_btn_Connect_clicked()
{
m_Socket->connectToHost(ui->lineEditI_Ip->text(), ui->lineEdit_Port->text().toInt());
if (m_Socket->waitForConnected(1000))
{
ui->btn_Connect->setEnabled(false);
ui->btn_DisConnect->setEnabled(true);
}
}
void Widget::on_btn_DisConnect_clicked()
{
m_Socket->disconnectFromHost();
if (m_Socket->state() == QAbstractSocket::UnconnectedState
|| m_Socket->waitForDisconnected(1000))
{
ui->btn_Connect->setEnabled(true);
ui->btn_DisConnect->setEnabled(false);
}
}
void Widget::on_btnSend_clicked()
{
QString data = ui->textEdit_Send->toPlainText();
if(data != "")
{
m_Socket->write(data.toLatin1());
}
}
QT提供了QTcpServer类,可以方便的实现一个服务端; .h
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
//接受信息
void receiveData();
void on_btn_Connect_clicked();
void on_btn_DisConnect_clicked();
void on_btnSend_clicked();
private:
Ui::Widget *ui;
//服务器
QTcpServer *m_tcpServer = nullptr;
//套接字
QTcpSocket *m_tcpSocket = nullptr;
};
.cpp文件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_tcpServer = new QTcpServer(this);
m_tcpSocket = new QTcpSocket(this);
//设置代理模式
m_tcpSocket->setProxy(QNetworkProxy::NoProxy);
//每当有新的连接可用时,就会发出此信号。
connect(m_tcpServer, &QTcpServer::newConnection, this,[&]{
m_tcpSocket = m_tcpServer->nextPendingConnection();
//该信号在设备当前读取通道中每次有新的数据可用时发出。
connect(m_tcpSocket, &QTcpSocket::readyRead, this, &Widget::receiveData);
//当套接字断开连接时发出此信号。
connect(m_tcpSocket, &QTcpSocket::disconnected,this,[&]{
ui->textEdit_Rec->append(QStringLiteral("断开连接"));
});
});
//获取本地IP
ui->lineEditI_Ip->setText(QNetworkInterface().allAddresses().at(1).toString());
}
Widget::~Widget()
{
delete ui;
}
void Widget::receiveData()
{
//从设备读取所有剩余的数据,并将其作为字节数组返回。
QByteArray buffer = m_tcpSocket->readAll();
ui->textEdit_Rec->append(buffer);
}
void Widget::on_btn_Connect_clicked()
{
//服务器监听传入的连接。当port为0时,
//系统自动选择端口。如果address为QHostAddress::Any,服务器将监听所有网络接口。
bool ok = m_tcpServer->listen(QHostAddress::Any, ui->lineEdit_Port->text().toInt());
if(ok)
{
ui->btn_Connect->setEnabled(false);
ui->btn_DisConnect->setEnabled(true);
}
}
void Widget::on_btn_DisConnect_clicked()
{
//关闭socket
m_tcpSocket->disconnectFromHost();
//等待直到套接字断开连接。
//如果连接已经断开,这个函数返回true;否则返回false。
bool ok = m_tcpSocket->waitForDisconnected(1000);
ui->btn_DisConnect->setEnabled(false);
ui->btn_Connect->setEnabled(true);
//不再监听端口
m_tcpServer->close();
m_tcpSocket->destroyed();
}
void Widget::on_btnSend_clicked()
{
QString data = ui->textEdit_Send->toPlainText();
if(data != "")
{
//发送数据
m_tcpSocket->write(data.toLatin1());
}
}
|