提交源码

This commit is contained in:
筱傑
2018-12-09 21:25:07 +08:00
committed by GitHub
parent a280783e7f
commit f029404192
27 changed files with 2724 additions and 0 deletions

BIN
IM Porject/IM.mp4 Normal file

Binary file not shown.

51
IM Porject/IM/IM.pro Normal file
View File

@@ -0,0 +1,51 @@
#-------------------------------------------------
#
# Project created by QtCreator 2018-11-30T17:54:04
#
#-------------------------------------------------
QT += core gui network sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = IM
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp \
imclient.cpp \
formlogin.cpp \
imdal.cpp
HEADERS += \
mainwindow.h \
imclient.h \
protocol.h \
formlogin.h \
immessage.h \
imdal.h
FORMS += \
mainwindow.ui \
formlogin.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
resources.qrc

322
IM Porject/IM/IM.pro.user Normal file
View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.7.2, 2018-12-08T20:06:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{2d03fc4c-541a-4fa5-8f5c-ae92a1998dce}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey">
<value type="QString">-fno-delayed-template-parsing</value>
</valuelist>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5112.win32_mingw53_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IM-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IM-Desktop_Qt_5_11_2_MinGW_32bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IM-Desktop_Qt_5_11_2_MinGW_32bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">IM</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:E:/C++/Qt/IM/IM.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">IM.pro</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">E:/C++/Qt/build-IM-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

128
IM Porject/IM/formlogin.cpp Normal file
View File

@@ -0,0 +1,128 @@
#include "formlogin.h"
#include "ui_formlogin.h"
#include <QMessageBox>
#include "mainwindow.h"
FormLogin::FormLogin(QWidget *parent) :
QWidget(parent),
ui(new Ui::FormLogin)
{
ui->setupUi(this);
connect(IMClient::instance(), &IMClient::serverConnected, this, &FormLogin::serverConnected);
connect(IMClient::instance(), &IMClient::serverClose, this, &FormLogin::serverClose);
connect(IMClient::instance(), &IMClient::loginResult, this, &FormLogin::loginResult);
connect(IMClient::instance(), &IMClient::connectError, this, &FormLogin::connectError);
// 连接服务器
IMClient::instance()->connectServer(ui->leHostName->text().trimmed());
}
FormLogin::~FormLogin()
{
delete ui;
}
// 连接成功后将重试按钮什么的隐藏掉
void FormLogin::serverConnected()
{
ui->lblServerConnectState->clear();
ui->btnRetry->setHidden(true);
ui->leHostName->setHidden(true);
}
// 如果服务器关闭,那么程序跟着关闭
void FormLogin::serverClose()
{
QMessageBox::warning(this, "警告", "服务器已关闭,程序即将退出!");
QCoreApplication::quit();
}
// 如果连接发生错误,提示并将重试按钮显示
void FormLogin::connectError(QString ErrorInfo)
{
QMessageBox::critical(this, "连接失败", "错误信息:" + ErrorInfo);
ui->lblServerConnectState->setText("服务器连接失败!");
ui->btnRetry->setHidden(false);
ui->leHostName->setHidden(false);
}
// 当登录有结果时
void FormLogin::loginResult(bool isSuccess)
{
// 如果登录没有成功,将登录按钮设置为可用,并提示用户
if (!isSuccess)
{
QMessageBox::critical(this, "登录失败", "该用户名或连接已经登录!");
ui->btnLogin->setText("登 录");
ui->btnLogin->setEnabled(true);
ui->lineEdit->setEnabled(true);
return;
}
// 登录成功,启动主窗体
MainWindow *w = new MainWindow;
w->show();
this->close();
}
// 登录按钮按下时
void FormLogin::on_btnLogin_clicked()
{
// 获取用户名
QString username = ui->lineEdit->text().trimmed();
if (username.isEmpty())
{
QMessageBox::critical(this, "错误", "请输入用户名!");
return;
}
// 检测是否存在非法字符
bool isSpace = false;
for (int i = 0; i < username.length(); ++i)
{
if (username[i].isSpace()
|| username[i] == ':'
|| username[i] == '"'
|| username[i] == '/'
|| username[i] == '*'
|| username[i] == '|'
|| username[i] == '?'
|| username[i] == '<'
|| username[i] == '>')
{
isSpace = true;
break;
}
}
if (isSpace)
{
QMessageBox::critical(this, "错误", "用户名中有非法字符!");
return;
}
if (!IMClient::instance()->isOpen())
{
QMessageBox::critical(this, "错误", "未连接服务器!");
return;
}
// 尝试登录
IMClient::instance()->login(username);
ui->btnLogin->setText("登录中...");
ui->btnLogin->setEnabled(false);
ui->lineEdit->setEnabled(false);
}
// 当重试按钮按下时
void FormLogin::on_btnRetry_clicked()
{
// 如果连接已经打开了,就直接隐藏按钮
if (IMClient::instance()->isOpen())
{
ui->lblServerConnectState->clear();
ui->btnRetry->setHidden(true);
ui->leHostName->setHidden(true);
}
else
{
// 否则尝试重新连接服务器
IMClient::instance()->connectServer(ui->leHostName->text().trimmed());
}
}

39
IM Porject/IM/formlogin.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef FORMLOGIN_H
#define FORMLOGIN_H
#include <QWidget>
namespace Ui {
class FormLogin;
}
class FormLogin : public QWidget
{
Q_OBJECT
public:
explicit FormLogin(QWidget *parent = nullptr);
~FormLogin();
// 槽
private slots:
// 服务器连接成功时触发
void serverConnected();
// 服务器关闭时触发
void serverClose();
// 连接发生错误时触发
void connectError(QString ErrorInfo);
// 登录结果
// 参数isSuccess 是否登录成功
void loginResult(bool isSuccess);
void on_btnLogin_clicked();
void on_btnRetry_clicked();
private:
Ui::FormLogin *ui;
};
#endif // FORMLOGIN_H

130
IM Porject/IM/formlogin.ui Normal file
View File

@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormLogin</class>
<widget class="QWidget" name="FormLogin">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>IM</string>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>90</x>
<y>120</y>
<width>41</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>用户名:</string>
</property>
</widget>
<widget class="QPushButton" name="btnLogin">
<property name="geometry">
<rect>
<x>110</x>
<y>170</y>
<width>181</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>登 录</string>
</property>
</widget>
<widget class="QLabel" name="lblServerConnectState">
<property name="geometry">
<rect>
<x>0</x>
<y>280</y>
<width>131</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>服务器连接状态:未连接</string>
</property>
</widget>
<widget class="QPushButton" name="btnRetry">
<property name="geometry">
<rect>
<x>140</x>
<y>280</y>
<width>41</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>重试</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>180</x>
<y>40</y>
<width>31</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<property name="text">
<string>IM</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>140</x>
<y>120</y>
<width>151</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="leHostName">
<property name="geometry">
<rect>
<x>190</x>
<y>280</y>
<width>151</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

223
IM Porject/IM/imclient.cpp Normal file
View File

@@ -0,0 +1,223 @@
#include <QDateTime>
#include "imclient.h"
#include "protocol.h"
#include "imdal.h"
IMClient::IMClient(QObject *parent)
: QObject(parent),
m_socket(new QTcpSocket)
{
connect(m_socket, &QTcpSocket::connected, this, &IMClient::connected);
connect(m_socket, &QTcpSocket::readyRead, this, &IMClient::readyread);
connect(m_socket, &QTcpSocket::disconnected, this, &IMClient::disconnected);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
[this](QAbstractSocket::SocketError socketError){this->error(socketError);});
}
IMClient *IMClient::instance()
{
static IMClient imClient;
return &imClient;
}
IMClient::~IMClient()
{
qDebug() << "~IMClient";
if (m_socket != nullptr)
{
m_socket->close();
delete m_socket;
}
}
// 连接服务器
void IMClient::connectServer(QString hostName)
{
m_socket->connectToHost(hostName, 9876, QTcpSocket::ReadWrite);
}
// 登录
void IMClient::login(QString name)
{
this->m_name = name;
this->sendData(QString("%1 %2").arg(ClientFunctionCode::Login).arg(name));
}
// 发送私聊消息
void IMClient::sendPrivateMessage(QString toName, QString content)
{
// 发送消息到服务器
this->sendData(QString("%1 %2 %3").arg(ClientFunctionCode::SendPrivateMessage).arg(toName).arg(content));
// 构造消息对象用o表示是发出消息
IMMessage msg("o", content, QDateTime::currentDateTime());
// 将消息添加到聊天记录中
this->m_chatRecord[toName].append(msg);
// 将消息插入到数据库中
IMDAL::instance()->addPrivateMessage(toName, msg);
}
// 发送群聊消息
void IMClient::sendGroupMessage(QString content)
{
// 发送消息到服务器
this->sendData(QString("%1 %2").arg(ClientFunctionCode::SendGroupMessage).arg(content));
// 构造消息对象
IMMessage msg(this->m_name, content, QDateTime::currentDateTime());
// 将消息添加到聊天记录中
this->m_gruopChatRecord.append(msg);
// 将消息插入到数据库中
IMDAL::instance()->addGroupMessage(msg);
}
const QVector<IMMessage> *IMClient::getChatRecord(QString name)
{
if (!this->m_chatRecord.contains(name))
this->m_chatRecord[name] = IMDAL::instance()->getPrivateMessage(name);
return &this->m_chatRecord[name];
}
// 连接成功时触发
void IMClient::connected()
{
qDebug() << "connected";
emit serverConnected();
}
// 当接收到数据时触发
void IMClient::readyread()
{
// 获取接收到数据的对象
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
// 获取数据
QByteArray data = sender->readAll();
QTextStream in(data, QIODevice::ReadOnly);
qDebug() << "readyread:" << data;
// 进行协议分析与任务调度
int functionID = 0;
in >> functionID;
switch (functionID) {
case ServerFunctionCode::PrivateMessage:
{
// 如果是私聊消息,获取发送者昵称,然后发出获取到私聊消息的信号
QString fromName;
in >> fromName;
in.seek(in.pos() + 1);
// 构造一个消息对象,发送者用'i'表示是接受到的消息
IMMessage msg("i", in.readAll(), QDateTime::currentDateTime());
// 将它添加到聊天记录中
this->m_chatRecord[fromName].append(msg);
// 并且插入数据库
IMDAL::instance()->addPrivateMessage(fromName, msg);
// 然后将发送者改回原来的名称
msg.fromName = fromName;
// 通过信号将其传递出去
emit receivedPrivateMessage(msg);
}break;
case ServerFunctionCode::GroupMessage:
{
// 如果是群聊消息,获取发送者昵称,然后发出获取到群聊消息的信号
QString fromName;
in >> fromName;
in.seek(in.pos() + 1);
// 构造一个消息对象
IMMessage msg(fromName, in.readAll(), QDateTime::currentDateTime());
// 添加到聊天记录中
this->m_gruopChatRecord.append(msg);
// 添加到数据库中
IMDAL::instance()->addGroupMessage(msg);
// 发出信号
emit receivedGroupMessage(msg);
}break;
case ServerFunctionCode::UserOnline:
{
// 如果是用户上线,获取发送者昵称,然后发出用户上线信号
QString fromName;
in >> fromName;
if (m_offline.contains(fromName))
m_offline.removeOne(fromName);
m_online.append(fromName);
emit userOnline(fromName);
}break;
case ServerFunctionCode::UserOffline:
{
// 如果是用户下线,获取发送者昵称,然后发出用户下线信号
QString fromName;
in >> fromName;
if (m_online.contains(fromName))
m_online.removeOne(fromName);
m_offline.append(fromName);
emit userOffline(fromName);
}break;
case ServerFunctionCode::LoginResult:
{
// 如果是登录有结果了,先获取登录结果
int result = 0;
in >> result;
if (result == 0)
{
// 如果登录成功了,获取当前在线人数
int n = 0;
in >> n;
QVector<QString> names;
QString name;
for (int i = 0; i < n; i++)
{
in >> name;
names.push_back(name);
}
this->m_online = names;
// 初始化数据库
IMDAL::instance()->initDatabase(this->m_name);
// 获取数据库中有聊天记录的用户名列表
QVector<QString> userList = IMDAL::instance()->getUserList();
// 将没上线的用户名添加到离线列表中
for (int i = 0; i < userList.length(); i++)
{
// 如果这个名字在在线列表中不存在同时又不是自己
if (!this->m_online.contains(userList[i]) && userList[i] != this->m_name)
{
// 就添加到离线列表中
this->m_offline.append(userList[i]);
}
}
// 初始化群聊消息
this->m_gruopChatRecord = IMDAL::instance()->getGroupMessage();
// 最后发送登录成功消息
emit loginResult(true);
}
else
{
// 否则就是登录失败了,发送登录失败的消息
emit loginResult(false);
}
}break;
default:
return;
}
}
// 当连接断开时触发
void IMClient::disconnected()
{
qDebug() << "disconnected";
// 发送服务器关闭信号
emit serverClose();
}
// 当连接发生错误时触发
void IMClient::error(QAbstractSocket::SocketError socketError)
{
qDebug() << socketError;
// 发出连接错误信号
emit connectError(this->m_socket->errorString());
}
// 向服务器发送数据方法
void IMClient::sendData(QString data)
{
if (this->isOpen())
this->m_socket->write(data.toUtf8());
}

204
IM Porject/IM/imclient.h Normal file
View File

@@ -0,0 +1,204 @@
#ifndef IMCLIENT_H
#define IMCLIENT_H
#include <QObject>
#include <QtNetwork>
#include <QString>
#include <QVector>
#include "immessage.h"
/***********************************
*
* Class IMClient
* IM客户端类
*
* 用于与服务端交互的封装类
*
* 公开方法有:
* login 登录
* sendPrivateMessage 发送私聊消息
* sendGroupMessage 发送群聊消息
*
* 发出的信号有:
* receivedPrivateMessage 接收到私聊消息信号
* receivedGroupMessage 接收到群聊消息信号
* userOnline 用户上线信号
* userOffline 用户下线信号
* serverClose 服务器关闭信号
*
**********************************/
/**
* @brief IM客户端类
*/
class IMClient : public QObject
{
Q_OBJECT
// 公开的成员函数
protected:
explicit IMClient(QObject *parent = nullptr);
public:
/**
* @brief instance 单例对象
* @return 单例对象指针
*/
static IMClient *instance();
~IMClient();
/**
* @brief connectServer 尝试连接服务器
* @param hostName 连接名
*/
void connectServer(QString hostName);
/**
* @brief login 登录
* @param name 用户名
*/
void login(QString name);
/**
* @brief sendPrivateMessage 发送私聊消息
* @param toName 发送给谁
* @param content 消息内容
*/
void sendPrivateMessage(QString toName, QString content);
/**
* @brief sendGroupMessage 发送群聊消息
* @param content 消息内容
*/
void sendGroupMessage(QString content);
/**
* @brief isOpen 连接是否打开
* @return
*/
bool isOpen()
{
return this->m_socket != nullptr
&& this->m_socket->state() != QAbstractSocket::UnconnectedState;
}
public:
const QVector<IMMessage> *getChatRecord(QString name);
const QVector<IMMessage> *getGroupChatRecord() { return &m_gruopChatRecord; }
const QVector<QString> *getOnlineList() { return &m_online; }
const QVector<QString> *getOfflineList() { return &m_offline; }
QString getName() { return m_name; }
// 信号
signals:
/**
* @brief loginResult 登录结果
* @param isSuccess 是否登录成功
*/
void loginResult(bool isSuccess);
/**
* @brief receivedPrivateMessage 接收到私聊消息信号
* @param msg 消息内容
*/
void receivedPrivateMessage(IMMessage msg);
/**
* @brief receivedGroupMessage 接收到群聊消息信号
* @param msg 消息内容
*/
void receivedGroupMessage(IMMessage msg);
/**
* @brief userOnline 用户上线信号
* @param fromName 上线者昵称
*/
void userOnline(QString fromName);
/**
* @brief userOffline 用户下线信号
* @param fromName 下线者昵称
*/
void userOffline(QString fromName);
/**
* @brief serverConnected 服务器连接成功信号
*/
void serverConnected();
/**
* @brief serverClose 服务器关闭信号
*/
void serverClose();
/**
* @brief connectError 连接发生错误信号
* @param ErrorInfo 错误信息文本说明
*/
void connectError(QString ErrorInfo);
// 槽
public slots:
/**
* @brief connected 连接成功时触发
*/
void connected();
/**
* @brief readyread 当接收到数据时触发
*/
void readyread();
/**
* @brief disconnected 当连接断开时触发
*/
void disconnected();
/**
* @brief error 当连接发生错误时触发
* @param socketError 错误信息
*/
void error(QAbstractSocket::SocketError socketError);
// 私有成员函数
private:
/**
* @brief sendData 发送数据到服务器
* @param data 数据
*/
void sendData(QString data);
// 私有的成员变量
private:
/**
* @brief 当前登录的用户昵称
*/
QString m_name;
/**
* @brief 客户端的Tcp Socket对象
*/
QTcpSocket *m_socket;
/**
* @brief 在线人员昵称列表
*/
QVector<QString> m_online;
/**
* @brief 离线人员昵称列表
*/
QVector<QString> m_offline;
/**
* @brief 私聊的聊天记录
*/
QMap<QString, QVector<IMMessage> > m_chatRecord;
/**
* @brief 群聊的聊天记录
*/
QVector<IMMessage> m_gruopChatRecord;
};
#endif // IMCLIENT_H

241
IM Porject/IM/imdal.cpp Normal file
View File

@@ -0,0 +1,241 @@
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QVector>
#include <QString>
#include <QDebug>
#include "imdal.h"
#include "immessage.h"
IMDAL *IMDAL::instance()
{
static IMDAL imDAL;
return &imDAL;
}
void IMDAL::initDatabase(QString name)
{
//打印Qt支持的数据库驱动
qDebug()<<QSqlDatabase::drivers();
QSqlDatabase database;
// 检测默认连接是否已经存在
if (QSqlDatabase::contains(QSqlDatabase::defaultConnection))
{
// 存在就直接用
database = QSqlDatabase::database(QSqlDatabase::defaultConnection);
}
else
{
// 不存在就添加一个数据库驱动引擎SQLite
database = QSqlDatabase::addDatabase("QSQLITE");
// 然后打开指定用户的数据库文件
database.setDatabaseName(QString("./msgsave_%1.db").arg(name));
// database.setUserName("root");
// database.setPassword("123456");
}
//打开数据库
if(!database.open())
{
// 如果打开失败 退出程序
qDebug()<<database.lastError();
qFatal("failed to connect.");
}
else
{
qDebug() << "Open database success!";
QStringList tables = database.tables(); //获取数据库中的表
qDebug() << QString("表的个数: %1").arg(tables.count()); //打印表的个数
// 如果表的数量小于3说明这是一个新用户登录
if (tables.count() < 3)
{
/*
SQL语句
CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR NOT NULL
UNIQUE
);
INSERT INTO user (
name
)
VALUES (
'xxx'
);
CREATE TABLE message (
id INTEGER PRIMARY KEY AUTOINCREMENT,
fromID INTEGER NOT NULL
REFERENCES user ( id ) ON DELETE CASCADE
ON UPDATE CASCADE,
content TEXT NOT NULL,
time DATETIME NOT NULL
DEFAULT ( datetime( 'now', 'localtime' ) ),
io CHAR NOT NULL
);
io这个字段代表是发送还是接受i收到消息 o发出消息 g群聊消息
*/
database.transaction();
QSqlQuery query;
// 创建表并将用户昵称插入表中作为第一条数据存在id为1
query.exec("CREATE TABLE user ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name VARCHAR NOT NULL UNIQUE);");
query.exec(QString("INSERT INTO user(name) values('%1');").arg(name));
query.exec("CREATE TABLE message ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"fromID INTEGER NOT NULL REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE,"
"content TEXT NOT NULL,"
"time DATETIME NOT NULL DEFAULT(datetime('now','localtime')),"
"io CHAR NOT NULL);");
if (!database.commit())
qDebug()<<database.lastError();
}
}
}
void IMDAL::addPrivateMessage(QString name, IMMessage msg)
{
if (!QSqlDatabase::database().isOpen())
return;
// 获得用户ID
int userID = getUserID(name);
if (userID == 0)
return;
// 插入这条私聊消息
QSqlQuery query;
query.prepare("INSERT INTO message(fromID, content, time, io) "
"VALUES(?, ?, ?, ?)");
query.addBindValue(userID);
query.addBindValue(msg.content);
query.addBindValue(msg.time);
query.addBindValue(msg.fromName);
if (!query.exec())
qDebug()<<query.lastError();
}
void IMDAL::addGroupMessage(IMMessage msg)
{
if (!QSqlDatabase::database().isOpen())
return;
// 获取用户ID
int userID = getUserID(msg.fromName);
if (userID == 0)
return;
// 插入这条群聊消息
QSqlQuery query;
query.prepare("INSERT INTO message(fromID, content, time, io) "
"VALUES(?, ?, ?, 'g')");
query.addBindValue(userID);
query.addBindValue(msg.content);
query.addBindValue(msg.time);
if (!query.exec())
qDebug()<<query.lastError();
}
QVector<IMMessage> IMDAL::getPrivateMessage(QString name)
{
QVector<IMMessage> msgList;
int userID = 0;
if (!QSqlDatabase::database().isOpen())
return msgList;
QSqlQuery query;
query.prepare("SELECT id FROM user WHERE name = ?");
query.addBindValue(name);
if(!query.exec())
{
qDebug()<<query.lastError();
return msgList;
}
// 获取这个昵称的id
while(query.next())
userID = query.value(0).toInt();
// 如果没有这个人的记录,直接返回空
if (userID == 0)
return msgList;
// 否则查找这个用户的消息
query.prepare("SELECT io, content, time FROM message WHERE fromID = ? AND io != 'g'");
query.addBindValue(userID);
if(!query.exec())
{
qDebug()<<query.lastError();
return msgList;
}
// 将所有消息添加到列表中
while(query.next())
msgList.append(IMMessage(query.value(0).toString(), query.value(1).toString(), query.value(2).toDateTime()));
return msgList;
}
QVector<IMMessage> IMDAL::getGroupMessage()
{
QVector<IMMessage> msgList;
if (!QSqlDatabase::database().isOpen())
return msgList;
QSqlQuery query;
if(!query.exec("SELECT name, content, time FROM message,user WHERE io == 'g' AND user.id = fromID"))
{
qDebug()<<query.lastError();
return msgList;
}
// 将所有消息添加到列表中
while(query.next())
msgList.append(IMMessage(query.value(0).toString(), query.value(1).toString(), query.value(2).toDateTime()));
return msgList;
}
QVector<QString> IMDAL::getUserList()
{
qDebug() << "getUserList()";
QVector<QString> names;
if (!QSqlDatabase::database().isOpen())
return names;
QSqlQuery query;
if (!query.exec("SELECT name FROM user"))
{
qDebug()<<query.lastError();
}
else
{
while (query.next())
names.append(query.value(0).toString());
}
qDebug() << names;
return names;
}
int IMDAL::getUserID(QString name)
{
QSqlQuery query;
int userID = 0;
query.prepare("SELECT id FROM user WHERE name = ?");
query.addBindValue(name);
if(!query.exec())
{
qDebug()<<query.lastError();
return 0;
}
// 获取这个昵称的id
while(query.next())
userID = query.value(0).toInt();
if (userID)
return userID;
// 如果没有这个人的记录那么就创建这个人的ID
query.prepare("INSERT INTO user(name) VALUES(?)");
query.addBindValue(name);
if(!query.exec())
{
qDebug()<<query.lastError();
return 0;
}
return query.lastInsertId().toInt();
}

59
IM Porject/IM/imdal.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef IMDAL_H
#define IMDAL_H
#include <QVector>
#include <QString>
#include "immessage.h"
// IM数据层
class IMDAL
{
public:
/**
* @brief instance 单例对象
* @return 单例对象指针
*/
static IMDAL *instance();
/**
* @brief initDatabase 初始化数据库
* @param name 用户名
*/
void initDatabase(QString name);
/**
* @brief addPrivateMessage 添加一条私聊消息
* @param name 用户名
* @param msg 消息内容
*/
void addPrivateMessage(QString name, IMMessage msg);
/**
* @brief addGroupMessage 添加一条群聊消息
* @param msg 消息内容
*/
void addGroupMessage(IMMessage msg);
/**
* @brief getPrivateMessage 获取私聊消息
* @param name 对方昵称
* @return 消息内容
*/
QVector<IMMessage> getPrivateMessage(QString name);
/**
* @brief getGroupMessage 获取群聊消息
* @return 消息内容
*/
QVector<IMMessage> getGroupMessage();
/**
* @brief getUserList 获取用户列表
* @return 用户列表
*/
QVector<QString> getUserList();
private:
int getUserID(QString name);
};
#endif // IMDAL_H

33
IM Porject/IM/immessage.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef IMMESSAGE_H
#define IMMESSAGE_H
#include <QString>
#include <QDateTime>
struct IMMessage
{
IMMessage(){}
IMMessage(QString fromName, QString content, QDateTime time)
: fromName(fromName),
content(content),
time(time) {}
/**
* @brief fromName 发送者
*/
QString fromName;
/**
* @brief content 内容
*/
QString content;
/**
* @brief time 时间
*/
QDateTime time;
};
#endif // IMMESSAGE_H

14
IM Porject/IM/main.cpp Normal file
View File

@@ -0,0 +1,14 @@
#include "formlogin.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec);
// 启动登录窗口
FormLogin l;
l.show();
return a.exec();
}

View File

@@ -0,0 +1,190 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QListWidget>
#include <QListWidgetItem>
#include <QDebug>
#include <QDateTime>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(IMClient::instance(), &IMClient::receivedPrivateMessage, this, &MainWindow::receivedPrivateMessage);
connect(IMClient::instance(), &IMClient::receivedGroupMessage, this, &MainWindow::receivedGroupMessage);
connect(IMClient::instance(), &IMClient::userOnline, this, &MainWindow::userOnline);
connect(IMClient::instance(), &IMClient::userOffline, this, &MainWindow::userOffline);
connect(IMClient::instance(), &IMClient::serverClose, this, &MainWindow::serverClose);
// 初始化好友列表
ui->listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
updateUserList();
// 设置窗口标题
this->setWindowTitle("IM:" + IMClient::instance()->getName());
}
MainWindow::~MainWindow()
{
delete ui;
}
// 当发送按钮被点击时
void MainWindow::on_btnSend_clicked()
{
// 获取输入框的内容
QString text = ui->plainTextEdit->toPlainText();
if (text.isEmpty())
return;
// 如果要发送的文本大于255提示超出范围并返回
if (text.length() > 255)
{
QMessageBox::warning(this, "警告", "您输入的文本太长");
return;
}
// 如果当前没有选中任何人,提示并返回
if (ui->listWidget->currentItem() == nullptr)
{
QMessageBox::information(this, "提示", "请选择对话对象!");
return;
}
// 验证通过后清空输入框
ui->plainTextEdit->clear();
// 用自己的名字组装消息结构
IMMessage msg(IMClient::instance()->getName(), text, QDateTime::currentDateTime());
// 添加到对话框中
this->addMessage(msg);
// 如果当前选中的是群聊,发送群聊消息,否则发送私聊消息
if (ui->listWidget->currentItem() == this->pGruopItem)
IMClient::instance()->sendGroupMessage(text);
else
IMClient::instance()->sendPrivateMessage(ui->listWidget->currentItem()->text(), text);
}
// 接收到私聊消息时
void MainWindow::receivedPrivateMessage(IMMessage msg)
{
// 如果当前没有选中发消息这个人,直接返回(优化的话就是新消息提醒)
if (ui->listWidget->currentItem() == nullptr)
return;
if (ui->listWidget->currentItem() == this->pGruopItem)
return;
if (ui->listWidget->currentItem()->text() != msg.fromName)
return;
// 将消息添加到对话框中
this->addMessage(msg);
}
void MainWindow::receivedGroupMessage(IMMessage msg)
{
if (ui->listWidget->currentItem() == this->pGruopItem)
this->addMessage(msg);
}
void MainWindow::userOnline(QString fromName)
{
updateUserList();
QMessageBox::information(nullptr, "提示", fromName + " 已上线");
}
void MainWindow::userOffline(QString fromName)
{
updateUserList();
QMessageBox::information(nullptr, "提示", fromName + " 已下线");
}
void MainWindow::serverClose()
{
QMessageBox::warning(this, "警告", "服务器已经关闭,程序即将退出!");
QApplication::quit();
}
// 更新用户列表
void MainWindow::updateUserList()
{
ui->listWidget->setCurrentItem(nullptr);
int n = ui->listWidget->count();
// 清空表,重新加载
for (int i = 0; i < n; i++)
delete ui->listWidget->takeItem(0);
// 添加群聊项在表中
pGruopItem = new QListWidgetItem(QIcon(":icons/images/group.png"), "群聊");
ui->listWidget->addItem(pGruopItem);
// 添加在线人员在表中
const QVector<QString> *pUserList = IMClient::instance()->getOnlineList();
for (int i = 0; i < pUserList->length(); i++)
ui->listWidget->addItem(new QListWidgetItem(QIcon(":icons/images/userOnline.png"), pUserList->at(i)));
// 添加离线人员到表中
pUserList = IMClient::instance()->getOfflineList();
for (int i = 0; i < pUserList->length(); i++)
ui->listWidget->addItem(new QListWidgetItem(QIcon(":icons/images/userOffline.png"), pUserList->at(i)));
}
void MainWindow::setChatRecord(const QVector<IMMessage> *chatRecord, const QString *name)
{
// 清空聊天框
ui->textBrowser->clear();
// 如果是空的直接返回
if (chatRecord == nullptr)
return;
// 如果name为空表示是群聊消息
if (name == nullptr)
{
// 群聊消息直接添加即可
for (int i = 0; i < chatRecord->length(); ++i)
this->addMessage(chatRecord->at(i));
}
else
{
// 私聊消息需要经过转换因为私聊消息的fromName使用i和o来代表接收或者发出
for (int i = 0; i < chatRecord->length(); ++i)
{
IMMessage msg = chatRecord->at(i);
// 如果是i表示接收的消息用传进来的名字代替否则是接收的消息用自己的名字来代替
msg.fromName = msg.fromName == "i" ? *name : IMClient::instance()->getName();
this->addMessage(msg);
}
}
}
void MainWindow::addMessage(const IMMessage &msg)
{
QString timeStr;
// 选择时间的格式 如果是同一天,那么时间就按 12:00:00 这种格式显示
if (msg.time.date() > QDateTime::currentDateTime().date().addDays(-1))
timeStr = msg.time.toString("HH:mm:ss");
// 否则如果超过一天,但是小于一年,则显示月份日期 12/10 12:00:00
else if (msg.time.date() > QDateTime::currentDateTime().date().addYears(-1))
timeStr = msg.time.toString("MM/dd HH:mm:ss");
// 否则显示年份
else
timeStr = msg.time.toString("yyyy/MM.dd HH:mm:ss");
// 显示文本
ui->textBrowser->append(QString("<font color=\"%1\">%2 %3</font>").arg(msg.fromName == IMClient::instance()->getName() ? "#008040" : "#0000ff").arg(msg.fromName).arg(timeStr));
ui->textBrowser->insertPlainText(QString("\n %1\n").arg(msg.content));
ui->textBrowser->moveCursor(QTextCursor::End);
}
void MainWindow::on_listWidget_itemClicked(QListWidgetItem *item)
{
// 如果选中项为空,那就清空对话框
if (item == nullptr)
this->setChatRecord(nullptr);
// 如果选中了群聊选项,加载群聊的聊天记录
if (item == this->pGruopItem)
this->setChatRecord(IMClient::instance()->getGroupChatRecord());
else
{
// 否则就是选中了用户,读取这个用户的聊天记录
QString name = item->text();
this->setChatRecord(IMClient::instance()->getChatRecord(name), &name);
}
}

View File

@@ -0,0 +1,83 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidgetItem>
#include <QVector>
#include "imclient.h"
#include "immessage.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_btnSend_clicked();
void on_listWidget_itemClicked(QListWidgetItem *item);
public slots:
/**
* @brief receivedPrivateMessage 接收到私聊消息时触发
* @param msg 消息内容
*/
void receivedPrivateMessage(IMMessage msg);
/**
* @brief receivedGroupMessage 接收到群聊消息时触发
* @param msg 消息内容
*/
void receivedGroupMessage(IMMessage msg);
/**
* @brief userOnline 用户上线时触发
* @param fromName 上线者昵称
*/
void userOnline(QString fromName);
/**
* @brief userOffline 用户下线时触发
* @param fromName 下线者昵称
*/
void userOffline(QString fromName);
/**
* @brief serverClose 服务器关闭时触发
*/
void serverClose();
private:
/**
* @brief updateUserList 更新用户列表
*/
void updateUserList();
/**
* @brief setChatRecord 设置当前聊天记录
* @param chatRecord 聊天记录内容
*/
void setChatRecord(const QVector<IMMessage> *chatRecord, const QString *name = nullptr);
/**
* @brief addMessage 添加一条消息
* @param msg 消息内容
*/
void addMessage(const IMMessage &msg);
private:
Ui::MainWindow *ui;
/**
* @brief pGruopItem 群聊项指针
*/
QListWidgetItem *pGruopItem;
};
#endif // MAINWINDOW_H

149
IM Porject/IM/mainwindow.ui Normal file
View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>800</width>
<height>500</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>500</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QTextBrowser" name="textBrowser">
<property name="geometry">
<rect>
<x>240</x>
<y>7</y>
<width>561</width>
<height>371</height>
</rect>
</property>
<property name="cursor" stdset="0">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
<widget class="QPlainTextEdit" name="plainTextEdit">
<property name="geometry">
<rect>
<x>240</x>
<y>400</y>
<width>561</width>
<height>71</height>
</rect>
</property>
<property name="cursor" stdset="0">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
<widget class="QPushButton" name="btnSend">
<property name="geometry">
<rect>
<x>720</x>
<y>470</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Send</string>
</property>
<property name="shortcut">
<string>Return</string>
</property>
</widget>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>230</x>
<y>390</y>
<width>571</width>
<height>111</height>
</rect>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255)</string>
</property>
</widget>
<widget class="QWidget" name="widget_2" native="true">
<property name="geometry">
<rect>
<x>230</x>
<y>0</y>
<width>571</width>
<height>388</height>
</rect>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255)</string>
</property>
</widget>
<widget class="QWidget" name="widget_3" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>229</width>
<height>501</height>
</rect>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255)</string>
</property>
<widget class="QListWidget" name="listWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>218</width>
<height>481</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</widget>
<zorder>widget_3</zorder>
<zorder>widget_2</zorder>
<zorder>widget</zorder>
<zorder>textBrowser</zorder>
<zorder>plainTextEdit</zorder>
<zorder>btnSend</zorder>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

59
IM Porject/IM/protocol.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
/************************************************
* IM通讯协议规定
*
* 功能码 [参数]
*
* 客户端功能码规定: 参数: 例子: 说明:
* 1 = 请求登录 用户昵称 1 张三 当客户端登录时必须先发送这条命令,告诉服务端自己的昵称
* 2 = 发送私聊消息 私聊对象 消息内容 2 李四 你妈喊你回家吃饭 当A向B发送一条私聊消息时A要向服务器发送这条指令告诉服务器消息发给谁和发什么消息
* 3 = 发送群聊消息 消息内容 3 大家好,我是张三 当A向群聊发送一条消息时直接告诉服务端需要发什么内容即可
*
* 服务端功能码规定: 参数: 例子: 说明:
* 1 = 发送私聊消息 用户昵称 消息内容 1 张三 你妈喊你回家吃饭 当A向B发送一条私聊消息时B会收到这条指令其中昵称是指A发送者的昵称
* 2 = 发送群聊消息 用户昵称 消息内容 2 张三 大家好,我是张三 当A向群聊发送一条消息时所有人都会收到这条指令其中昵称是指A发送者的昵称
* 3 = 某人上线 用户昵称 3 张三 当A上线时所有人都会收到这条指令其中昵称是A上线者的昵称
* 4 = 某人下线 用户昵称 4 张三 当A下线时所有人都会手套这条指令其中昵称是A下线者的昵称
* 10 = 登录结果 是否成功(0:成功,!0:失败) [当前在线人数] [当前在线人员列表]
* 成功时 10 0 4 张三 李四 王五 赵六 当客户端发送登录请求后,如果登录成功则返回当前在线人数与昵称列表,如果失败就返回一个!0值
* 失败时 10 1
*
***********************************************/
/**
* @brief 服务端功能码
*/
enum ServerFunctionCode {
// 私聊消息
PrivateMessage = 1,
// 群聊消息
GroupMessage = 2,
// 用户上线
UserOnline = 3,
// 用户下线
UserOffline = 4,
// 登录结果
LoginResult = 10
};
/**
* @brief 客户端功能码
*/
enum ClientFunctionCode {
// 登录
Login = 1,
// 发送私聊消息
SendPrivateMessage = 2,
// 发送群聊消息
SendGroupMessage = 3
};
#endif // PROTOCOL_H

View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/icons">
<file>images/group.png</file>
<file>images/userOffline.png</file>
<file>images/userOnline.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,29 @@
QT -= gui
QT += network
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
imservice.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
imservice.h \
protocol.h

View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.7.2, 2018-12-08T20:06:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{2d03fc4c-541a-4fa5-8f5c-ae92a1998dce}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey">
<value type="QString">-fno-delayed-template-parsing</value>
</valuelist>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.11.2 MinGW 32bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5112.win32_mingw53_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">IMService</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:E:/C++/Qt/IMService/IMService.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">IMService.pro</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">E:/C++/Qt/build-IMService-Desktop_Qt_5_11_2_MinGW_32bit-Debug</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>

View File

@@ -0,0 +1,229 @@
#include "imservice.h"
#include "protocol.h"
#include <QDebug>
// 构造函数
IMService::IMService(QObject *parent)
: QObject(parent),
m_server(new QTcpServer),
m_clientSocket(new QMap<QString, QTcpSocket *>),
m_clientNames(new QMap<QTcpSocket *, QString>)
{
connect(this->m_server, &QTcpServer::newConnection, this, &IMService::newConnection);
if (this->m_server->listen(QHostAddress::Any, 9876))
qDebug() << "Service open SUCCESS!";
else
qDebug() << this->m_server->errorString(); //错误信息
}
IMService::~IMService()
{
m_server->close();
delete m_server;
delete m_clientSocket;
delete m_clientNames;
qDebug() << "Service Close!";
}
void IMService::closeService()
{
// 遍历并关闭所有Socket连接
for (auto it : *(this->m_clientSocket))
it->close();
// 清空表
this->m_clientSocket->clear();
this->m_clientNames->clear();
}
// 当有新连接进入时
void IMService::newConnection()
{
// 获取这个连接的Socket
QTcpSocket *socketTemp = this->m_server->nextPendingConnection();
// 当接收到数据时触发readyRead
connect(socketTemp, &QTcpSocket::readyRead, this, &IMService::readyRead);
// 当连接断开时触发disconnected
connect(socketTemp, &QTcpSocket::disconnected, this, &IMService::disconnected);
qDebug() << "newConnection!";
}
// 当连接断开时触发
void IMService::disconnected()
{
qDebug() << "disconnected!";
// 获取断开连接的对象
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
// 释放内存
sender->deleteLater();
// 先查一下这个连接是否存在表中如果没在说明这个连接没上线直接return即可
if (!this->m_clientNames->contains(sender))
return;
// 否则说明这是一个在线用户断开连接
// 记录这个用户的昵称
QString senderName = this->m_clientNames->value(sender);
// 将这个用户从表中移除
this->m_clientSocket->remove(senderName);
this->m_clientNames->remove(sender);
// 通知其他人该用户离线
this->userOffline(senderName);
}
// 当接收到数据时触发
void IMService::readyRead()
{
// 获取接收到数据的对象
QTcpSocket* sender = static_cast<QTcpSocket*>(QObject::sender());
// 获取数据
QByteArray data = sender->readAll();
QTextStream in(data, QIODevice::ReadOnly);
qDebug() << "readyread:" << data;
// 进行协议分析与任务调度
int functionID = 0;
in >> functionID;
// 如果是登录的功能码
if (functionID == ClientFunctionCode::Login)
{
QString name;
in >> name;
// 执行登录
this->userLogin(name, sender);
}
// 检测这个连接有没有登录
else if (this->m_clientNames->contains(sender))
{
// 如果是私聊消息
if (functionID == ClientFunctionCode::SendPrivateMessage)
{
// 获取要发送的用户昵称
QString toName;
in >> toName;
in.seek(in.pos() + 1);
// 将剩下的内容全部发送
this->sendPrivateMessage(this->m_clientNames->value(sender), toName, in.readAll());
}
// 否则如果是群聊消息
else if (functionID == ClientFunctionCode::SendGroupMessage)
{
in.seek(in.pos() + 1);
this->sendGroupMessage(this->m_clientNames->value(sender), in.readAll());
}
}
}
void IMService::sendData(QTcpSocket *socket, QString data)
{
if (socket != nullptr && socket->isOpen())
socket->write(data.toUtf8());
}
/*
enum ServerFunctionCode {
// 私聊消息
PrivateMessage = 1,
// 群聊消息
GroupMessage = 2,
// 用户上线
UserOnline = 3,
// 用户下线
UserOffline = 4,
// 登录结果
LoginResult = 10
};
*/
// 用户登录
// 参数name 用户昵称
void IMService::userLogin(QString name, QTcpSocket *socket)
{
qDebug() << "userLogin(): user name:" << name << "\tsocket:" << socket;
// 如果这个昵称或者连接已经登录了
if (this->m_clientSocket->contains(name) || this->m_clientNames->contains(socket))
{
qDebug() << "Login failed!";
// 发送登录结果:登录失败
this->sendData(this->m_clientSocket->value(name), QString("%1 1").arg(ServerFunctionCode::LoginResult));
}
else
{
qDebug() << "Login success!";
// 获取当前在线的用户昵称
QList<QString> temp = this->m_clientSocket->keys();
this->m_clientSocket->insert(name, socket);
this->m_clientNames->insert(socket, name);
// 将所有在线用户的昵称组合
QString ret = QString("%1 0 %2").arg(ServerFunctionCode::LoginResult).arg(temp.length());
QTextStream ts(&ret);
for (QString it : temp)
ts << ' ' << it;
qDebug() << "ret:" << ret;
// 发送登录结果:登录成功! 并返回当前在线人员数据
this->sendData(this->m_clientSocket->value(name), ret);
// 通知其他人改用户上线
this->userOnline(name);
}
}
// 发送私聊消息
// 参数:fromName 发送者昵称
// 参数:toName 接收者昵称
// 参数:content 内容
void IMService::sendPrivateMessage(QString fromName, QString toName, QString content)
{
qDebug() << "sendPrivateMessage(): fromName:" << fromName << "\ttoName" << toName << "\tcontent" << content;
// 如果该用户存在才发送
if (this->m_clientSocket->contains(toName))
this->sendData(this->m_clientSocket->value(toName), QString("%1 %2 %3").arg(ServerFunctionCode::PrivateMessage).arg(fromName).arg(content));
}
// 发送群聊消息
// 参数:fromName 发送者昵称
// 参数:content 内容
void IMService::sendGroupMessage(QString fromName, QString content)
{
qDebug() << "sendGroupMessage(): fromName:" << fromName << "\tcontent" << content;
QString data = QString("%1 %2 %3").arg(ServerFunctionCode::GroupMessage).arg(fromName).arg(content);
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
if (it.key() != fromName)
this->sendData(it.value(), data);
}
// 用户上线
// 参数:name 用户昵称
void IMService::userOnline(QString name)
{
qDebug() << "userOnline(): name:" << name;
QString data = QString("%1 %2").arg(ServerFunctionCode::UserOnline).arg(name);
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
if (it.key() != name)
this->sendData(it.value(), data);
}
// 用户离线
// 参数:name 用户昵称
void IMService::userOffline(QString name)
{
qDebug() << "userOffline(): name:" << name;
QString data = QString("%1 %2").arg(ServerFunctionCode::UserOffline).arg(name);
for (auto it = this->m_clientSocket->begin(); it != this->m_clientSocket->end(); it++)
if (it.key() != name)
this->sendData(it.value(), data);
}

View File

@@ -0,0 +1,129 @@
#ifndef IMSERVICE_H
#define IMSERVICE_H
#include <QObject>
#include <QtNetwork>
#include <QMap>
/***********************************
*
* Class IMService
* IM服务端类
*
* 用于与客户端交互的封装类
*
* 公开方法有:
* login 登录
* sendPrivateMessage 发送私聊消息
* sendGroupMessage 发送群聊消息
*
* 发出的信号有:
* receivedPrivateMessage 接收到私聊消息信号
* receivedGroupMessage 接收到群聊消息信号
* userOnline 用户上线信号
* userOffline 用户下线信号
* serverClose 服务器关闭信号
*
**********************************/
class IMService : public QObject
{
Q_OBJECT
// 公开成员函数
public:
explicit IMService(QObject *parent = nullptr);
~IMService();
/**
* @brief closeService 关闭服务 断开所有Socket连接
*/
void closeService();
// 信号
signals:
// 槽
public slots:
/**
* @brief newConnection 当有新连接进入时
*/
void newConnection();
/**
* @brief disconnected 当连接断开时触发
*/
void disconnected();
/**
* @brief readyRead 当接收到数据时触发
*/
void readyRead();
// 私有成员函数
private:
// 发送数据到socket对象中
/**
* @brief sendData 发送数据到socket对象中
* @param socket 指定socket对象
* @param data 要发送的数据
*/
void sendData(QTcpSocket *socket, QString data);
/**
* @brief userLogin 用户登录
* @param name 用户昵称
* @param socket socket对象
*/
void userLogin(QString name, QTcpSocket *socket);
/**
* @brief sendPrivateMessage 发送私聊消息
* @param fromName 发送者昵称
* @param toName 接收者昵称
* @param content 内容
*/
void sendPrivateMessage(QString fromName, QString toName, QString content);
/**
* @brief sendGroupMessage 发送群聊消息
* @param fromName 发送者昵称
* @param content 内容
*/
void sendGroupMessage(QString fromName, QString content);
/**
* @brief userOnline 用户上线
* @param name 用户昵称
*/
void userOnline(QString name);
/**
* @brief userOffline 用户离线
* @param name 用户昵称
*/
void userOffline(QString name);
// 私有成员变量
private:
/**
* @brief m_server 服务端的Tcp Server对象
*/
QTcpServer *m_server;
// 客户端的Tcp Socket连接列表
// QMap是一个键值对容器在这里key是用户的昵称value是用户的Socket连接对象
// 每当一个新用户上线,将会添加到该容器中
// 当用户下线时则从容器中删除
/**
* @brief m_clientSocket 客户端的Tcp Socket连接列表
*/
QMap<QString, QTcpSocket *> *m_clientSocket;
/**
* @brief m_clientNames 客户端的昵称列表
*/
QMap<QTcpSocket *, QString> *m_clientNames;
};
#endif // IMSERVICE_H

View File

@@ -0,0 +1,13 @@
#include <QCoreApplication>
#include <QTextCodec>
#include "imservice.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec);
static IMService imService;
return a.exec();
}

View File

@@ -0,0 +1,59 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
/************************************************
* IM通讯协议规定
*
* 功能码 [参数]
*
* 客户端功能码规定: 参数: 例子: 说明:
* 1 = 请求登录 用户昵称 1 张三 当客户端登录时必须先发送这条命令,告诉服务端自己的昵称
* 2 = 发送私聊消息 私聊对象 消息内容 2 李四 你妈喊你回家吃饭 当A向B发送一条私聊消息时A要向服务器发送这条指令告诉服务器消息发给谁和发什么消息
* 3 = 发送群聊消息 消息内容 3 大家好,我是张三 当A向群聊发送一条消息时直接告诉服务端需要发什么内容即可
*
* 服务端功能码规定: 参数: 例子: 说明:
* 1 = 发送私聊消息 用户昵称 消息内容 1 张三 你妈喊你回家吃饭 当A向B发送一条私聊消息时B会收到这条指令其中昵称是指A发送者的昵称
* 2 = 发送群聊消息 用户昵称 消息内容 2 张三 大家好,我是张三 当A向群聊发送一条消息时所有人都会收到这条指令其中昵称是指A发送者的昵称
* 3 = 某人上线 用户昵称 3 张三 当A上线时所有人都会收到这条指令其中昵称是A上线者的昵称
* 4 = 某人下线 用户昵称 4 张三 当A下线时所有人都会手套这条指令其中昵称是A下线者的昵称
* 10 = 登录结果 是否成功(0:成功,!0:失败) [当前在线人数] [当前在线人员列表]
* 成功时 10 0 4 张三 李四 王五 赵六 当客户端发送登录请求后,如果登录成功则返回当前在线人数与昵称列表,如果失败就返回一个!0值
* 失败时 10 1
*
***********************************************/
/**
* @brief 服务端功能码
*/
enum ServerFunctionCode {
// 私聊消息
PrivateMessage = 1,
// 群聊消息
GroupMessage = 2,
// 用户上线
UserOnline = 3,
// 用户下线
UserOffline = 4,
// 登录结果
LoginResult = 10
};
/**
* @brief 客户端功能码
*/
enum ClientFunctionCode {
// 登录
Login = 1,
// 发送私聊消息
SendPrivateMessage = 2,
// 发送群聊消息
SendGroupMessage = 3
};
#endif // PROTOCOL_H

11
IM Porject/readme.txt Normal file
View File

@@ -0,0 +1,11 @@
IM<EFBFBD>ͻ<EFBFBD><EFBFBD>ˣ<EFBFBD>
FormLogin Ϊ<><CEAA>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>
IMClient ΪIM<49>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
IMDAL ΪIM<49><4D><EFBFBD>ݿ<EFBFBD>
IMMessage ΪIM<49><4D>Ϣ<EFBFBD><EFBFBD><E1B9B9>
MainWindow Ϊ<><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
protocol ΪͨѶЭ<D1B6><D0AD>
IM<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
IMService ΪIM<49><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
protocol ΪͨѶЭ<D1B6><D0AD>