看本系统文章需要些C语言、数据结构和网络基础知识!

说明:由于游戏服务器端会有成千上万的客户端进行连接请求,所以要求我们需要做一些简单的会话管理!如下图

1.简单说明

进行统一的分配和管理,就需要我们去统一分配资源,创建和销毁(也就内存统一进行管理),采取一种内存池方式来管理。

1)先分配一块大的堆内存,其中整个空间是N个Session结构组成的,并利用链表进行串联起来,请看后面代码示例。

2)当分配一个Session时,就从内存池空闲的链表中获取到一块Session结构体大小的内存给新的Session;

3)当释放一个Session时,就把该Session再次加入到内存池空闲的链表中。

2.创建Session结构体如下:

typedef struct Session_s {
char ip[32]; // IP
int port; // Port
int sock; // socket
int is_removed; // 是否被删除 struct Session_s* next; // 指向下一个Session_t
//void* data; // 附加数据
} Session_t;

3.接口设计:

// 初始化Session内存管理池
void SessionPoolInit();
// 释放Session内存管理池资源
void SessionPoolExit(); // 将Session保存到Session内存管理池中
// @sock:client socket
// @ip: client ip
// @port: client port
Session_t* SessionToPoolAdd(int sock, char* ip, unsigned short port); // 关闭session
void SessionClose(Session_t* s); // 接口:遍历所有在线的session调用回调函数
// 如果callback 返回1,停止往下遍历;
void SessionForeachOnline(int (*call_back)(Session_t* s, void* params), void* params);
// 循环遍历在线session是否有要删除的session,主要考虑到多线程和延缓关闭套接字问题
void SessionFromPoolClear(void(*closed_socket)(int sock, void* params), void* params);

4.代码实现

.h文件

#ifndef __SESSION_H__
#define __SESSION_H__ #ifdef WIN32
#include<winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
#endif
typedef struct Session_s {
char ip[32]; // IP
int port; // Port
int sock; // socket
int is_removed; // 是否被删除 struct Session_s* next; // 指向下一个Session_t
//void* data; // 数据
} Session_t; // 初始化Session内存管理池
void SessionPoolInit();
// 释放Session内存管理池资源
void SessionPoolExit(); // 将Session保存到Session内存管理池中
// @sock:client socket
// @ip: client ip
// @port: client port
Session_t* SessionToPoolAdd(int sock, char* ip, unsigned short port); // 关闭session
void SessionClose(Session_t* s); // 接口:遍历所有在线的session调用回调函数
// 如果callback 返回1,停止往下遍历;
void SessionForeachOnline(int (*call_back)(Session_t* s, void* params), void* params);
// 循环遍历在线session是否有要删除的session,主要考虑到多线程和延缓关闭套接字问题
void SessionFromPoolClear(void(*closed_socket)(int sock, void* params), void* params);
#endif

.c文件

#include "session.h"

#define my_malloc malloc
#define my_free free #define MAX_SEESION 5000 // 最大会话量,自己可以设置
#define MAX_RECV_BUFFER 8096 // 接收数据缓冲大小 static struct {
Session_t* online; // 在线客户端链表首地址
Session_t* pBase; // 分配内存首地址
Session_t* free_list_base; // 空闲链表首 int has_removed_session; // 池中是否删除session
//int readed; // 缓冲区已经读取数据长度
//char recv_buffer[MAX_RECV_BUFFER]; // 数据缓冲区
}SessionPool; // ================================内部使用==================================
// 从池中申请Session_t
static Session_t* session_alloc() {
Session_t* session; if (SessionPool.free_list_base) {
session = SessionPool.free_list_base;
SessionPool.free_list_base = SessionPool.free_list_base->next;
}
else {
printf("警告:最大进行会话数量为:%d\n", MAX_SEESION);
session = my_malloc(sizeof(Session_t));
}
memset(session, 0, sizeof(Session_t)); return session;
} // 从池中释放Session_t
static void session_free(Session_t* s) {
if (s < SessionPool.pBase || s >= SessionPool.pBase + MAX_SEESION) {
my_free(s);
}
else {
// 将不用的session添加到空闲链表中
s->next = SessionPool.free_list_base;
SessionPool.free_list_base = s;
}
}
// ================================END======================================== void SessionPoolInit()
{
int i = 0;
memset(&SessionPool, 0, sizeof(SessionPool)); // 分配空间并初始化为0
SessionPool.pBase = my_malloc(MAX_SEESION * sizeof(Session_t));
memset(SessionPool.pBase, 0, MAX_SEESION * sizeof(Session_t)); // 串成链表
for (i = 0; i < MAX_SEESION; i++) { //
SessionPool.pBase[i].next = SessionPool.free_list_base;
SessionPool.free_list_base = &SessionPool.pBase[i];
}
} void SessionPoolExit()
{
// 服务器一般很少编写,留作接口使用
} Session_t* SessionToPoolAdd(int c_s, char* ip, unsigned short port)
{
Session_t* s = session_alloc();
size_t len = strlen(ip); if (len >= 32) {
len = 32 - 1;
}
strncpy(s->ip, ip, len);
s->ip[len] = 0;
s->port = port;
s->sock = c_s; // 添加进在线客户端链表中
s->next = SessionPool.online;
SessionPool.online = s; return s;
} void SessionClose(Session_t* s)
{
s->is_removed = 1; // session被删除
SessionPool.has_removed_session = 1; // 池中有需要删除的session
} void SessionForeachOnline(int (*call_back)(Session_t* s, void* params), void* params)
{
Session_t* walk = NULL;
if (call_back == NULL) {
return;
} walk = SessionPool.online;
while (walk) {
if (call_back(walk, params)) {
return;
}
walk = walk->next;
}
} void SessionFromPoolClear(void(*closed_socket)(int sock, void* params), void* params)
{
Session_t** walk = NULL;
if (SessionPool.has_removed_session == 0) {
return;
} walk = &SessionPool.online;
while (*walk) {
if ((*walk)->is_removed) {
Session_t* node = (*walk);
*walk = node->next;
node->next = NULL; if (closed_socket) {
closed_socket(node->sock, params);
}
printf("\r\n");
printf("client exit %s:%d\n", node->ip, node->port);
printf("\r\n");
closesocket(node->sock);
node->sock = 0;
node->is_removed = 0;
session_free(node);
}
else {
walk = &(*walk)->next;
}
}
SessionPool.has_removed_session = 0;
}

5.测试小Demo

#define _CRT_SECURE_NO_WARNINGS

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "session.h" int forkSession(Session_t* s, void* params)
{
printf("=============================================\r\n");
printf("||online client:[%d]--[%s]--[%d]||\r\n", s->sock, s->ip, s->port);
printf("=============================================\r\n");
return 0;
}
int main()
{
Session_t* s1 = NULL;
Session_t* s2 = NULL;
Session_t* s3 = NULL;
Session_t* s4 = NULL;
// 测试
// 初始化内存池
SessionPoolInit();
// 测试增加客户端
s1 = SessionToPoolAdd(1000, "127.0.0.1", 6060);
s2 = SessionToPoolAdd(2000, "127.0.0.1", 7070);
s3 = SessionToPoolAdd(3000, "127.0.0.1", 8080);
s4 = SessionToPoolAdd(4000, "127.0.0.1", 9090); // 测试循环在线客户端
printf("$$$$$$$$$$$$$$$查询在线客户端$$$$$$$$$$$$$$$\r\n");
SessionForeachOnline(forkSession, NULL);
printf("$$$$$$$$$$$$$$$$$$$$$END$$$$$$$$$$$$$$$$$$$$\r\n");
// 删除客户端
SessionClose(s3);
SessionFromPoolClear(NULL, NULL); //
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n");
// 再测试循环有哪些在线客户端
SessionForeachOnline(forkSession, NULL); printf("hello...jadeshu\n");
system("pause");
return 0;
}

测试Demo结果:

本节代码下载:点击下载

游戏客户端Session的统一管理的更多相关文章

  1. WiFi 统一管理以及设备自动化测试实践

    ATX 安卓设备 WiFi 统一管理以及设备自动化测试实践 (零散知识梳理总结) 此文为转载,感谢作者  目录  众所周知,安卓单台设备的UI自动化测试已经比较完善了,有数不清的自动化框架或者工具.但 ...

  2. 利用log4j+mongodb实现分布式系统中日志统一管理

    背景     在分布式系统当中,我们有各种各样的WebService,这些服务可能分别部署在不同的服务器上,并且有各自的日志输出.为了方便对这些日志进行统一管理和分析.我们可以将日志统一输出到指定的数 ...

  3. .NET Core微服务之基于Steeltoe使用Spring Cloud Config统一管理配置

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  4. media静态文件统一管理 操作内存的流 - StringIO | BytesIO PIL:python图片操作库 前端解析二进制流图片(了解) Admin自动化数据管理界面

    一.media ''' 1. 将用户上传的所有静态文件统一管理 -- settings.py -- MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 2. 服务 ...

  5. Active Directory、Exchange、单点登录,企业账号统一管理解决方案

    现在的公司一般都会有很多内部管理系统,比如OA.ERP.CRM.邮件系统等.员工入职之后如果每个系统都创建一个账号和密码,首先员工记系统账号就是一件非常头疼的事情,如果公司有一百个系统那就得创建一百个 ...

  6. SpringCloud-微服务配置统一管理SpringCloud Config(七)

    前言:对于应用,配制文件通常是放在项目中管理的,它可能有spring.mybatis.log等等各种各样的配置文件和属性文件,另外你还可能有开发环境.测试环境.生产环境等,这样的话就得一式三份,若是传 ...

  7. 服务器端Session和客户端Session(和Cookie区别)2

    https://blog.csdn.net/java_faep/article/details/78082802 我们可以得出如下结论: 关闭浏览器,只会是浏览器端内存里的session cookie ...

  8. 服务器端Session和客户端Session(和Cookie区别)

    Session其实分为客户端Session和服务器端Session. 当用户首次与Web服务器建立连接的时候,服务器会给用户分发一个 SessionID作为标识.SessionID是一个由24个字符组 ...

  9. 《Unity 3D游戏客户端基础框架》概述

    框架概述: 做了那么久的业务开发,也做了一年多的核心战斗开发,最近想着自己倒腾一套游戏框架,当然暂不涉及核心玩法类型和战斗框架,核心战斗的设计要根据具体的游戏类型而定制,这里只是一些通用的基础系统的框 ...

随机推荐

  1. centos6.5上安装ftp服务

    这是之前搭建过,但没记录,因为昨天使用人过来说使用有问题,突然发现没有记录,好心慌,现在的记忆真的只有1周而已,穷和老都是原罪啊!! 环境准备:centos6.5 vm 安装ftp:

  2. 基于【CentOS-7+ Ambari 2.7.0 + HDP 3.0】搭建HAWQ数据仓库01 —— 准备环境,搭建本地仓库,安装ambari

    一.集群软硬件环境准备: 操作系统:  centos 7 x86_64.1804 Ambari版本:2.7.0 HDP版本:3.0.0 HAWQ版本:2.3.05台PC作为工作站: ep-bd01 e ...

  3. 关闭win10一切

    狂客原创,转载请注明来源 关闭更新 注册表(以管理员身份运行) 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\     Start值 ...

  4. 同时使用Union和Order by问题(ORA-00933错误)解决

    之前,同事在编写视图的过程中遇到这样了这个错误.我把简化后的语句整理如下: 1: select 2: '2016' as nf, 3: qxdm, 4: round(sum(tbdlmj)/10000 ...

  5. dbeaver导出MySQL的架构提示"IO Error: Utility 'mysqldump.exe' not found in client home 'MySQL Connector/Net"解决方案

    今天想到用dbeaver的Dump dabase功能导出MySQL的架构脚本,到最后一步生成的时候提示以下错误信息: IO Error: Utility 'mysqldump.exe' not fou ...

  6. ubuntu中python3安装package

    1.实验环境 Ubuntu16.04x86 + python3.5 ubuntu中同时存在python2.7 和 python3.5 2.pip使用说明 sudo pip install packag ...

  7. layui---form表单模块

    虽然对layui比较熟悉了,但是今天有时间还是将layui的form表单模块重新看一下. https://www.layui.com/doc/modules/form.html 一.更新渲染 layu ...

  8. CEditUI 控件使用

    SetLimitText(UINT nMax )  //设置文本限制字符数 参数为nMax为控件可接受的文本最大字节数 GetTextLength() //获得文本长度 参考文档:http://www ...

  9. Java程序员必会英语单词

    Complie: 编译 line: 行 variable: 变量 parameter: 参数 defaul: 默认 access: 访问 operation:  操作运算 member-variabl ...

  10. 怎样把Word文档导入Excel表格

    Word是现在办公中的基础文件格式了,很多的内容我们都通过Word来进行编辑,那么当我们需要将Word文档里的信息导入到Excel里面的时候,我们应该怎样做呢?下面我们就一起来看一下吧. 操作步骤: ...