使用Qt库中的 <QTcpServer> 和<QTcpSocket>类实现局域网络下的聊天室。
分为服务端和客户端;
服务端接收来自各个客户端的信息,并发送到所有客户端;
客户端用于用户登陆及聊天。
客户端:
使用<QTcpSocket>类即可;
首先在 工程文件.pro中加入一行:
QT += network
创建工程,然后用一个dialog实现主窗体就行了;
用Qt设计器添加控件:
以下是Dialog.h源码:
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QTcpSocket> #include <QHostAddress> namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); ~Dialog(); private: Ui::Dialog *ui; bool connectStatus; // int port; QHostAddress *serverIP; QString userName; QTcpSocket *tcpSocket; public slots: void slotEnter(); void slotConnected(); void slotDisconnected(); void slotDataReceived(); void slotSend(); }; #endif // DIALOG_H
以下是Dialog.cpp源码:
#include "dialog.h" #include "ui_dialog.h" #include <QMessageBox> #include <QHostAddress> Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); this->setFixedSize(400,500); this->setWindowTitle("TCP Client"); ui->portLineEdit->setText("45454"); ui->userNameLineEdit->setText("UserName"); connect(ui->enterButton,SIGNAL(clicked()),this,SLOT(slotEnter())); connect(ui->sendButton,SIGNAL(clicked()),this,SLOT(slotSend())); this->serverIP = new QHostAddress(); this->connectStatus = false; ui->sendButton->setEnabled(false); } Dialog::~Dialog() { delete ui; } void Dialog::slotEnter() { if(!this->connectStatus) { //--------------------------------------------------- if(ui->userNameLineEdit->text()=="") { QMessageBox::information(this,tr("error"),tr("User name Error ! ")); } this->userName = ui->userNameLineEdit->text(); if(ui->serverIPLineEdit->text()=="") { QMessageBox::information(this,tr("error"),tr("Server Address Error ! ")); } this->serverIP->setAddress(ui->serverIPLineEdit->text()); if(ui->portLineEdit->text() == "") { QMessageBox::information(this,tr("error"),tr("Port Error ! ")); } this->port = ui->portLineEdit->text().toInt(); //--------------------------------------------------- this->tcpSocket = new QTcpSocket(this); connect(this->tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected())); connect(this->tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); this->tcpSocket->connectToHost(*this->serverIP,this->port); // } else { QString msg = this->userName + tr(":leave chat Room"); this->tcpSocket->write(msg.toLatin1(),msg.length()); this->tcpSocket->disconnectFromHost(); } } void Dialog::slotConnected() { ui->sendButton->setEnabled(true); ui->enterButton->setText(tr("Leave")); connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(slotDataReceived())); QString msg = this->userName + tr(":Enter Chat room"); this->tcpSocket->write(msg.toLatin1(),msg.length()); this->connectStatus = true; QMessageBox::information(this,tr("Connected"),tr("Entered the Chat room")); } void Dialog::slotDisconnected() { ui->sendButton->setEnabled(false); ui->enterButton->setText(tr("Enter")); this->connectStatus = false; QMessageBox::information(this,tr("Disconnected"),tr("Exited the Chat room")); } void Dialog::slotSend() { if(ui->sendLineEdit->text()=="") { return; } QString msg = this->userName+" : "+ui->sendLineEdit->text(); this->tcpSocket->write(msg.toLatin1(),msg.length()); ui->sendLineEdit->clear(); } void Dialog::slotDataReceived() { while(tcpSocket->bytesAvailable()>0) { QString msg = this->tcpSocket->readAll(); ui->contentListWidget->addItem(msg.left(msg.length())); } }
然后是服务端:
同样,首先在 工程文件.pro中加入一行:
QT += network
用Widgets实现主窗体:
服务端实现了两个类:<clientTCPsocket>类和<TCPserver>类,分别继承自<QTcpSocket>和<QTcpServer>; clientTCPsocket.h:
#ifndef CLIENTTCPSOCKET_H #define CLIENTTCPSOCKET_H #include <QTcpSocket> #include <QObject> class clientTCPsocket : public QTcpSocket { Q_OBJECT public: clientTCPsocket(QObject *parent = 0); signals: void updateClients(QString,int); void disconnected(int); public slots: void dataReceived(); void slotDisconnected(); }; #endif // CLIENTTCPSOCKET_H
clientTCPsocket.cpp:
#include "clienttcpsocket.h" clientTCPsocket::clientTCPsocket(QObject *parent) : QTcpSocket(parent) { connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived())); connect(this,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected())); } void clientTCPsocket::dataReceived() { while(this->bytesAvailable()>0) { QString msg = this->readAll(); int length = msg.length(); emit updateClients(msg,length); } } void clientTCPsocket::slotDisconnected() { emit disconnected(this->socketDescriptor()); // }
TCPserver.h:
#ifndef TCPSERVER_H #define TCPSERVER_H #include <QTcpServer> #include <QTcpSocket> #include <QObject> #include <clienttcpsocket.h> class TCPserver : public QTcpServer { Q_OBJECT public: TCPserver(QObject *parent = 0,int port = 0); QList<clientTCPsocket*>clientTCPsocketList; signals: void updateServer(QString,int); public slots: void updateClients(QString msg, int length); void slotDisconnected(int descriptor); void acceptConnection(); }; #endif // TCPSERVER_H
TCPserver.cpp:
#include "tcpserver.h" TCPserver::TCPserver(QObject *parent,int port) : QTcpServer(parent) { this->listen(QHostAddress::Any,port); connect(this,SIGNAL(newConnection()),this,SLOT(acceptConnection())); } void TCPserver::acceptConnection() { clientTCPsocket *TCPsocket = new clientTCPsocket(this); connect(TCPsocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int))); connect(TCPsocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int))); TCPsocket->setSocketDescriptor(this->nextPendingConnection()->socketDescriptor()); this->clientTCPsocketList.append(TCPsocket); } void TCPserver::updateClients(QString msg, int length) { emit updateServer(msg,length); // for(int i=0;i<clientTCPsocketList.count();i++) { QTcpSocket *item = clientTCPsocketList.at(i); item->write(msg.toLatin1(),length); } } void TCPserver::slotDisconnected(int descriptor) { for(int i =0;i<clientTCPsocketList.count();i++) { QTcpSocket *item = clientTCPsocketList.at(i); if(item->socketDescriptor()==descriptor) { clientTCPsocketList.removeAt(i); return; } } return; }
Widgets中创建并初始化一个TCPserver对象;
widgets.h:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <tcpserver.h> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; int port; TCPserver *server; public slots: void slotCreateServer(); void updateServer(QString msg, int length); }; #endif // WIDGET_H
widgets.cpp:
#include "widget.h" #include "ui_widget.h" #include <QMessageBox> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); setWindowTitle(tr("TCP server")); this->setFixedSize(400,500); ui->PortlLineEdit->setText("45454"); connect(ui->CreateBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer())); } Widget::~Widget() { delete ui; } void Widget::slotCreateServer() { //******************************************* if(ui->PortlLineEdit->text() == "") { QMessageBox::information(this,tr("error"),tr("Port Error ! ")); } this->port = ui->PortlLineEdit->text().toInt(); //******************************************* this->server = new TCPserver(this,this->port); connect(this->server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int))); ui->CreateBtn->setEnabled(false); } void Widget::updateServer(QString msg, int length) { ui->ContentListWidget->addItem(msg.left(length)); }
这样服务端和客户端都实现完成;
运行效果:
服务端:
客户端: