客户端:
功能:
连接:获取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);