3-IM聊天系统-Mediator
文章目录
准备工作
创建筛选器
梳理:
- 父类
- 网络类
- 实现功能
- 打开网络-初始化网络(initNet)
- 关闭网络-关闭(close)
INetMediator.h
#pragma once
class INetMediator {
public:
INetMediator(){}
virtual ~INetMediator(){}
//打开网络
//和初始化一样,是调用initNet函数
virtual bool openNet() = 0;
//关闭网络
//调用unInitNet函数
virtual void closeNet() = 0;
//发送数据
//data:发送数据的内容,len:发送的数据长度,to:发送的地址,发给谁,UDP是ip,TCP是socket
virtual bool sendData(char* data, int len, unsigned long to) = 0;
//转发数据(把Net层接收到的数据传给核心处理类)
//1.什么数据
//2.数据从哪儿来 UDP-ip TCP-socket
virtual void transmitData(char* data, int len, unsigned long from) = 0;
};
框架实现类似INet类。测试代码详见3-01笔记。
实现
主函数
通过中介者初始化网络。
UdpMediator
- openNet()函数:
通过对象调用Udp中initNet函数。
- 创建Udp对象-在INetMediator.h头文件中添加父类指针成员
(在Tcp中也需要使用该对象)
加入头文件
使用相对路径-"./"返回上一级寻找。(默认从当前文件夹开始寻找)
指针初始化
- 子类的构造函数中创建对象
//打开网络
bool UdpMediator::openNet() {
//构造函数创建对象,实现调用
m_pNet = new Udp(this);
return true;
}
创建Udp的对象,调用Udp的函数。
添加Udp的文件
- 通过指针调用函数
//关闭网络
void UdpMediator::closeNet() {
//回收资源
m_pNet->unInitNet();
}
相比原本直接调用,使用中介者类,多一层调用更安全。
- 析构函数回收指针
//关闭网络
void UdpMediator::closeNet() {
//回收资源
if (m_pNet) {
m_pNet->unInitNet();
delete m_pNet;
m_pNet = nullptr;
}
}
- 传输数据
//转发数据(把net层的数据传给核心处理类)//net层的数据由Udp使用transmit函数传给Mediator
- <font style="color:black;">Udp 使用指针调用Mediator的transmit函数把接收的的数据传给Mediator。</font>
- <font style="color:black;">同理,不止UDP,Tcp也需要使用父类指针创建对象</font>
在INet类中添加指针
加入头文件
创建指针
初始化
- <font style="color:black;"> INet() :m_isRunning(true) , m_pMediator(nullptr) {}</font>
- 问题:
INetMediator.h包含INet.h文件
INet.h文件包含INetMediator.h文件
头文件相互包含。编译在预处理的阶段会导致重复拷贝。
解决:
申明先有INet类,可以直接使用,先不编译INet类。
但是INet类需要在整个编译过程中被使用。
- 问题:
- 栈溢出
Udp::Udp(INetMediator* p) :m_sock(INVALID_SOCKET),m_handle(nullptr),m_isRunning(true) {
m_pMediator = p;
}
bool UdpMediator::openNet() {
//构造函数创建对象,实现调用
m_pNet = new Udp(this);
return m_pNet->initNet();
}
原因:
主函数中创建了udpMediator对象,udpMediator对象走析构函数到udpMediator,创建udp对象。udp走析构函数,创建udpMediator对象。走udpMediator析构函数创建udp对象。相互调用死循环,stack溢出。
解决:
将主函数创建的对象传入udpMediator构造中创建的udp对象。
加入有参构造。把对象传入。
在udpMediator析构,创建Udp对象的时候传入参数(this-当前的udpMediater)。
代码
主函数测试
#include<Windows.h>
#include<iostream>
#include"Mediator/TcpClientMediator.h"
#include"Mediator/TcpServerMediator.h"
#include"Mediator/UdpMediator.h"
using namespace std;
int main() {
INetMediator* p1 = new UdpMediator;
//初始化UDP网络
if (!p1->openNet()) {
cout << "打开UDP网络失败" << endl;
delete p1;
return 1;
}
//使用直接广播发送测试消息
char s[] = "this is a test";
//p1->sendData(s, sizeof(s), inet_addr("192.168.134.1"));
//打开服务端网络
INetMediator* p3 = new TcpServerMediator;
if (!p3->openNet()) {
cout << "打开tcp服务端网络失败" << endl;
delete p3;
return 1;
}
//打开客户端网络
INetMediator* p2 = new TcpClientMediator;
if (!p2->openNet()) {
cout << "打开tcp网络失败" << endl;
delete p2;
return 1;
}
//客户端给服务端发一个消息
for (int i = 0; i < 20; i++) {
p2->sendData(s, sizeof(s), 0);
}
while (true) {
Sleep(50000);
cout << "imserver is running" << endl;
}
delete p1;
delete p2;
delete p3;
//INetMediator* p11 = new TcpClientMediator;
//INetMediator* p12 = new TcpServerMediator;
//INetMediator* p13 = new UdpMediator;
//delete p11;
//delete p12;
//delete p13;
return 0;
}
//IM--聊天系统
//功能
/*1.注册
* 2.登陆账号
* 3.添加好友
* 4.聊天窗口界面
* 5.主界面
* 6.下线 -由服务端维护socket通信状态
* 7.上线
*/
/*面向对象编程,分析系统框架
*
* 客户端QT
* 核心处理类(处理收到的数据,组织要发送的数据)-注册信息,聊天信息,在线状态
* UI界面
* 网络类(收发数据,初始化网络,关闭网络)
*服务端
* 数据库(好友关系,账号数据,信息)
* 核心处理类(处理收到的数据,组织要发送的数据)
* 中介者类
//不做数据处理,只做转发
//代码量不大的时候不使用中介者类也可以,添加是为了方便以后的功能扩展
* 网络类(收发数据,初始化网络,关闭网络) UDP-TCP协议
*/
//网络类
//封装继承多态
//父类:定义接口--纯虚函数
//子类:实现函数:UDP子类,TCPClient子类,TCPServer子类
//中介者:架构和网络类一样
//父类:
//子类:
//数据结构STL:
//vector:数组,数据连续存储,知道下标查找快,不知道下标查找慢,下标是连续的。增加和删除数据不方便
//一串连续的数字
//list:数据不连续存储,查找效率低,插入删除方便,
//经常插入删除
//stack:数据先进后出
//queue:数据先进先出
//对数据顺序有要求
//map:key-value,自动排序,查找快
//一一对