QT TCP练习
一、简述
简单的单个服务器端与多个客户端的基于TCP协议的双向通信 练习
二、效果
三、工程结构
四、源码文件
TcpClient.pro文件
QT +=widgets gui network HEADERS += \ tcpclient.h SOURCES += \ main.cpp \ tcpclient.cpp
tcpclient.h文件
#ifndef TCPCLIENT_H #define TCPCLIENT_H #include <QWidget> #include <QTcpSocket> #include <QTcpSocket> #include <QGridLayout> #include <QLineEdit> #include <QPushButton> #include <QTextBrowser> class TcpClient : public QWidget { Q_OBJECT public: explicit TcpClient(QWidget *parent = 0); signals: public slots: void MySend();//向服务端发送数据 void MyReceive();//接收数据 private: QTcpSocket* _socket;//通信socket QLineEdit* _lineEdit;//行文本编辑框,编写要发送给服务器的信息 QTextBrowser* _text;//展示接收到的信息 }; #endif // TCPCLIENT_H
tcpclient.cpp文件
#include "tcpclient.h" #include <QDebug> TcpClient::TcpClient(QWidget *parent) : QWidget(parent) { //创建通信socket _socket = new QTcpSocket(); //指定要通信的服务器的ip地址以及端口 _socket->connectToHost("127.0.0.1", 8899); //创建行文本编辑框 _lineEdit = new QLineEdit; //创建“发送”按钮 QPushButton* sendBtn = new QPushButton("发送"); //创建QTextBrowser,用来展示服务器端的信息 _text = new QTextBrowser; //创建一个QGridLayout网格布局 QGridLayout* glayout = new QGridLayout(this); //将_text、_lineEdit和sendBtn添加到QHBoxLayout布局 glayout->addWidget(_lineEdit,0,0,1,2);//将_lineEdit添加到第0行第0列,占据1行、2列 glayout->addWidget(sendBtn,0,2,1,1);//将sendBtn添加到第0行第2列,占据1行、1列 glayout->addWidget(_text,1,0,1,3);//将_text添加到第1行第0列,占据1行、3列 //连接发送按钮点击触发的事件 connect(sendBtn, SIGNAL(clicked()), this, SLOT(MySend())); //当焦点在行文本编辑框时,按下回车键触发的事件 connect(_lineEdit, SIGNAL(returnPressed()), this, SLOT(MySend())); //连接_socket收到数据时的处理函数 connect(_socket, SIGNAL(readyRead()),this, SLOT(MyReceive())); } void TcpClient::MySend() { //获取行文本编辑框的文本内容,即要发送给服务器的信息 QString text = _lineEdit->text(); if(!text.isEmpty())//如果信息不为空 { //将信息发送给服务端,可以选择QByteArray格式 _socket->write(text.toUtf8()); //发送完毕将编辑框清空 _lineEdit->clear(); } } void TcpClient::MyReceive() { qDebug()<<"text"; // 接收数据,判断是否有数据,如果有,通过readAll函数获取所有数据 while(_socket->bytesAvailable() > 0) { QByteArray buf = _socket->readAll();//获取所有数据 _text->append(buf);//在QTextBrowser上展示收到的信息 } }
main.cpp文件
扫描二维码关注公众号,回复:
1443046 查看本文章
#include <QApplication> #include <tcpclient.h> int main(int argc,char* argv[]) { QApplication app(argc,argv); TcpClient client; //创建客户端窗体 client.setWindowTitle("客户端");//设置窗体标题 client.show();//show出客户端窗体 return app.exec(); }
TcpServer.pro文件
QT += widgets gui network HEADERS += \ tcpserver.h SOURCES += \ main.cpp \ tcpserver.cpp
tcpserver.h文件
#ifndef TCPSERVER_H #define TCPSERVER_H #include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QTextBrowser> #include <QGridLayout> #include <QPushButton> #include <QLineEdit> #include <QLabel> #include <QComboBox> #include <QList> class TcpServer : public QWidget { Q_OBJECT public: explicit TcpServer(QWidget *parent = 0); signals: public slots: void MyConnection();//处理客户端连接 void MyReceive();//接收客户端信息 void MySend();//向客户端发送信息 void MyDisconnected();//断开连接时处理对应的socket private: QTcpServer* _server;//服务器 QTcpSocket* _socket;//通信socket QTextBrowser* _text;//展示接收到的信息 QComboBox* _sendAddrCbb;//保存客户端的IP、端口 QLineEdit* _lineEdit;//行文本编辑框,编写要发送给客户端的信息 QList<QTcpSocket*> _socketList;//通信socket列表 }; #endif // TCPSERVER_H
tcpserver.cpp文件
#include "tcpserver.h" #include <QDebug> TcpServer::TcpServer(QWidget *parent) : QWidget(parent) { // 创建服务器 _server = new QTcpServer(this); //监听服务器的所有ip地址的8899端口 _server->listen(QHostAddress::Any, 8899); // 当有客户端来请求连接的是_server监听的端口时,调用MyConnection方法 connect(_server, SIGNAL(newConnection()),this, SLOT(MyConnection())); //创建QLabel标签 QLabel* sendAddrLbl = new QLabel("发送至"); //创建QComboBox _sendAddrCbb = new QComboBox(); _sendAddrCbb->addItem("请选择IP及端口"); //创建行文本编辑框 _lineEdit = new QLineEdit; //创建“发送”按钮 QPushButton* sendBtn = new QPushButton("发送"); //创建QTextBrowser,用来展示客户端的信息 _text = new QTextBrowser; //创建一个QGridLayout网格布局 QGridLayout* glayout = new QGridLayout(this); //将_text、_lineEdit和sendBtn添加到QHBoxLayout布局 glayout->addWidget(sendAddrLbl,0,0,1,1);//将sendAddrLbl添加到第0行第0列,占据1行、1列 glayout->addWidget(_sendAddrCbb,0,1,1,2);//将sendAddrCbb添加到第0行第1列,占据1行、2列 glayout->addWidget(_lineEdit,1,0,1,2);//将_lineEdit添加到第1行第0列,占据1行、2列 glayout->addWidget(sendBtn,1,2,1,1);//将sendBtn添加到第1行第2列,占据1行、1列 glayout->addWidget(_text,2,0,1,3);//将_text添加到第2行第列,占据1行、3列 //连接发送按钮点击触发的事件 connect(sendBtn, SIGNAL(clicked()), this, SLOT(MySend())); //当焦点在行文本编辑框时,按下回车键触发的事件 connect(_lineEdit, SIGNAL(returnPressed()), this, SLOT(MySend())); } void TcpServer::MyConnection() { // 循环处理待处理的连接 while(_server->hasPendingConnections()) { //调用nextPeddingConnection去获得连接的socket, //即取得与具体某一个客户端通信socket,一个通信socket对应一个一个客户端 _socket = _server->nextPendingConnection(); //添加到soclet列表 _socketList.append(_socket); //在ComBoBox添加已经连接上服务器的客户端ip、端口 _sendAddrCbb->addItem(_socket->peerAddress().toString()+":"+QString::number(_socket->peerPort())); //为新的socket提供槽函数,来接收数据 connect(_socket, SIGNAL(readyRead()),this, SLOT(MyReceive())); connect(_socket, SIGNAL(disconnected()),this, SLOT(MyDisconnected()));//与客户端断开连接时,进行相应处理 } } void TcpServer::MyReceive() { for(int i=0;i<_socketList.size();++i) { // 接收数据,判断是否有数据,如果有,通过readAll函数获取所有数据 while(_socketList.at(i)->bytesAvailable() > 0) { QByteArray buf = ("["+_socketList.at(i)->peerAddress().toString()+":"+QString::number(_socketList.at(i)->peerPort())+"]").toUtf8(); buf.append(_socketList.at(i)->readAll());//获取所有数据 _text->append(buf);//在QTextBrowser上展示收到的信息 } } } void TcpServer::MySend() { //获取行文本编辑框的文本内容,即要发送给客户端的信息 QString text = _lineEdit->text(); int index = _sendAddrCbb->currentIndex(); //如果信息不为空且已经选择了已经连接的客户端IP地址及端口 if(!text.isEmpty() && index != 0) { //根据index找到客户端对应的socket将信息发送给客户端,以QByteArray格式发送数据 if(index-1<=_socketList.size()) { _socketList.at(index-1)->write(text.toUtf8()); } //发送完毕将编辑框清空 _lineEdit->clear(); } } void TcpServer::MyDisconnected() { for(int i=0;i<_socketList.size();++i) { //找到已经断开连接的socket if(_socketList.at(i)->state() == QAbstractSocket::UnconnectedState) { _sendAddrCbb->removeItem(i+1);//在选择列表中去掉断开连接的IP地址、端口 _socketList.removeAt(i);//去掉断开连接的socket break; } } }
main.cpp文件
#include <QApplication> #include <tcpserver.h> int main(int argc,char* argv[]) { QApplication app(argc,argv); TcpServer server; //创建服务器窗体 server.setWindowTitle("服务器端");//设置窗体标题 server.show();//show出服务器窗体 return app.exec(); }