qt Tcp 聊天系统

为了熟悉qt’中的tcp使用方法特意写了个,简单的聊天系统。消息传输利用json进行传输,客户端能显示当前在线的人。

效果图如下

客户端效果图
在这里插入图片描述
在这里插入图片描述
服务端
在这里插入图片描述

源代码

服务端的源代码

//这是server.h
#ifndef SERVER_H_
#define SERVER_H_
#include<QObject>
#include<QTcpServer>
#include<QTcpSocket>
#include<QHash>

struct User
{
	User() = default;
	User(QTcpSocket* sock) :sock(sock) {}
	QString username;
	QTcpSocket* sock;
};


class Server :public QObject
{
	Q_OBJECT
public:
	Server(QObject * parent=nullptr);
	~Server();
	void init();
public slots:
	void onNewConnection();
	void onClientReadyRead();
private:
	QTcpServer* _tcpServer;
	QHash<QTcpSocket*, User*> _hashMaps;

};

#endif // !SERVER_H_

//这是server.cpp
#include "server.h"
#include <QDebug>
#include "../common/SJsonData.h"
Server::Server(QObject* parent)
	:QObject(parent),_tcpServer(new QTcpServer(this))
{
	init();
}

Server::~Server()
{
	for (auto user : _hashMaps)
	{
		user->sock->close();
	}
	_tcpServer->close();
}

void Server::init()
{

	if (!_tcpServer->listen(QHostAddress::Any, 8888)){
		qWarning() << "listen failed" << _tcpServer->errorString();
		return;
	}
	connect(_tcpServer, &QTcpServer::newConnection, this, &Server::onNewConnection);



}
void Server::onNewConnection()
{
	if (_tcpServer->hasPendingConnections()) {
		auto sock = _tcpServer->nextPendingConnection();
		connect(sock, &QTcpSocket::readyRead, this, &Server::onClientReadyRead);
		_hashMaps.insert(sock, new User(sock));
		//sock->write("hello client");
	}
}
//onNewConnection
void Server::onClientReadyRead()
{
	auto sock=dynamic_cast<QTcpSocket*>(sender());  //知道是谁发过来的
	if (!sock)
		return;
	
	auto data = sock->readAll();
	qInfo() << "server:\t" << data;
	SJsonData jd = SJsonData::fromJson(data);
	if (jd.stringValue("type") == "login") {
		auto username = jd.stringValue("username");
		_hashMaps.value(sock)->username = username;

		if(_hashMaps.size()>1){
			//这是发给当前登录的用户
			jd.clear();
			jd.addValue("type", "onLineUsers");
			QStringList list;
			for (auto user : _hashMaps) {
				if (user->sock != sock)
					list.append(user->username);
			}
			jd.addValue("users", list);
			sock->write(jd.toJson());
			//把当前登录的用户发给所有已经登录的用户
			SJsonData online;
			online.addValue("type", "userOnline");
			online.addValue("username", username);
			auto onlineData = online.toJson();
			for (auto user : _hashMaps) {
				if (user->sock != sock) {
					
					user->sock->write(onlineData);
				}
				list.append(user->username);
			}

		}
		
		
	}
	else if (jd.stringValue("type")=="chatMsg")
	{
		
		//转发给所有人
		for (auto user : _hashMaps)
		{
			if (user->sock != sock) {
				
				user->sock->write(jd.toJson());
			}
		}
	}



	qInfo() << "user counts:"<<_hashMaps.size();
	for (auto user : _hashMaps)
	{
		qInfo() << user->username;
	}
}

客户端代码

tcp连接进行封装

//这是 STcpConnection.h
#ifndef STCPCONNECTION_H_
#define STCPCONNECTION_H_
#include<QObject>
#include<QTcpSocket>
#include<QList>

#define BIND_MEMBER_FUN(fun) std::bind(fun, this, std::placeholders::_1)
#define BIND_FUN(fun) std::bind(fun,std::placeholders::_1)

class STcpConnection :public QObject
{
	Q_OBJECT
public:
	using ListenFun = std::function<void(QTcpSocket*)>;
public:
	STcpConnection(QObject *parent=nullptr);
	~STcpConnection();
	qint32 addListener(ListenFun fun);
	QTcpSocket* tcpSocket() { return _tcpSocket; }
	operator QTcpSocket* () { return _tcpSocket; }
	static STcpConnection* mainCon();

public :

	void onReadyread();

private:
	QTcpSocket* _tcpSocket;
	QList<ListenFun> _listener;
};


#endif // !STCPCONNECTION_H_

//这是 STcpConnection.cpp
#include "STcpConnection.h"

STcpConnection::STcpConnection(QObject* parent)
	:QObject(parent),_tcpSocket(new QTcpSocket(this))
{
	connect(_tcpSocket, &QTcpSocket::readyRead, this, &STcpConnection::onReadyread);

}

STcpConnection::~STcpConnection()
{
}

qint32 STcpConnection::addListener(ListenFun fun)
{
	_listener.append(fun);
	return _listener.size()-1;
}

STcpConnection* STcpConnection::mainCon()
{
	static STcpConnection* con = nullptr;
	if (!con) {
		con = new STcpConnection;
		//将localHost 更改为服务器地址
		con->_tcpSocket->connectToHost(QHostAddress::LocalHost, 8888);
		connect(*con, &QTcpSocket::connected, []() {
			qInfo() << "connect server success";
			
			});

		connect(*con, &QTcpSocket::disconnected, []() {
			qInfo() << "disconnect server success";

			});
		connect(*con, &QTcpSocket::errorOccurred, []() {
			qInfo() << "has error" << static_cast<QTcpSocket*>(*con)->errorString();

			});
	}


	return con;
}



void STcpConnection::onReadyread()
{

	while (_tcpSocket->bytesAvailable())
	{
		for (auto& fun : _listener) {
			fun(_tcpSocket);
		}
	}

}

关键代码已经贴出,整个项目的源码在文中附加资源 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值