天天看点

QTcpSocket学习笔记--TCP服务器一对多通信实例服务器的搭建步骤客户端的搭建步骤源码

TCP服务器一对多实例

  • 服务器的搭建步骤
    • 1.实例化QTcpServer对象
    • 2.监听
    • 3.绑定客户端连接的信号和槽
    • 4.自定客户端连接的槽函数并绑定客户端会发出信号的槽函数
    • 5.处理客户端发送过来的消息
    • 6.处理客户端断开连接
    • 7.服务器退出
  • 客户端的搭建步骤
  • 源码
    • qtcpserver.h
    • qtcpserver.cpp
    • main.cpp
    • 实例效果如下图
编程环境 VS2008 + Qt4.7
           

代码思路:用QList<QTcpSocket *> socketClient将所有连接上来的客户端Socket描述符都保存起来,当服务器接收到一个客户端发来的消息的时候,就把此消息发送给其他所有的客户端,当一个客户端断开连接发出disconnected()信号的时候,就把这个描述符从链表中删掉并释放掉

服务器的搭建步骤

1.实例化QTcpServer对象

QTcpServer *MyServer  = new QTcpServer(this);
 // 可以将QTcpServer描述符理解为监听描述符,用于监听
           

2.监听

MyServer->listen(QHostAddress::Any,1997);
 // QHostAddress::Any -- 监听所有地址 
 // 1997 -- 端口号,可自定
           

3.绑定客户端连接的信号和槽

connect(MyServer,SIGNAL(newConnection()),this,SLOT(handleConnect()),Qt::UniqueConnection);
// newConnection()[signal] -- 如果有新连接上来的客户端就会触发此信号
           

4.自定客户端连接的槽函数并绑定客户端会发出信号的槽函数

// 客户端会emit的信号
// disconnected()[signal] -- 客户端断开连接
// readyRead()[signal]    -- 客户端发送消息
void QtServer::handleConnect()
{
	QTcpSocket *client = new QTcpSocket(this);
	client = MyServer->nextPendingConnection();
	//用一个QList把所有连接上来的客户端描述符保存起来
	socketClient.append(client);
	
	connect(client,SIGNAL(readyRead()),this,SLOT(return_data()),Qt::UniqueConnection);
	connect(client, SIGNAL(disconnected()),this,SLOT(handleDisconnect()));
}
           

5.处理客户端发送过来的消息

//将接收到的信息转发到其他的客户端
void QtServer::return_data()
{
	char *buffer = new char[1024];
	memset(buffer,0,1024);
	QTcpSocket * sendclient = (QTcpSocket*)sender();//获取触发此槽函数的客户端的Socket
	sendclient->read(buffer,1024);
	//遍历socketClient,把接收到的信息转发到其他所有的客户端
	foreach(QTcpSocket *sock,socketClient)
	{
		if(sock != sendclient)//判断此客户端socket是否为发送方
			sock->write(buffer);
	}
	QString ip = sendclient->peerAddress().toString();
	ui.recv_textEdit->append(ip+" : "+buffer);//将客户端发送过来的消息显示在主窗口的textEdit上
}
           

6.处理客户端断开连接

void QtServer::handleDisconnect()
{
	QTcpSocket * sendclient = (QTcpSocket*)sender();
	sendclient->close();//关闭此描述符
	socketClient.removeOne(sendclient);//链表剔除此元素
}

           

7.服务器退出

//遍历链表一项一项断开连接并关闭
void QtServer::on_exit_pushButton_clicked()
{
	foreach(QTcpSocket *sock,socketClient)
	{
		sock->disconnectFromHost();
		sock->close();
	}
	MyServer->close();
	this->close();
}
           
服务器的所有基本操作完成,客户端的操作可以看我之前的文章,里面有详细的介绍

客户端的搭建步骤

见我之前的博客,在此不再叙述 https://blog.csdn.net/weixin_46276101/article/details/113877603

源码

qtcpserver.h

//qtcpserver.h
#ifndef QTSERVER_H
#define QTSERVER_H

#include <QtGui/QMainWindow>
#include "ui_qtserver.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QStringList>
#include <QString>
#include <QDebug>
#include <QList>
#include <QString>
#include <cstdlib>

class QtServer : public QMainWindow
{
	Q_OBJECT

public:
	QtServer(QWidget *parent = 0, Qt::WFlags flags = 0);
	~QtServer();

private slots:
	void on_listen_pushButton_clicked();//点击开始监听
	void on_exit_pushButton_clicked();//点击退出
	void handleConnect();
	void return_data();
	void handleDisconnect();

private:
	Ui::QtServerClass ui;
	QTcpServer *MyServer;
	QStandardItemModel *ItemModel;//操作ListView需要操作ItemModel
	QStringList client_ip;
	QList<QTcpSocket *> socketClient;//用于存放链接上来的客户端的Socket描述符
};

#endif // QTSERVER_H

           

qtcpserver.cpp

#include "qtserver.h"

QtServer::QtServer(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);
	MyServer  = new QTcpServer(this);
	ItemModel = new QStandardItemModel(this);

	//为了安全起见在关闭前需要释放资源,禁止点击窗口直接左上角的X关闭,必须要点击exit按钮
	setWindowFlags(Qt::CustomizeWindowHint|Qt::WindowMinimizeButtonHint|Qt::WindowMaximizeButtonHint);
	socketClient.clear();
	connect(ui.listen_pushButton,SIGNAL(clicked()),this,SLOT(on_listen_pushButton_clicked()),Qt::UniqueConnection);
	connect(ui.exit_pushButton,SIGNAL(clicked()),this,SLOT(on_exit_pushButton_clicked()),Qt::UniqueConnection);
}

QtServer::~QtServer()
{
	delete ItemModel;
	delete MyServer;
}

void QtServer::on_listen_pushButton_clicked()
{
	if(!MyServer->listen(QHostAddress::Any,1997))
	{
		QMessageBox::information(NULL,"Listen",QObject::tr("Listen error"));
	}
	else
	{
		//Qt::UniqueConnection -- 防止信号和槽多次连接
		connect(MyServer,SIGNAL(newConnection()),this,SLOT(handleConnect()),Qt::UniqueConnection);
	}
}

void QtServer::handleConnect()
{
	QTcpSocket *client = new QTcpSocket(this);
	client = MyServer->nextPendingConnection();
	socketClient.append(client);

	client_ip.clear();
	QString ip = client->peerAddress().toString();
	client_ip.append(ip);

	//连接上来的客户端的ip地址显示在主窗口的listView中
	for(int i = 0;i < client_ip.size();i++)
	{
		QString string = static_cast<QString>(client_ip.at(i));
		QStandardItem *item = new QStandardItem(string);
		ItemModel->appendRow(item);//加入每行的值
	}

	ui.client_listView->setModel(ItemModel);

	connect(client,SIGNAL(readyRead()),this,SLOT(return_data()),Qt::UniqueConnection);
	connect(client, SIGNAL(disconnected()),this,SLOT(handleDisconnect()));
}

//将接收到的信息转发到其他的客户端
void QtServer::return_data()
{
	char *buffer = new char[1024];
	memset(buffer,0,1024);
	QTcpSocket * sendclient = (QTcpSocket*)sender();//获取触发此槽函数的客户端的Socket
	sendclient->read(buffer,1024);
	foreach(QTcpSocket *sock,socketClient)
	{
		if(sock != sendclient)
			sock->write(buffer);
	}
	QString ip = sendclient->peerAddress().toString();
	ui.recv_textEdit->append(ip+" : "+buffer);
}


void QtServer::handleDisconnect()
{
	QTcpSocket * sendclient = (QTcpSocket*)sender();
	QString ip = sendclient->peerAddress().toString();//获取ip
	sendclient->close();//关闭此socket
	socketClient.removeOne(sendclient);//从链表中剔除
	//主窗口的listView移除此行
	QList<QStandardItem *> tList = ItemModel->findItems (ip);
	QStandardItem *tItem = tList.at(0);
	int row  = tItem->row();
	ItemModel->removeRow(row);
}

void QtServer::on_exit_pushButton_clicked()
{
	foreach(QTcpSocket *sock,socketClient)
	{
		sock->disconnectFromHost();
		sock->close();
	}
	MyServer->close();
	this->close();
}
           

main.cpp

#include "qtserver.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	QtServer w;
	w.show();
	return a.exec();
}

           

实例效果如下图

QTcpSocket学习笔记--TCP服务器一对多通信实例服务器的搭建步骤客户端的搭建步骤源码

另外求助一下各位大佬,我的主窗口上的textEdit为什么显示中文的时候是乱码,应该怎么解决

继续阅读