QT:Qsocket长连接的实现(多线程服务器)

废话少说:直接上代码

PS:为了减少代码量,这里忽略了链接出错时的错误处理

//服务器端
//dialog.h
#ifndef DIALOG_H
#define DIALOG_H
 
#include <QtGui>
#include <QtNetwork>
#include "fortuneserver.h"
 
class Dialog : public QDialog
{
    Q_OBJECT
 
public:
    Dialog(QWidget *parent = 0);
 
private:
    QLabel *statusLabel;
    QPushButton *quitButton;
    FortuneServer server;
};
 
#endif
 
 
 
//fortuneserver.h
#ifndef FORTUNESERVER_H
#define FORTUNESERVER_H
 
#include <QStringList>
#include <QTcpServer>
 
class FortuneServer : public QTcpServer
{
    Q_OBJECT
public:
    FortuneServer(QObject *parent = 0);
protected:
    void incomingConnection(int socketDescriptor);
private:
    QStringList fortunes;
};
 
#endif
 
 
 
//fortunethread.h
#ifndef FORTUNETHREAD_H
#define FORTUNETHREAD_H
 
#include <QThread>
#include <QTcpSocket>
 
class FortuneThread : public QThread
{
    Q_OBJECT
public:
    FortuneThread(int socketDescriptor, QObject *parent);
    void run();
private:
    int socketDescriptor;
    QString theString;
	QTcpSocket *tcpSocket;
	qint16 blockSize;
 
	public slots:
		void readMessage();
		void sendMessage();
signals:
		void error(QTcpSocket::SocketError socketError);
};
 
#endif
 
 
 
//dialog.cpp
#include "dialog.h"
 
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    statusLabel = new QLabel;
    quitButton = new QPushButton(tr("Quit"));
    quitButton->setAutoDefault(false);
 
    if (!server.listen(QHostAddress::Any, 8888)) 
	{
        QMessageBox::critical(this, tr("Threaded Fortune Server"),
                              tr("Unable to start the server: %1.")
                              .arg(server.errorString()));
        close();
        return;
    }
 
    QString ipAddress;
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    for (int i = 0; i < ipAddressesList.size(); ++i) {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
            ipAddressesList.at(i).toIPv4Address()) {
            ipAddress = ipAddressesList.at(i).toString();
            break;
        }
    }
    if (ipAddress.isEmpty())
        ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
    statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
                            "Run the Fortune Client example now.")
                         .arg(ipAddress).arg(server.serverPort()));
 
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
 
    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->addStretch(1);
    buttonLayout->addWidget(quitButton);
    buttonLayout->addStretch(1);
 
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addLayout(buttonLayout);
    setLayout(mainLayout);
 
    setWindowTitle(tr("Threaded Fortune Server"));
}
 
 
 
//fortuneserver.cpp
#include "fortuneserver.h"
#include "fortunethread.h"
 
FortuneServer::FortuneServer(QObject *parent)
    : QTcpServer(parent)
{
}
 
void FortuneServer::incomingConnection(int socketDescriptor)
{
    FortuneThread *thread = new FortuneThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}
 
 
 
//fortunethread.cpp
#include "fortunethread.h"
 
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
    : QThread(parent), socketDescriptor(socketDescriptor)
{
	blockSize = 0;
	
}
 
void FortuneThread::run()
{
	tcpSocket = new QTcpSocket;
	if (!tcpSocket->setSocketDescriptor(socketDescriptor))
	{
		emit error(tcpSocket->error());
		return;
	}
	connect(tcpSocket, SIGNAL(readyRead()), this, 
		SLOT(readMessage()), Qt::DirectConnection);
	exec();
}
 
void FortuneThread::readMessage()
{
	QDataStream in(tcpSocket);
	in.setVersion(QDataStream::Qt_4_0);
	if (blockSize == 0)
	{
		if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
			return;
		in >> blockSize;
	}
	if (tcpSocket->bytesAvailable() < blockSize)
		return;
 
	in >> theString;
	blockSize = 0;
	sendMessage();
}
 
void FortuneThread::sendMessage()
{
	QByteArray block;
	QDataStream out(&block, QIODevice::WriteOnly);
	out.setVersion(QDataStream::Qt_4_0);
 
	out << (quint16)0;
	out << theString;
	out.device()->seek(0);
	out << (quint16)(block.size() - sizeof(quint16));
 
	tcpSocket->write(block);
}
 
 
//main.cpp
#include <QApplication>
#include <QtCore>
#include "dialog.h"
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Dialog dialog;
    dialog.show();
    return dialog.exec();
}
 
 
 
 
 
 
//客户端
//client.h
#ifndef TRYCLI_H_
#define TRYCLI_H_
 
#include <QtNetwork>
#include <QtGui>
#include <QtCore>
 
class Client : public QWidget
{
	Q_OBJECT
private:
	bool isConnected;
	QLineEdit *serverIpEdit;
	QLabel *label;
	QLineEdit *strEdit;
	QPushButton *startButton;
 
	QTcpSocket *tcpClient;
	quint16 blockSize;
	QString sendString;
	QString readString;
 
public:
	Client();
	~Client();
 
	public slots:
		void displayError(QAbstractSocket::SocketError socketError);
		void newConnect();
		void readMessage();
		void sendMessage();
 
};
 
#endif
 
 
//client.cpp
#include "client.h"
#include <QtGui/QMessageBox>
#include <QtGui/QHBoxLayout>
#include <QtEvents>
 
Client::Client()
{
	setWindowTitle("Client");
	resize(300, 100);
 
	serverIpEdit = new QLineEdit("127.0.0.1");
	startButton = new QPushButton("start");
	strEdit = new QLineEdit;
	label = new QLabel("Emtpy");
	isConnected = false;
 
	QVBoxLayout *layout = new QVBoxLayout;
	layout->addWidget(serverIpEdit);
	layout->addWidget(label);
	layout->addWidget(strEdit);
	layout->addWidget(startButton);
	setLayout(layout);
 
	tcpClient = new QTcpSocket(this);
	connect(startButton, SIGNAL(clicked()), this, SLOT(newConnect()));
	connect(tcpClient, SIGNAL(connected()), this, SLOT(sendMessage()));
	connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage()));
	connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),
		this, SLOT(displayError(QAbstractSocket::SocketError)));
}
 
Client::~Client()
{
 
}
 
void Client::newConnect()
{
	blockSize = 0;
	if(!isConnected)
	{
		tcpClient->abort();
		tcpClient->connectToHost(serverIpEdit->text(), 8888);
		isConnected = true;
	}
	else
		sendMessage();
}
 
void Client::sendMessage()
{
	QByteArray block;
	QDataStream out(&block, QIODevice::WriteOnly);
	out.setVersion(QDataStream::Qt_4_0);
 
	sendString = strEdit->text();
	out << (quint16)0;
	out << sendString;
	out.device()->seek(0);
	out << (quint16)(block.size() - sizeof(quint16));
 
	tcpClient->write(block);
}
 
void Client::readMessage()
{
	QDataStream in(tcpClient);
	in.setVersion(QDataStream::Qt_4_0);
 
	if (blockSize == 0)
	{
		if (tcpClient->bytesAvailable() < (int)sizeof(quint16))
			return;
		in >> blockSize;
	}
	if (tcpClient->bytesAvailable() < blockSize)
		return;
 
	in >> readString;
	label->setText(readString);
}
 
void Client::displayError(QAbstractSocket::SocketError socketError)
{
	switch (socketError) {
	case QAbstractSocket::RemoteHostClosedError:
		break;
	case QAbstractSocket::HostNotFoundError:
		QMessageBox::information(this, tr("Fortune Client"),
			tr("The host was not found. Please check the "
			"host name and port settings."));
		break;
	case QAbstractSocket::ConnectionRefusedError:
		QMessageBox::information(this, tr("Fortune Client"),
			tr("The connection was refused by the peer. "
			"Make sure the fortune server is running, "
			"and check that the host name and port "
			"settings are correct."));
		break;
	default:
		QMessageBox::information(this, tr("Fortune Client"),
			tr("The following error occurred: %1.")
			.arg(tcpClient->errorString()));
	}
}
 
 
//main.cpp
#include "client.h"
#include <QtGui/QApplication>
 
int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	Client w;
	w.show();
	return a.exec();
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用Qt编写服务端程序时,可以使用Qt网络模块提供的QTcpServer类来实现一个服务端连接多个客户端的功能。具体实现方法如下: 首先需要在服务端程序中创建一个QTcpServer对象,用于监听客户端的连接请求。可以在服务端程序的构造函数中使用如下代码创建一个QTcpServer对象: ``` m_server = new QTcpServer(this); ``` 然后需要调用QTcpServer对象的listen()函数开始监听客户端的连接请求,例如: ``` if(!m_server->listen(QHostAddress::Any, 1234)) { qDebug() << "Server listen error!"; return; } ``` 上述代码中的端口号1234可以根据实际需求进行修改。如果端口被占用或监听失败,listen()函数会返回false;如果监听成功,返回true。 当服务端监听到一个新的客户端连接请求时,会自动发出newConnection()信号。因此在服务端程序中需要连接这个信号并编写一个槽函数来处理客户端的连接请求,例如: ``` connect(m_server,SIGNAL(newConnection()),this,SLOT(onNewConnection())); ``` 上述代码将服务端的newConnection()信号连接到了名为onNewConnection()的槽函数。 在onNewConnection()函数中需要调用QTcpServer对象的nextPendingConnection()函数来获取一个新的QTcpSocket对象,这个对象代表一个新连接的客户端。这里需要用一个QList对象来保存所有已连接的客户端(QTcpSocket对象)。例如: ``` void MyServer::onNewConnection() { QTcpSocket *socket = m_server->nextPendingConnection(); m_clients.append(socket); } ``` 上述代码中,将新连接的QTcpSocket对象加入到保存已连接客户端的QList对象中。 现在服务端已经连接了多个客户端,可以通过发送和接收数据来与客户端进行通信。具体方法可以参考QTcpSocket类的使用方法。 最后需要注意的是,需要在服务端程序析构函数中将所有已连接的客户端QTcpSocket对象都关闭并从QList中移除,以免出现内存泄漏的问题。例如: ``` MyServer::~MyServer() { foreach (QTcpSocket *socket, m_clients) { socket->close(); m_clients.removeOne(socket); delete socket; } } ``` 上述代码中,遍历已连接的客户端QTcpSocket对象,依次关闭并移除它们,最后删除这些对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值