提交源码

This commit is contained in:
筱傑 2018-12-09 21:25:07 +08:00 committed by GitHub
parent a280783e7f
commit f029404192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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客户端
FormLogin 为登录窗口
IMClient 为IM客户端主功能类
IMDAL 为IM数据库
IMMessage 为IM消息结构体
MainWindow 为主窗体
protocol 为通讯协议
IM服务端
IMService 为IM服务端主功能类
protocol 为通讯协议