话不多说,先一睹芳颜
项目目录
一.服务端
1.界面设计
2.服务端获取主机地址
将主机地址放在了一个容器中.
3.初始化服务端
当有新的客户端请求连接时,会发出newConnection()的信号.
4.服务端开启监听
注意listen函数的参数类型,要转换一下.
5.套接字socket
当有客户端请求连接后,我们需要套接字来作为服务端和客户端的接口.
6.服务端的读写
当有信息可以读的时候,我们就可以来读信息.
发送信息用write ,注意要用utf8编码.
7.socket的其他信号的槽函数
8.服务端关闭监听
9.完整代码
mainwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostInfo>
#include <QHostAddress>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButtonOpen_clicked();
void on_pushButtonClose_clicked();
void onNewConnection();
void onReadyRead();
void onConnected();
void onDisconnected();
void onStateChanged(QAbstractSocket::SocketState socketState);
private:
Ui::MainWindow *ui;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QStringList addrs;
QLabel *labelState;
void initTCPServer();
void getHostAddress();
void sendMsg(const QString&str);
void initLabel();
};
#endif // MAINWINDOW_H
mainwindow.cpp
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initTCPServer();
initLabel();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButtonOpen_clicked()
{
getHostAddress();
int i=rand()%addrs.count();
QString addr=addrs.at(i);
ui->labelIP->setText("服务器地址:"+addr);
quint16 port=rand()%9000+8000;
ui->labelPort->setText("服务器端口:"+QString::number(port));
QHostAddress IP(addr);
tcpServer->listen(IP,port);
ui->pushButtonOpen->setEnabled(false);
ui->pushButtonClose->setEnabled(true);
ui->labelIP->show();
ui->labelPort->show();
}
void MainWindow::on_pushButtonClose_clicked()
{
if(tcpServer->isListening())
{
tcpServer->close();
ui->pushButtonOpen->setEnabled(true);
ui->pushButtonClose->setEnabled(false);
ui->labelIP->hide();
ui->labelPort->hide();
}
}
void MainWindow::onNewConnection()
{
tcpSocket=tcpServer->nextPendingConnection();
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
connect(tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState socketState)),
this,SLOT(onStateChanged(QAbstractSocket::SocketState)));
onStateChanged(tcpSocket->state());
}
void MainWindow::onReadyRead()
{
QString str;
while(tcpSocket->canReadLine())
{
QString read=tcpSocket->readLine();
//qDebug()<<tcpSocket->readLine()<<endl;
if(read=="人有悲欢离合\n")
{
str="月有阴晴圆缺";
sendMsg(str);
}
else if(read=="此情可待成追忆\n")
{
str="只是当时已惘然";
sendMsg(str);
}
else if(read=="宁教我负天下人\n")
{
str="休教天下人负我";
sendMsg(str);
}
else
{
str="喂喂喂!你在说啥?";
sendMsg(str);
}
}
}
void MainWindow::onConnected()
{
labelState->setText("连接状态: 已连接");
}
void MainWindow::onDisconnected()
{
labelState->setText("连接状态: 已断开连接");
tcpSocket->deleteLater();//之后删
}
void MainWindow::onStateChanged(QAbstractSocket::SocketState socketState)
{
switch (socketState) {
case QAbstractSocket::UnconnectedState:
labelState->setText("连接状态: 已断开连接");
break;
case QAbstractSocket::ConnectedState:
labelState->setText("连接状态: 已连接");
break;
}
}
void MainWindow::initTCPServer()
{
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}
void MainWindow::getHostAddress()
{
QHostInfo hostInfo =QHostInfo::fromName(QHostInfo::localHostName());
QList<QHostAddress> lists=hostInfo.addresses();
for(int i=0;i<lists.count();i++)
{
QHostAddress address=lists[i];
if(address.protocol()==QAbstractSocket::IPv4Protocol)
{
addrs.append(address.toString());
}
}
}
void MainWindow::sendMsg(const QString &str)
{
QByteArray msg= str.toUtf8();
msg.append('\n');
tcpSocket->write(msg);
}
void MainWindow::initLabel()
{
labelState=new QLabel("连接状态: 未连接");
ui->statusbar->addWidget(labelState);
ui->labelIP->hide();
ui->labelPort->hide();
QLinearGradient gradient(0,0,ui->label->width(),ui->label->height());
gradient.setColorAt(0,Qt::green);
gradient.setColorAt(1,Qt::blue);
QPalette palette;
palette.setBrush(QPalette::WindowText,QBrush(gradient));
ui->label->setPalette(palette);
}
二.客户端
1.界面设计
2.套接字的初始化
3.连接服务器
如果连接成功,就弹出我们的发送框.
这里的tcpSocketGet是在对话框中获取到套接字的,然后可以来发送信息.
4.界面设计师类
5.客户端的读写
读到的信息添加到对话框中.
发送信息:
发送的信息都添加了一个换行符,因为这样可以判断一行,然后对方进行读取.
6.客户端关闭连接
7.完整代码
mainwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QLabel>
#include <dialog.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButtonConnect_clicked();
void on_pushButtonDisConnect_clicked();
void onConnected();
void onDisconnected();
void onReadyRead();
private:
Ui::MainWindow *ui;
QTcpSocket*tcpSocket;
QLabel* labState;
QLabel* labIP;
QLabel* labPort;
Dialog* chat;
void initTCPSocket();
void intitLabel();
};
#endif // MAINWINDOW_H
mainwindow.cpp
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initTCPSocket();
intitLabel();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initTCPSocket()
{
tcpSocket=new QTcpSocket(this);
connect(tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}
void MainWindow::intitLabel()
{
labState=new QLabel(this);
labState->setMinimumWidth(100);
labPort=new QLabel(this);
labPort->setMinimumWidth(100);
labIP=new QLabel(this);
this->statusBar()->addWidget(labState);
this->statusBar()->addWidget(labPort);
this->statusBar()->addWidget(labIP);
}
void MainWindow::on_pushButtonConnect_clicked()
{
QString addr=ui->lineEditAddr->text();
QString port=ui->lineEditProt->text();
if(addr==NULL||port==NULL)return;
QHostAddress IP(addr);
tcpSocket->connectToHost(IP,port.toInt());
}
void MainWindow::on_pushButtonDisConnect_clicked()
{
if(tcpSocket->state()==QAbstractSocket::ConnectedState)
{
tcpSocket->disconnectFromHost();
chat->close();
}
}
void MainWindow::onConnected()
{
labState->setText("连接状态: 已连接");
labPort->setText("服务器端口: "+QString::number(tcpSocket->peerPort()));
labIP->setText("服务器IP: "+tcpSocket->peerAddress().toString());
chat=new Dialog(this);
//this->hide();
chat->tcpSocketGet(tcpSocket);
chat->show();
}
void MainWindow::onDisconnected()
{
labState->setText("连接状态: 已断开连接");
labState->clear();
labIP->clear();
labPort->clear();
}
void MainWindow::onReadyRead()
{
while(tcpSocket->canReadLine())
{
QString str=tcpSocket->readLine();
chat->setMsg(str);
}
}
dialog.h
cpp
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QTcpSocket>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
void setMsg(const QString&str);
void tcpSocketGet(QTcpSocket *tcpSocket);
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
QTcpSocket*tcpSocket;
protected:
void closeEvent(QCloseEvent*event);
};
#endif // DIALOG_H
dialog.cpp
cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QHostAddress>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
ui->plainTextEdit->setReadOnly(true);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::setMsg(const QString &str)
{
ui->plainTextEdit->appendPlainText("服务器: "+str);
}
void Dialog::tcpSocketGet(QTcpSocket *tcpSocket)
{
this->tcpSocket=tcpSocket;
//qDebug()<<this->tcpSocket->peerAddress();
}
void Dialog::on_pushButton_clicked()
{
QString str=ui->lineEdit->text();
QByteArray msg=str.toUtf8();
msg.append('\n');
tcpSocket->write(msg);
ui->plainTextEdit->appendPlainText("客户: "+str);
ui->lineEdit->clear();
ui->lineEdit->setFocus();
}
void Dialog::closeEvent(QCloseEvent *event)
{
if(tcpSocket->state()==QAbstractSocket::ConnectedState)
{
tcpSocket->disconnectFromHost();
}
event->accept();
}
三.结语
当然我这里只是稍微的演示一下,你也可以自己在服务端做手脚,自己发送信息也可以.
念头通达,现在应该算是炼气期1层.