一、UDP客户端
widget.h:
套接字头文件 槽函数 套接字
#include <QUdpSocket>
private slots:
void on_pb_send_clicked();
void on_pb_clear_clicked();
private:
QUdpSocket *socket;
widget.cpp:
//1.new套接字 别忘了指定父对象this
socket = new QUdpSocket(this);
//2.连接socket信号 与 槽函数(拉姆达表达式)
//2.1 读取并显示到接收区 readyread--表示有对端的数据到达
connect(socket,&QUdpSocket::readyRead,[=](){
while(socket->hasPendingDatagrams()){ //循环读取
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());//根据接收数据的长度调整字节数组的长度
socket->readDatagram(datagram.data(),datagram.size());//读数据
ui->te_recv->append(datagram);//显示到接收区
}
});
//3.发送数据按钮
//3.1判空(地址、端口、内容)
//3.2把文本编辑器的内容转化并写入套接字
void Widget::on_pb_send_clicked()
{
if(ui->le_ip->text().isEmpty() ||
ui->le_port->text().isEmpty()){
QMessageBox::information(this,"服务器地址或端口错误!","服务器地址和端口不能为空!");
return;
}
if(ui->te_send->toPlainText().isEmpty()){
QMessageBox::information(this,"发送内容错误!","发送内容不能为空!");
return;
}
//发送数据到服务器的地址和端口
//文本编辑器的纯文本 latin..............
if(socket->writeDatagram(ui->te_send->toPlainText().toLocal8Bit(),//toLatin1()可能只支持英文
QHostAddress(ui->le_ip->text()),
ui->le_port->text().toUShort()) == -1){
qDebug()<<"客户端发送数据失败";
}
else
qDebug()<<"客户端发送数据成功";
}
void Widget::on_pb_clear_clicked()
{
ui->te_recv->clear();
}
二、UDP服务器
widget.h:
头文件
转到槽函数
对象
#include <QUdpSocket>
private slots:
void on_pb_send_clicked();
void on_pb_clear_clicked();
private:
Ui::Widget *ui;
QUdpSocket *socket;
QHostAddress ip;//对端的IP地址
quint16 port;//对端的端口号
wifget.cpp
1.new一个套接字
2.bind绑定本机任意IP地址,绑定端口
3.连接信号与槽函数
3.1 循环读取数据并显示到接收区
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("UDP服务器");
socket = new QUdpSocket(this);
socket->bind(QHostAddress::AnyIPv4,8848); //绑定!!本机任意IPv4地址和8848端口
//连接信号与槽函数
connect(socket,&QUdpSocket::readyRead,[=](){
//只要还有待处理的数据,就不断读取
while(socket->hasPendingDatagrams()){ //haspendingdatagrams返回布尔值
QByteArray datagram;
//根据接收数据的大小调整字节数组的大小
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),
&ip,&port);//获得数据的同时,保存IP和端口!!!
//显示到接收区
ui->te_recv->append(QString::fromLocal8Bit(datagram));//转换
ui->pb_send->setEnabled(true);//激活发送按钮
}
});
}
4.发送按钮
4.1判空
4.2发送
void Widget::on_pb_send_clicked()
{
if(ui->te_send->toPlainText().isEmpty()) //文本编辑框没有text()
{
QMessageBox::warning(this,"发送数据错误!","发送数据不能为空");
return;
}
if(socket->writeDatagram(ui->te_send->toPlainText().toLocal8Bit(),
ip,port) == -1){
qDebug()<<"服务器发送数据失败";
}
else{
qDebug()<<"服务器发送数据成功";
}
}
void Widget::on_pb_clear_clicked()
{
ui->te_recv->clear();
}
三、TCP客户端
widget.h:
头文件、转到槽函数、套接字
widget.cpp:
#include <QHostAddress>
构造函数:
socket = new QTcpSocket(this);//别忘记设置父对象this
//连接信号与槽函数
//1.socket 发送 连接成功 的信号 connected
connect(socket,&QTcpSocket::connected,[=](){
ui->pb_connect->setText("断开连接");
ui->pb_send->setEnabled(true);
});
//2.socket 发送 连接断开 的信号 disconnected
connect(socket,&QTcpSocket::disconnected,[=](){
ui->pb_connect->setText("连接");
ui->pb_send->setEnabled(false);
});
//3.socket 发送 数据就绪 的信号 readtRead
connect(socket,&QTcpSocket::readyRead,[=](){
QByteArray data;
data = socket->readAll(); //socket->readAll()返回QByteArray
if(!data.isEmpty()){
ui->te_recv->append(QString::fromLocal8Bit(data));//QByteArray转化为QString放到接收区
}
});
//4.socket 发送 错误 的信号error 模板类Qoverload的使用QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error)
connect(socket,QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),[=](QAbstractSocket::SocketError socketError){
qDebug()<< "socket error = "<<socketError;//打印连接失败的信息
if(socket->state() != QAbstractSocket::ConnectedState){
socket->connectToHost(QHostAddress(ui->le_ip->text()),ui->le_port->text().toUShort());
}//主动向服务器发起连接.这样就只需要点一次连接
});
连接按钮(连接上了变成断开连接)
//判空、发送连接请求
void Widget::on_pb_connect_clicked()
{
if(ui->pb_connect->text() == "连接"){
QString ip = ui->le_ip->text();
QString port = ui->le_port->text();
if(ip.isEmpty() || port.isEmpty()){
QMessageBox::warning(this,"连接错误!","服务器IP或端口不能为空!");
return;
}
//4.向 服务器 发起 连接请求
socket->connectToHost(QHostAddress(ip),port.toUShort());
}
else
socket->close();
}
发送按钮
//判空、发送
void Widget::on_pb_send_clicked()
{
if(ui->te_send->toPlainText().isEmpty()){
QMessageBox::information(this,"发送内容错误!","发送内容不能为空!");
return;
}
//5.发送数据到对端
if (socket->write(ui->te_send->toPlainText().toLocal8Bit()) == -1){
qDebug()<<"客户端发送数据失败";
}
else{
qDebug()<<"客户端发送数据成功";
}
}
void Widget::on_pb_clear_clicked()
{
ui->te_recv->clear();
}
四、TCP服务器
widget.h: 两个头文件 一个用于TCP连接 一个用于通信的套接字
#include <QTcpSocket>
#include <QTcpServer> //头文件
private slots:
void on_pb_send_clicked();
void on_pb_clear_clicked();
private:
Ui::Widget *ui;
QTcpServer *server;//同于TCP连接
QTcpSocket *socket;//用于通信的套接字
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("TCP服务器");
server = new QTcpServer(this);
//socket = new QTcpSocket(this); 服务端的socket是建立连接后返回的(同网络编程)
//1.监听
server->listen(QHostAddress::AnyIPv4,8848);//监听本地地址和端口
//连接服务器的信号与槽函数
//2.server 发送的 新的连接 已经建立 的信号
connect(server,&QTcpServer::newConnection,[=](){
while(server->hasPendingConnections()){//连接建立好了
qDebug()<<"incoming connection";
//获取一个新的通信套接字
socket = server->nextPendingConnection();
ui->pb_send->setEnabled(true);
//连接 通信套接字的 信号与槽函数
//socket通信套接字 发送的 连接断开 的信号
connect(socket,&QTcpSocket::disconnected,[=](){
ui->pb_send->setEnabled(false);
});
connect(socket,&QTcpSocket::readyRead,[=](){
QByteArray data;
data = socket->readAll(); //返回QByteArray
ui->te_recv->append(QString::fromLocal8Bit(data));//转换
});
}
qDebug()<<"incoming connection 2";
});
}
Widget::~Widget(){delete ui;}
void Widget::on_pb_send_clicked()
{
if(ui->te_send->toPlainText().isEmpty()){
QMessageBox::warning(this,"发送内容错误","发送内容不能为空");
return;
}
//使用utf8的编码,支持更多的语言
if (-1 == socket->write(ui->te_send->toPlainText().toLocal8Bit())){
qDebug()<<"TCP服务器发送数据失败";
}
else
qDebug()<<"TCP服务器发送数据成功";
}
void Widget::on_pb_clear_clicked()
{
ui->te_recv->clear();
}
目前处在硬记步骤和函数的状态 也不好改进质量