本次要实现的是一个基于TCP的聊天程序,客户端输入服务器端的IP地址和端口号,在客户端发送消息,服务器端可以接收,服务器端发送消息,客户端也可以接收
基于TCP的半双工通信
先写服务端代码
头文件:dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QTcpServer>
#include <QDateTime>
#include <QTcpSocket>
#include <QTextStream>
#include <QMessageBox>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpServer * server;// 管理类对象
QTcpSocket * socket = NULL;// 连接类对象,只能连接一个对象,多个对象连接一个服务器需要创建QList类
private slots:
void newConnSlot();// 新连接建立的槽函数
void disConnSlot();// 网络连接断开的槽函数
void readyReadSlot();// 读取消息的槽函数
void btnSndMsgClickedSlot();// 发送信息的槽函数
};
#endif // DIALOG_H
源文件:dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
setWindowFlags(Qt::WindowStaysOnTopHint);// 设置窗口标记为顶层
server = new QTcpServer(this);// 创建管理类对象
connect(server,SIGNAL(newConnection()),this,SLOT(newConnSlot()));// 连接服务器通知的信号槽
// 服务器开启监听,等待客户主动发起连接
// 参数1:监听来自于哪个IP地址的请求,默认值Any:不限制IP地址,QHostAddress类是IP地址的封装类。
// 参数2:服务器端口号
server->listen(QHostAddress::Any,8877);
}
Dialog::~Dialog()
{
if(server->isListening()){// 如果还在监听,则关闭
server->close();
}
delete ui;
}
void Dialog:: newConnSlot()
{
if(socket != NULL){// 如果不是第一次连接服务器,先踢掉之前的连接
socket->close();
}
socket = server->nextPendingConnection();// 拿到与客户端进行连接的QTcpSocket对象
connect(socket,SIGNAL(disconnected()),this,SLOT(disConnSlot()));// 建立断链通知的信号槽
connect(socket,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));// 建立读取消息的信号槽
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(btnSndMsgClickedSlot()));// 建立发送消息的信号槽
QString ip = socket->peerAddress().toString();// 拿到对面客户端的IP与端口号
qint16 port = socket->peerPort();
QString time = QDateTime::currentDateTime().toString("hh:mm:ss");// 输出信息
ui->textBrowser->append(time);
ui->textBrowser->append("新客户连接");
ui->textBrowser->append(ip.append(";").append(QString::number(port)));
ui->textBrowser->append("");
}
void Dialog::disConnSlot()
{
QString ip = socket->peerAddress().toString();// 拿到对面客户端的IP与端口号
qint16 port = socket->peerPort();
QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
ui->textBrowser->append(time);
ui->textBrowser->append("客户已经断开连接");
ui->textBrowser->append(ip.append(":").append(QString::number(port)));
ui->textBrowser->append("");
}
void Dialog::readyReadSlot()
{
QTextStream input(socket);
QString msg = input.readLine();// 读取数据
ui->textBrowser->append(msg);// 展示
}
void Dialog:: btnSndMsgClickedSlot()
{
QString msg = ui->lineEdit->text();
if(msg == ""){
QMessageBox::warning(this,"warning","please input message!");
return;
}
QTextStream outputTextBrower(socket);
outputTextBrower<<msg.append("");
ui->lineEdit->clear();
}
再写客户端代码
头文件:dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QTcpSocket>// 连接类
#include <QMessageBox>
#include <QTextStream>// 文本流类
#include <QTcpSocket>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QTcpSocket *client;// 连接对象
private slots:
void btnConnClickedSlot();
void btnDisConnClickedSlot();
void btnSndMsgClickedSlot();
void connectedSlot();
void disconnectSlot();
void readyReadSlot();
};
#endif // DIALOG_H
源文件:dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
connect(ui->pushButtonConn,SIGNAL(clicked()),
this,SLOT(btnConnClickedSlot()));
connect(ui->pushButtonDisConn,SIGNAL(clicked()),
this,SLOT(btnDisConnClickedSlot()));
connect(ui->pushButtonSnd,SIGNAL(clicked()),this,SLOT(btnSndMsgClickedSlot()));
setWindowFlags(Qt::WindowStaysOnTopHint);// 设置窗口标记为顶层
client = new QTcpSocket(this);// 创建连接对象
connect(client,SIGNAL(connected()),this,SLOT(connectedSlot()));// 连接状态检测的信号槽
connect(client,SIGNAL(disconnected()),this,SLOT(disconnectSlot()));
}
Dialog::~Dialog()
{
if(client->isOpen()){// 如果客户端还在连着,关掉
client->close();
}
delete ui;
}
void Dialog:: btnConnClickedSlot()
{
// 默认输入有效,连接到服务器
// 参数1:服务器的IP地址
// 参数2:服务器的端口号
client->connectToHost(ui->lineEditIP->text(),ui->lineEditPor->text().toInt());
connect(client,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));
}
void Dialog::btnDisConnClickedSlot()
{
client->close();
}
void Dialog::btnSndMsgClickedSlot()
{
QString msg = ui->lineEdit->text();// 获取用户输入的内容
if(msg == ""){
QMessageBox::warning(this,"tip","please input message!");
return ;
}
QTextStream output(client);// 创建文本流对象
output<<msg;// 发送内容
ui->lineEdit->clear();// 清空输入框
}
void Dialog:: connectedSlot()
{
ui->lineEditIP->setEnabled(false);
ui->lineEditPor->setEnabled(false);
ui->pushButtonConn->setEnabled(false);// 屏蔽连接按钮
ui->pushButtonConn->setText("已连接");
ui->pushButtonSnd->setEnabled(true);// 释放发送按钮
ui->lineEdit->setEnabled(true);
}
void Dialog::disconnectSlot()
{
ui->lineEditIP->setEnabled(true);
ui->lineEditPor->setEnabled(true);
ui->pushButtonConn->setEnabled(true);// 恢复连接按钮
ui->pushButtonConn->setText("连接");
ui->pushButtonSnd->setEnabled(false);// 屏蔽发送按钮
ui->lineEdit->setEnabled(false);
}
void Dialog:: readyReadSlot()
{
QTextStream inputTextBrower(client);
QString msg = inputTextBrower.readLine();
ui->textBrowser->append(msg);
}