您的位置:首页 > 财经 > 产业 > 策划一个网站策划书_龙岩网站建设的软件_app用户量排名_品牌推广案例

策划一个网站策划书_龙岩网站建设的软件_app用户量排名_品牌推广案例

2025/4/14 14:27:33 来源:https://blog.csdn.net/qq_27302885/article/details/147163161  浏览:    关键词:策划一个网站策划书_龙岩网站建设的软件_app用户量排名_品牌推广案例
策划一个网站策划书_龙岩网站建设的软件_app用户量排名_品牌推广案例

目录

1.知识点概述

2.解决windows下动态库找不到的问题

3.编解码类图分析

4.通过protobuf生成需要的x++类

5.编解码基类codec实现

6.编解码类代码分析

7.工厂模式介绍

8.简单工厂模式实现-伪代码

9.工厂模式使用-伪代码

10.编解码类图

11.服务器通信效率分析

12.线程池设计思路

13.线程池相关

14.客户端效率优化

15.套接字连接池实现-伪代码

16.连接池c api

17.套接字通信C语言api分析

18.套接字通信客户端类封装

19.服务器端C++类设计-有问题

20.服务器端类改进

21.封装之后的套接字类服务器和客户端通信流程

22.套接字类图


1.知识点概述

## 2. 简单工厂模式 - 只需要一个工厂类

> 工厂: 使用一个单独的类来做创建实例的过程, 这就是工厂。

> 简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。
> 特点:
>
> - 缺点:每添一个对象,就需要对简单工厂进行修改(尽管不是删代码,仅仅是添一个switch case,但仍然违背了“不改代码”的原则)
> - 优点:去除了与具体产品的依赖, 实现简单。
>

```shell
# 简单工厂模式的使用:
1. 创建一个工厂类
2. 在这个类中提供一个公共的成员方法
    - 创建对象, 一般情况下创建某些实现多态的子类对象
    - 返回这个对象的地址
```

2.解决windows下动态库找不到的问题

```c++
// 通过创建工厂类, 添加工厂函数, 创建对象
// 两个编解码的子类
class RequestCodec : public Codec    // 编解码请求数据
class RespondCodec : public Codec    // 编解码响应数据


/*
    知识点:
        做条件判断的时候, if..else if .. else 效率比 switch 低
        如果判断的情况比较少使用 if .. else
        如果情况比较多, 建议使用 switch
*/

3.编解码类图分析

// 创建工厂类, 创建编解码对象
class Factory
{
public:
    Factory();
    ~Factory();
    // 工厂函数, 创建对象
    // flag==1 -> RequestCodec
    // falg==2 -> RespondCodec
    Codec* createObject(int flag)
    {
        Codec* c = NULL;
        // 判断
        if(flag == 1)
        {
            c = new RequestCodec();
        }
        else if(flag == 2)
        {
            c = new RespondCodec();
        }
        return c;
    }
}
```

4.通过protobuf生成需要的x++类

工厂类的使用:

```c++
// 1. 创建工厂类对象
Factory* fac = new Factory;
// 2. 通过工厂函数创建编解码对象
Codec* c = fac->createObject(1);
// 3. 编码
string str = c->encoceMsg();
```

## 3. 工厂模式 - 需要有N个工厂类

> 工厂方法:每种产品由一种工厂来创建,一个工厂保存一个new
>
> 特点:基本完美,完全遵循  “不改代码”的原则

```shell
# 工厂模式流程
1. 创建一个工厂类的基类
2. 在这个基类中定义一个虚函数 -> 创建对象的方法
3. 创建子工厂类(编解码的基类有多少子类, 就创建多少个子工厂类)
    - 每个编解码的子类, 都对应一个工厂类
4. 在子工厂类中重写工厂类基类中的虚函数
```

5.编解码基类codec实现

工厂类的使用:

```c++
// 两个编解码的子类
class RequestCodec : public Codec
class RespondCodec : public Codec
class TestCodec : public Codec    // 编解码响应数据
```

使用

```c++
// 创建工厂类的基类
class BaseFactory
{
public:
    BaseFactory();
    ~BaseFactory;
    virtual Codec* createObject()
    {
        return NULL;
    }
}

6.编解码类代码分析

// 工厂类子类
class RequestFactory : public BaseFactory
{
public:
    RequestFactory();
    ~RequestFactory;
    Codec* createObject()
    {
        return new RequestCodec;
    }
}

class RespondFactory : public BaseFactory
{
public:
    RespondFactory();
    ~RespondFactory;
    Codec* createObject()
    {
        return new RespondCodec;
    }
}

7.工厂模式介绍

class TestFactory : public BaseFactory
{
public:
    TestFactory();
    ~TestFactory;
    Codec* createObject()
    {
        return new TestCodec;
    }
}
```

工厂模式使用

```c
// 1. 创建工厂类对象
BaseFactory* fac = new RespondFactory;
// 2. 得到了编解码对象
Codec* c = fac->createObject();
// 3. 编码
string str = c->encodeMsg();
```

8.简单工厂模式实现-伪代码

# 2. 套接字通信

## 2.1 通信效率问题

- 服务器端

  - 单线程/单进程

    - 无法使用, 不支持多客户端

  - 多线程/多进程

    - 写程序优先考虑多线程
    - 什么时候考虑多进程:
      - 启动了一个可执行程序A, 要在A中启动可执行程序B
    - 支持多客户端连接

  - IO多路转接

    - 单线程/进程

      - 支持多客户端连接
      - 效率并不是最高的
        - 所有的客户端请求都是顺序处理的 -> 排队

    - 多线程

      ```c
      void acceptConn(void* arg)
      {
          int fd = accept();    
          // fd添加到epoll树上
          epoll_ctl();
      }
      
      void connClient(void* arg)
      {
          read();
          write();
          // 如果连接断开
          epoll_crl(epfd, epoll_ctl_del, fd, NULL);
      }

9.工厂模式使用-伪代码

  // 服务器
      int main()
      {
          // 1. 监听fd
          int lfd = socket();
          // 2. 绑定
          bind();
          // 3. 监听
          listen();
          // 4. 初始化epoll
          int epfd = epoll_create(x);
          // 5. epoll添加检测节点 -> lfd
          epoll_ctl(epfd, epoll_ctl_add, lfd, ev);
          
          struct epoll_event evs[1024];
          while(1)
          {
              int num = epoll_wait(epfd, evs, 1024, NULL);
              for(int i=0; i<num; ++i)
              {
                  int curfd = evs[i].data.fd;
                  if(curfd == lfd)
                  {
                      pthread_create(&tid, NULL, acceptConn, &epfd);
                  }
                  else
                  {
                      // 这么传递curfd是错误的 -> 不能直接传地址
                      // 根据分析需要传递: curfd和epfd
                      pthread_create(&tid, NULL, connClient, &curfd);
                  }
              }
          }
      }
      ```

10.编解码类图

- 线程池

    - 多个线程的一个集合, 可以回收用完的线程

      - 线程池中线程的个数? -> 看业务逻辑
      - 密集型业务逻辑: 需要大量cup时间进行数据处理
          - 线程个数 == 当前电脑的cup核心数
        - 进行IO操作
          - 线程个数 = 2倍cup核心数

    - 不需要频繁的创建销毁线程

    - 设计思路
    
      ```c
    1. 需要两个角色
          - 管理者 -> 1个线程
          - 工作的线程 -> N个
      2. 管理者
          - 不工作(不处理业务逻辑, 监测工作的线程的状态, 管理线程的个数)
          - 假设工作线程不够用了, 动态创建新的工作线程
          - 建设工作的线程太多了, 销毁一部分工作的线程
          - 动态监测工作的线程的状态
      3. 工作的线程
          - 处理业务逻辑
      4. 需要一个任务队列
          - 存储任务 -> 唤醒阻塞线程 -> 条件变量 pthread_cond_broadcast/siganl
          - 工作的线程处理任务队列中的任务
          - 没有任务 -> 阻塞 pthread_cond_wait
      ```
    
      

11.服务器通信效率分析

客户端

  - 一般情况客户端只有一个连接和服务器通信

    - 没什么可以优化的

  - 客户端同时有多个连接和服务器通信
  
    - 第一个链接: 数据交换

    - 第2-6个连接: 下载

    - 提交效率的点:
  
      - 建立连接的时候:    `connect`

    - 处理思路: -> 套接字连接池
  
      - 在进行业务通信之前, 先把需要的连接创建出来, 存储到一个容器中
      - 当前要通信的时候, 从容器中取出一个连接 (fd) -> 和服务器通信
      - 通信完成之后 -> 将这个连接放回到容器中
  
    - 套接字连接池实现思路
  
      ```c++
      class ConnectPool
      {
      public:
          ConnectPool(int number)
          {
              for(int i=0; i<number; ++i)
              {
                  int fd = socket();    // 创建通信的fd
                  conect();            // 连接服务器
                  m_list.push(fd);
              }
          }
          
          // 取出一个连接
          int getConnect()
          {
              if(m_list.size() > 0)
              {
                  int fd = m_list.head();
                  m_list.pop();
                  return fd;
              }
              return -1;
          }
          
          // 放回一个连接
          void putConnect(int fd, bool isvaild)
          {
            m_list.push(fd);
          }
          
          ~ConnectPool();
          
      private:
          queue<int> m_list;
      }
      ```

12.线程池设计思路

## 2.2 C++类封装

- c语言API

  ```c
  // 客户端
  // C API
  int sckClient_init();
  /* 客户端 连接服务器 */
  int sckClient_connect(char *ip, int port, int connecttime, int *connfd);
  /* 客户端 关闭和服务端的连接 */
  int sckClient_closeconn(int connfd);
  /* 客户端 发送报文 */
  int sckClient_send(int connfd, int sendtime, unsigned char *data, int datalen);
  /* 客户端 接受报文 */
  int sckClient_rev(int connfd, int revtime, unsigned char **out, int *outlen); //1
  /* 释放内存 */
  int sck_FreeMem(void **buf);
  /* 客户端 释放 */
  int sckClient_destroy();
  
  // 服务器端
  /* 服务器端初始化 */
  int sckServer_init(int port, int *listenfd);
  int sckServer_accept(int listenfd, int timeout, int *connfd);
  /* 服务器端发送报文 */
  int sckServer_send(int connfd, int timeout, unsigned char *data, int datalen);
  /* 服务器端端接受报文 */
  int sckServer_rev(int  connfd, int timeout, unsigned char **out, int *outlen); //1
  int sckServer_close(int connfd);
  /* 服务器端环境释放 */
  int sckServer_destroy();

13.线程池相关

C++ 套接字类

  - 客户端

    ```c++
    // 创建TcpSocket对象 == 一个连接, 这个对象就可以和服务器通信了, 多个连接需要创建多个这样的对象
    class TcpSocket
    {
    public:
        TcpSocket()
        {
            m_connfd = socket(af_inet, sock_stream, 0);
        }
            
        TcpSocket(int fd)
        {
            m_connfd = fd;    // 传递进行的fd是可以直接通信的文件描述符, 不需要连接操作
        }
        ~TcpSocket();
        /* 客户端 连接服务器 */
        int conectToHost(string ip, unsigned short port, int connecttime)
        {
            connect(m_connfd, &serverAddress, &len);
        }
        /* 客户端 关闭和服务端的连接 */
        int disConnect();
        /* 客户端 发送报文 */
        int sendMsg(string sendMsg, int sendtime = 10000)
        {
            send(m_connfd, data, datadlen, 0);
        }
        /* 客户端 接受报文 */
        string recvMsg(int timeout)
        {
            recv(m_connfd, buf, size, 0);
            return string(buf);
        }
    
    private:
        int m_connfd;
    }
  

14.客户端效率优化

- 服务器端
  
    ```c++
    // 这个类不能用, 因为只能和一个客户端建立连接
    class TcpServer
    {
    public:
        // 初始化监听的套接字: 创建, 绑定, 监听
        TcpServer();
        ~TcpServer();    // 在这里边关闭监听的fd
    
        int acceptConn(int timeout);
        /* 服务器 发送报文 */
        int sendMsg(string sendMsg, int sendtime = 10000);
        /* 服务器 接受报文 */
        string recvMsg(int timeout); 
        int disConnect();    // 和客户端断开连接
    private:
        int m_lfd;        // 监听的文件描述符
        int m_connfd;    // 通信的文件描述符
    }
    ```

15.套接字连接池实现-伪代码

 ```c++
    // 第二版
    // 这个类不能用, 因为只能和一个客户端建立连接
    class TcpServer
    {
    public:
        // 初始化监听的套接字: 创建, 绑定, 监听
        TcpServer();
        ~TcpServer();    // 在这里边关闭监听的fd
    
        int acceptConn(int timeout);
        /* 服务器 发送报文 */
        int sendMsg(string sendMsg, int sendtime = 10000);
        /* 服务器 接受报文 */
        string recvMsg(int timeout); 
        int disConnect();    // 和客户端断开连接
    private:
        int m_lfd;        // 监听的文件描述符
        vector<int> m_connfd;    // 不好用, 因为在接收和发送数据的时候, 不知道用安一个fd
    }
    ```

16.连接池c api

```c++
    // 第三个版本
  // 思想: 服务端不负责通信, 只负责监听, 如果通信使用客户端类
    class TcpServer
    {
    public:
        // 初始化监听的套接字: 创建, 绑定, 监听
        TcpServer();
        ~TcpServer();    // 在这里边关闭监听的fd
        
        TcpSocket* acceptConn(int timeout = 90000)
        {
             int fd = accept(m_lfd, &address, &len);
            // 通信fd -> 类
            TcpSocket* tcp = new TcpSocket(fd);
            if(tcp != NULL)
            {
                return tcp;
            }
            return NULL;
        }

17.套接字通信C语言api分析

  private:
        int m_lfd;    // 监听的fd
    }
    ```
  
    ```c++
    // TcpServer 使用
    void* callback(void* arg)
    {
        TcpSocket* tcp = (TcpSocket* )arg;
        // 通信
        tcp->sendMsg();
        tcp->recvMsg();
        tcp->disConnect();
        delete tcp;
  }
    // 套接字通信的服务器端程序
    int main()
    {
        TcpServer* server = new TcpServer;
        while(1)
        {
            TcpSocket* tcp = server->acceptConn();
            // 创建子线程 -> 通信
            pthread_crate(&tid, NULL, callback, tcp);
        }
        
        delete server;
      return 0;
    }

18.套接字通信客户端类封装

 ```c++
    // tcp客户端程序
    int main()
    {
        // 创建通信的套接字对象
        TcpSocket* tcp = new TcpSocket;
        // 连接服务器
        tcp->conectToHost(ip, port, timeout);
        // 通信
        tcp->sendMsg();
        tcp->recvMsg();
        tcp->disConnect();
        delete tcp;
    }
    ```
  

19.服务器端C++类设计-有问题

20.服务器端类改进

21.封装之后的套接字类服务器和客户端通信流程

22.套接字类图

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com