客户端:
功能:
连接:获取ip地址和端口号,并连接 取消:关闭窗口
工程文件加上
QT=+=core gui network
相关类与函数
QTcpSocket类:(需要被包含)
connectToHost() 连接。参数:QHostAdress地址对象(可用QString初始化),端口号(16位短整型)(QString自带进制转换,如ip.toshort)
连接成功后会发出一个信号:&QTcpSocket::connected
连接异常也会发出一个信号:&QTcpSocket::disconnected
peerAddress();获取客户端地址
peerAddress的子函数toString():将其转化位字符串
peerPort():获取客户端端口号(并非服务器端口)
write():参数:QByteArray ,可用append拼接,发送后会出现&QTcpSocket::readyread信号
QHostAddress类:(需要被包含)
其他函数:
(QTcpSocket * )sender();获取信号的发送者并强制转为QTcpSocket指针
服务器:
相关类与函数:
QTcpServer类:
listen():监听网卡,参数QHostAdress::AnyIPv4,端口号
如果有信号,会发出QTcpServer::newConnection信号
nextPendingConnection() 建立TCP连接,返回QTcpSocket类型
实现服务器与客户端连接
在widget构造函数中监听网卡ip,等待请求,收到信号后与客户端建立连接
注意,必须使用127开头的地址
127.0.0.1 地址称为本地回环地址,是一种特殊的网络地址,用于让单独的计算机进行自我回路测试和通信。 这个地址在 IP 协议中被定义为环回地址。 在网络设备中,网络接口上的 127.0.0.1 地址本质上是本机对自己的网络地址。
通信
打开其他窗口:新建qt->设计师...,在客户端创建新的窗口类chat
this->hide()隐藏窗口
创建新窗口对象时要用堆空间创建,也即是指针形式,这样申请的内存不会被销毁,
widget在连接成功后隐藏当前窗口,并打开新窗口chat,与打开widget窗口类似
chat *k=new chat(SOCKET);
k->show();
要将socket信息传到新窗口中,所以类chat中要有参数,并在chat构造函数中初始化
QTcpSocket *s
在新窗口中,使用socket中的write发送信息,参数是QByteArray类型
在服务器中连接后再connect一个新的信号与曹:
&QTcpSocket::readyRead
&Widget::data_resslot
在槽函数中要注意变量的范围,如果QTcpSocket指针是内部变量,则需要使用
(QTcpSocket*)sender();
将其转化为QTcpSocket类型指针,再用readAll读取所有发送的数据。
服务器代码:
chat.h
#ifndef CHAT_H
#define CHAT_H
#include <QWidget>
#include <QTcpSocket>
namespace Ui {
class chat;
}
class chat : public QWidget
{
Q_OBJECT
public:
explicit chat(QTcpSocket *s,QWidget *parent = nullptr);
~chat();
private slots:
void on_clearButton_clicked();
void on_sendButton_2_clicked();
private:
Ui::chat *ui;
QTcpSocket *SOCKET;
};
#endif // CHAT_H
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QDebug>
#include <QMessageBox>
#include <chat.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 on_cancelButton_2_clicked();
void on_connectButton_clicked();
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QTcpSocket *SOCKET;
};
#endif // WIDGET_H
chat.cpp
#include "chat.h"
#include "ui_chat.h"
chat::chat(QTcpSocket *s,QWidget *parent) :
QWidget(parent),
ui(new Ui::chat)
{
ui->setupUi(this);
SOCKET=s;
}
chat::~chat()
{
delete ui;
}
void chat::on_clearButton_clicked()
{
ui->lineEdit->clear();
}
void chat::on_sendButton_2_clicked()
{
QString text1=ui->lineEdit->text();
QByteArray ba;
ba.append(text1);
//write只能发送QByteArray类型数据
SOCKET->write(ba);
}
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
SOCKET=new QTcpSocket;
//成功/异常警告
connect(SOCKET,&QTcpSocket::connected,[this]()
{
QMessageBox::information(this,"提示","连接成功");
this->hide();
chat *k=new chat(SOCKET);
k->show();
});
connect(SOCKET,&QTcpSocket::disconnected,[this]()
{
QMessageBox::warning(this,"警告","连接异常");
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_cancelButton_2_clicked()
{
this->close();
}
void Widget::on_connectButton_clicked()
{
//获取ip与端口号
QString com1=ui->COMlineEdit_2->text();
QString ip1=ui->IPlineEdit->text();
if(com1.isEmpty()||ip1.isEmpty())
{
QMessageBox::warning(this,"警告","请输入ip地址和端口号");
}
//开始连接
SOCKET->abort();
SOCKET->connectToHost(QHostAddress(ip1),com1.toShort());
}
void Widget::on_pushButton_clicked()
{
qDebug()<<"disconnect";
SOCKET->disconnectFromHost();
}
服务器代码:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
#define TCPCOM 8000
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void serverslot();
void on_check_clicked();
void data_resslot();
private:
Ui::Widget *ui;
QTcpServer *SERVER;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
SERVER=new QTcpServer;
SERVER->listen(QHostAddress::Any,TCPCOM);
qDebug()<<TCPCOM;
connect(SERVER,&QTcpServer::newConnection,this,&Widget::serverslot);
}
Widget::~Widget()
{
delete ui;
}
void Widget::serverslot()
{
QTcpSocket *SOCKET1;
SOCKET1=SERVER->nextPendingConnection();
QHostAddress ip1=SOCKET1->peerAddress();
quint16 com1=SOCKET1->peerPort();
ui->comlineEdit->setText(QString::number(com1));
ui->iplineEdit_2->setText(ip1.toString());
QMessageBox::information(this,"提示","连接成功");
connect(SOCKET1,&QTcpSocket::readyRead,this,&Widget::data_resslot);
}
void Widget::on_check_clicked()
{
if(SERVER->isListening())
{
qDebug()<<"IS LISTENING";
}
}
void Widget::data_resslot()
{
QTcpSocket *Socket=(QTcpSocket*)sender();
ui->datalineEdit->setText(Socket->readAll());
}
结果:
多线程
在服务器中启用多线程,即可接收多个客户端的连接。
相关类与函数
在文件中添加c++类,在继承中继承QThread,添加后多了.h和.cpp文件
QThread类,需要包含
start()打开线程
虚函数run():在run里连接信号与槽,线程处理函数
自定义信号
在类中定义,和private同级,在信号传递时可以附加参数
signals:
void sendtowidget(QByteArray ba);
在需要发出信号的地方加上即可,最后在widget中连接信号与槽
QByteArray ba=socket->readall();
emit sendtowidget(ba);