QT(C++)实现网络聊天程序的设计与实现(基于TCP协议)
目录
TCP/IP协议介绍
网络聊天程序的功能介绍
QT中socket编程
·服务器实现
·客户端实现
测试结果
TCP/IP协议介绍
TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件、软件需求的定义。TCP/IP协议确切的说法应该是TCP/UDP/IP协议。UDP协议(User Datagram Protocol 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输。TCP协议(Transmission Control Protocol 传输控制协议),是一种流传输的协议。他提供可靠的、有序的、双向的、面向连接的传输。
保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。
而面向流则是指无保护消息边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包。
举例来说,假如,我们连续发送三个数据包,大小分别是2k、4k、8k,这三个数据包都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完。而使用TCP协议,我们只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。
这就是因为UDP协议的保护消息边界使得每一个消息都是独立的。而流传输,却把数据当作一串数据流,它不认为数据是一个一个的消息。所以有很多人在使用TCP协议通讯的时候,并不清楚TCP是基于流的传输,当连续发送数据的时候,他们时常会认为TCP会丢包。其实不然,因为当它们使用的缓冲区足够大时,它们有可能会一次接收到两个甚至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个数据包,而已经接收的其它据包却被忽略了。
网络聊天程序的功能介绍
对于此程序的功能和界面在这进行一个简单的说明。首先服务器功能包括打开服务器(监听IP和端口)、接收显示客户端发送过来的消息、与客户端进行通信、在没有客户端接入的时候通过连接信号槽可以的得知且发送按钮失效。其次服务器功能包括通过输入IP地址和端口号进行连接服务器、接受显示服务器发送过来的消息、与服务器进行通信、同样在没有成功连接服务器的时候通过连接信号槽可以的得知且发送按钮失效。
此程序是一对一通信,如果需要进行多客户端通信的话,只需要多开几个线程进行监听即可。
QT中socket编程
·服务器实现
服务器端编程的步骤:
1:创建QT封装类TCP服务器对象server = new QTcpServer();
2:使用server对象调用函数listen()绑定监听IP地址和端口号;
3:建立连接信号槽connect()是否有客户端连接,有且获取客户端信息比如端口号;
4:请求到来后,接受连接请求,socket对象可以与客户端进行通信;
5:返回,等待另一连接请求;
7:关闭server和socket。
mainwindow.ui
MainWindow 0 0 550 583 服务器 110 30 72 31 端口号: 190 30 113 31 340 30 101 31 OpenServer 40 360 451 101 40 130 451 151 400 480 93 28 发送 40 80 91 41 Agency FB 12 消息内容: 40 310 221 41 Agency FB 12 服务器返回消息编辑: 0 0 550 26
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include
#include
#include namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:void on_pushButton_Listen_clicked();void on_pushButton_Send_clicked();void server_New_Connect();void socket_Read_Data();void socket_Disconnected();private:Ui::MainWindow *ui;QTcpServer* server;QTcpSocket* socket;
};#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QMessageBox"
#include "QTextCodec.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setFixedSize(550,583); // 禁止改变窗口大小。ui->textEdit_Recv->setReadOnly(true);ui->lineEdit_Port->setText("6000");ui->pushButton_Send->setEnabled(false);server = new QTcpServer();//连接信号槽connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);
}MainWindow::~MainWindow()
{server->close();server->deleteLater();delete ui;
}
void MainWindow::on_pushButton_Listen_clicked()
{ui->textEdit_Recv->setText("");if(ui->pushButton_Listen->text() == tr("OpenServer")){server = new QTcpServer();//连接信号槽connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);ui->textEdit_Recv->insertPlainText("OpenSuccessfully\n");//从输入框获取端口号int port = ui->lineEdit_Port->text().toInt();//监听指定的端口if(!server->listen(QHostAddress::Any, port)){//若出错,则输出错误信息QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));QMessageBox::information(this,tr("消息"),tr("打开服务器失败!"),QMessageBox::Yes);return;}//修改按键文字ui->pushButton_Listen->setText("CloseServer");QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));QMessageBox::information(this,tr("消息"),tr("打开服务器成功!"),QMessageBox::Yes);}else{server->deleteLater();//取消侦听server->close();//修改按键文字ui->pushButton_Listen->setText("OpenServer");//发送按键失能ui->pushButton_Send->setEnabled(false);ui->textEdit_Recv->insertPlainText("CloseSuccessfully\n");}}void MainWindow::on_pushButton_Send_clicked()
{ui->textEdit_Recv->insertPlainText(tr("服务器:")+ui->textEdit_Send->toPlainText()+"\n");socket->write(ui->textEdit_Send->toPlainText().toLocal8Bit());socket->flush();ui->textEdit_Send->setText("");
}void MainWindow::server_New_Connect()
{//获取客户端连接socket = server->nextPendingConnection();//连接QTcpSocket的信号槽,以读取新数据QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);//发送按键使能ui->pushButton_Send->setEnabled(true);}void MainWindow::socket_Read_Data()
{QByteArray buffer;//读取缓冲区数据buffer = socket->readAll();if(!buffer.isEmpty()){QString str = QString::fromLocal8Bit(buffer);ui->textEdit_Recv->insertPlainText("李青说:"+str+"\n");}
}void MainWindow::socket_Disconnected()
{//发送按键失能ui->pushButton_Send->setEnabled(false);
}
·客户端实现
客户端编程的步骤:
1:创建QT封装TCP套接字对象socket=new QTcpSocket();
2:建立连接信号槽connect()是否与服务器有连接;
3:向服务器发出连接请求( socket->connectToHost(IP, port));
4:和服务器端进行通信( socket->write());
5:关闭套接字。
mainwindow.ui
MainWindow 0 0 642 699 客户端 60 50 61 41 IP地址: 280 50 61 41 端口号: 120 60 151 21 340 60 113 21 480 50 93 31 连接 490 610 93 28 发送 60 150 521 261 60 490 521 101 60 110 131 31 Agency FB 12 聊天内容: 60 430 121 51 Agency FB 12 编辑消息: 0 0 642 26
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include
#include namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:void on_pushButton_Connect_clicked();void on_pushButton_Send_clicked();void socket_Read_Data();void socket_Disconnected();private:Ui::MainWindow *ui;QTcpSocket *socket;
};#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QTcpSocket"
#include "QMessageBox"
#include "QTextCodec.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setFixedSize(642,700); // 禁止改变窗口大小。socket=new QTcpSocket();//连接信号槽QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);ui->textEdit_Recv->setReadOnly(true);ui->pushButton_Send->setEnabled(false);ui->lineEdit_IP->setText("127.0.0.1");ui->lineEdit_Port->setText("6000");
}MainWindow::~MainWindow()
{delete this->socket;delete ui;
}
void MainWindow::on_pushButton_Connect_clicked()
{if(ui->pushButton_Connect->text() == tr("连接")){QString IP;int port;//获取IP地址IP = ui->lineEdit_IP->text();//获取端口号port = ui->lineEdit_Port->text().toInt();ui->textEdit_Recv->setText("");ui->textEdit_Recv->insertPlainText("正在连接"+ui->lineEdit_IP->text()+":"+ui->lineEdit_Port->text()+"\n");//取消已有的连接socket->abort();//连接服务器socket->connectToHost(IP, port);//等待连接成功if(!socket->waitForConnected(30000)){QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));QMessageBox::warning(this,tr("消息"),tr("连接失败!请重新连接"),QMessageBox::Yes);ui->textEdit_Recv->insertPlainText("连接失败\n");return;}ui->textEdit_Recv->insertPlainText("连接成功\n");QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));QMessageBox::information(this,tr("消息"),tr("连接成功"),QMessageBox::Yes);//发送按键使能ui->pushButton_Send->setEnabled(true);//修改按键文字ui->pushButton_Connect->setText("断开连接");}else{//断开连接ui->textEdit_Recv->setText("断开连接\n");socket->disconnectFromHost();//修改按键文字ui->pushButton_Connect->setText("连接");ui->pushButton_Send->setEnabled(false);}
}void MainWindow::on_pushButton_Send_clicked()
{ui->textEdit_Recv->insertPlainText(tr("李青说:")+ui->textEdit_Send->toPlainText()+"\n");socket->write(ui->textEdit_Send->toPlainText().toLocal8Bit());socket->flush();ui->textEdit_Send->setText("");
}void MainWindow::socket_Read_Data()
{QByteArray buffer;//读取缓冲区数据buffer = socket->readAll();if(!buffer.isEmpty()){QString str = QString::fromLocal8Bit(buffer);ui->textEdit_Recv->insertPlainText("服务器消息:"+str+"\n");}
}void MainWindow::socket_Disconnected()
{//发送按键失能ui->pushButton_Send->setEnabled(false);//修改按键文字ui->pushButton_Connect->setText("连接");qDebug() << "Disconnected!";
}
测试结果


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
