Qt 中是通过 QTcpSocket
类 和 QTcpServer
类 实现TCP协议的编程。下面编写一个基于 TCP 协议的网络聊天室应用,它同样也是由 客户端 和 服务器两部分组成的。
server.h:
#ifndef SERVER_H
#define SERVER_H
#include
#include
#include "tcpclientsocket.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
Server(QObject * parent = 0,int port = 0);
QList<TcpClientSocket*> tcpClientSocketList;
signals:
void updateServer(QByteArray);
public slots:
void updateClients(QByteArray);
void slotDisconnected(int);
protected:
void incomingConnection(int socketDescriptor);
};
#endif // SERVER_H
tcpclientsocket.h:
#ifndef TCPCLIENTSOCKET_H
#define TCPCLIENTSOCKET_H
#include
#include
class TcpClientSocket : public QTcpSocket
{
Q_OBJECT
public:
TcpClientSocket(QObject *parent = nullptr);
signals:
void updateClients(QByteArray);
void disconnected(int);
protected slots:
void dataReceived();
void slotDisconnected();
};
#endif // TCPCLIENTSOCKET_H
tcpserver.h:
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include
#include
#include
#include
#include
#include
#include "server.h"
class TcpServer : public QDialog
{
Q_OBJECT
public:
TcpServer(QWidget *parent = nullptr,Qt::WindowFlags f = 0);
~TcpServer();
public slots:
void slotCreateServer();
void updateServer(QByteArray);
private:
QListWidget * contentListWidget;
QLabel * portLabel;
QLineEdit * portLineEdit;
QPushButton * createBtn;
QGridLayout * mainLayout;
int port;
Server * server;
};
#endif // TCPSERVER_H
main.cpp:
#include "tcpserver.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TcpServer w;
w.show();
return a.exec();
}
server.cpp:
#include "server.h"
Server::Server(QObject * parent,int port)
:QTcpServer(parent)
{
listen(QHostAddress::Any,port);
}
void Server::incomingConnection(int socketDescriptor){
TcpClientSocket * tcpClientSocket = new TcpClientSocket(this);
connect(tcpClientSocket,SIGNAL(updateClients(QByteArray)),
this,SLOT(updateClients(QByteArray)));
connect(tcpClientSocket,SIGNAL(disconnected(int)),
this,SLOT(slotDisconnected(int)));
tcpClientSocket->setSocketDescriptor(socketDescriptor);
tcpClientSocketList.append(tcpClientSocket);
}
void Server::updateClients(QByteArray msg){
emit updateServer(msg);
for(int i = 0;i < tcpClientSocketList.count();i++){
QTcpSocket * item = tcpClientSocketList.at(i);
if(item->write(msg) != -1){
continue;
}
}
}
void Server::slotDisconnected(int descriptor){
for(int i = 0;i < tcpClientSocketList.count();i++){
QTcpSocket * item = tcpClientSocketList.at(i);
if(item->socketDescriptor() == descriptor){
tcpClientSocketList.removeAt(i);
return;
}
}
}
tcpclientsocket.cpp:
#include "tcpclientsocket.h"
TcpClientSocket::TcpClientSocket(QObject *parent) : QTcpSocket(parent)
{
connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));
connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
}
void TcpClientSocket::dataReceived(){
while(bytesAvailable() > 0){
QByteArray datagram = readAll();
emit updateClients(datagram);
}
}
void TcpClientSocket::slotDisconnected(){
emit disconnected(this->socketDescriptor());
}
tcpserver.cpp:
#include "tcpserver.h"
TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f)
: QDialog(parent,f)
{
setWindowTitle(tr("TCP Server"));
contentListWidget = new QListWidget;
portLabel = new QLabel(tr("端口:"));
portLineEdit = new QLineEdit;
createBtn = new QPushButton(tr("创建聊天室"));
port = 8010;
portLineEdit->setText(QString::number(port));
mainLayout = new QGridLayout(this);
mainLayout->addWidget(contentListWidget,0,0,1,2);
mainLayout->addWidget(portLabel,1,0);
mainLayout->addWidget(portLineEdit,1,1);
mainLayout->addWidget(createBtn,2,0,1,2);
connect(createBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));
}
void TcpServer::slotCreateServer(){
server = new Server(this,port);
connect(server,SIGNAL(updateServer(QByteArray)),
this,SLOT(updateServer(QByteArray)));
createBtn->setEnabled(false);
}
void TcpServer::updateServer(QByteArray msg){
contentListWidget->addItem(QString::fromUtf8(msg));
}
TcpServer::~TcpServer()
{
}
tcpclient.h:
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include
#include
#include
#include
#include
#include
#include
#include
class TcpClient : public QDialog
{
Q_OBJECT
public:
TcpClient(QWidget *parent = nullptr);
~TcpClient();
public slots:
void slotEnter();
void slotConnected();
void dataReceived();
void slotSend();
private:
QListWidget * contentListWidget;
QLineEdit * sendLineEdit;
QPushButton * sendBtn;
QLabel * usernameLabel;
QLineEdit * usernameLineEdit;
QLabel * serverIPLabel;
QLineEdit * serverIPLineEdit;
QLabel * portLabel;
QLineEdit * portLineEdit;
QPushButton * enterBtn;
QGridLayout * mainLayout;
bool status;
int port;
QHostAddress * serverIP;
QString username;
QTcpSocket * tcpSocket;
};
#endif // TCPCLIENT_H
main.cpp:
#include "tcpclient.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TcpClient w;
w.show();
return a.exec();
}
tcpclient.cpp:
#include "tcpclient.h"
#include
#include
#include
TcpClient::TcpClient(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(tr("TCP Client"));
contentListWidget = new QListWidget;
sendLineEdit = new QLineEdit;
sendBtn = new QPushButton(tr("发送"));
usernameLabel = new QLabel(tr("用户名:"));
usernameLineEdit = new QLineEdit;
serverIPLabel = new QLabel(tr("服务器地址:"));
serverIPLineEdit = new QLineEdit;
portLabel = new QLabel(tr("端口:"));
portLineEdit = new QLineEdit;
enterBtn = new QPushButton(tr("进入聊天室"));
status = false;
port = 8010;
portLineEdit->setText(QString::number(port));
serverIP = new QHostAddress();
mainLayout = new QGridLayout(this);
mainLayout->addWidget(contentListWidget,0,0,1,2);
mainLayout->addWidget(sendLineEdit,1,0);
mainLayout->addWidget(sendBtn,1,1);
mainLayout->addWidget(usernameLabel,2,0);
mainLayout->addWidget(usernameLineEdit,2,1);
mainLayout->addWidget(serverIPLabel,3,0);
mainLayout->addWidget(serverIPLineEdit,3,1);
mainLayout->addWidget(portLabel,4,0);
mainLayout->addWidget(portLineEdit,4,1);
mainLayout->addWidget(enterBtn,5,0,1,2);
connect(enterBtn,SIGNAL(clicked()),this,SLOT(slotEnter()));
connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend()));
sendBtn->setEnabled(false);
}
void TcpClient::slotEnter(){
if(!status){
QString ip = serverIPLineEdit->text();
if(!serverIP->setAddress(ip)){
QMessageBox::information(this,tr("error"),tr("server ip address error!"));
return;
}
if(usernameLineEdit->text() == ""){
QMessageBox::information(this,tr("error"),tr("username error!"));
return;
}
username = usernameLineEdit->text();
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
tcpSocket->connectToHost(*serverIP,port);
status = true;
if(status) qDebug() << "进入了聊天室"<<endl;
}
else{
sendBtn->setEnabled(false);
enterBtn->setText(tr("进入聊天室"));
//清空
usernameLineEdit->setText("");
sendLineEdit->setText("");
portLineEdit->setText("");
serverIPLineEdit->setText("");
status = false;
if(!status) qDebug() << "离开了聊天室"<<endl;
QString msg = username + tr(":Leave chat room");
if(tcpSocket->write(msg.toUtf8()) != -1){
return;
}
//tcp 断开连接
tcpSocket->disconnectFromHost();
}
}
void TcpClient::slotConnected(){
sendBtn->setEnabled(true);
enterBtn->setText(tr("离开"));
QString msg = username + tr(":Enter Chat Room");
if(tcpSocket->write(msg.toUtf8()) != -1){
return;
}
}
void TcpClient::slotSend(){
if(sendLineEdit->text() == ""){
return;
}
QString msg = username + ":" + sendLineEdit->text();
tcpSocket->write(msg.toUtf8());
sendLineEdit->clear();
}
void TcpClient::dataReceived(){
while(tcpSocket->bytesAvailable() > 0){
QByteArray datagram = tcpSocket->readAll();
contentListWidget->addItem(QString::fromUtf8(datagram));
}
}
TcpClient::~TcpClient()
{
}
为了实现中文不出现乱码,我将则很难哥哥过程中的通信数据格式全部转成了 utf8
格式。