效果并不是很理想,unreal客户端上的效果一卡一卡的

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <unordered_map>#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>#include "GameMessage.pb.h"#define IMPORT_USER
#include "User.h"const int MaxClient = 128;
const int MaxEvents = 256;
const int MaxMessageQueue = 1024;
int ClientCount = 0;
bool isBegin = false;//客户端号与fd对应
std::unordered_map<int, int> FdToClientID;
int ClientIDToFd[MaxClient];
bool isClientLogin[MaxClient];uint8_t Buffer[MaxClient][1024];uint8_t Size[MaxClient];
uint8_t MessageType[MaxClient];
uint8_t MessageLen[MaxClient];uint32_t NowLoginCount = 0;int iFrameCount = 0;
int iQueueLen = 0;
uint8_t BufferFrameQueue[MaxMessageQueue][1024];
int BufferEffectiveSize[MaxMessageQueue];enum class MType
{LoginRequest = 1,LoginRespond = 2,GameBegin = 3,ActionRequest = 4,PlayerAction = 5,MoveRequest = 6,PlayerMove = 7
};inline void Init()
{InitUserInfo();memset(Size, 0, sizeof(Size));memset(MessageType, 0, sizeof(MessageType));memset(MessageLen, 0, sizeof(MessageLen));memset(isClientLogin, false, sizeof(isClientLogin));memset(ClientIDToFd, -1, sizeof(ClientIDToFd));iFrameCount = 0;iQueueLen = 0;printf("Init Done\n");
}inline void SendAll(int i, uint32_t SumLen)
{for (int ID = 1; ID <= ClientCount; ID += 1){if (ClientIDToFd[ID] < 0){continue;}if (isClientLogin[ID]) // DANGER{send(ClientIDToFd[ID], Buffer[i], SumLen, 0);}}
}inline void FrameQueue_SendAllMessages()
{if(iQueueLen == 0){//处理没有消息的时候}for (int i = 0; i < iQueueLen; i++){for (int ID = 1; ID <= ClientCount; ID += 1){if (ClientIDToFd[ID] < 0){continue;}if (isClientLogin[ID]) // DANGER{send(ClientIDToFd[ID], BufferFrameQueue[i], BufferEffectiveSize[i], 0);}}}iQueueLen = 0;
}inline void FrameQueue_PushMessage(int BufferID, uint32_t SumLen)
{printf("push a messgae from %d\n", BufferID);BufferEffectiveSize[iQueueLen] = SumLen;memcpy(BufferFrameQueue[iQueueLen], Buffer[BufferID], SumLen);iQueueLen++;
}/*
struct timeval tv;
long long lastFrameSendTime = 0;
void testfunc(int x)
{gettimeofday(&tv, NULL);if(tv.tv_sec * 1000 + tv.tv_usec / 1000 - lastFrameSendTime>33){ printf("ggggggg %lld\n",tv.tv_sec * 1000 + tv.tv_usec / 1000 - lastFrameSendTime);}else if(tv.tv_sec * 1000 + tv.tv_usec / 1000 - lastFrameSendTime<33){printf("---------------------------\n");}else printf("****\n");lastFrameSendTime = tv.tv_sec * 1000 + tv.tv_usec / 1000;}
//计时器
void init_sigaction(){struct sigaction act;act.sa_handler = testfunc;//FrameQueue_SendAllMessages;act.sa_flags = 0;sigemptyset(&act.sa_mask); sigaction(SIGPROF,&act,NULL); //设置信号 SIGPROF 的处理函数为 FrameQueue_SendAllMessages}void init_time() {struct itimerval value; value.it_value.tv_sec=0; //定时器启动后,每隔33ms秒将执行相应的函数value.it_value.tv_usec=33000; value.it_interval=value.it_value; setitimer(ITIMER_PROF,&value,NULL); //初始化 timer,到期发送 SIGPROF 信号
}
*/inline void ProcessEvent(int iClientID)
{switch (static_cast<MType>(MessageType[iClientID])){case MType::LoginRequest:{PLoginRequest LoginRequest;LoginRequest.ParseFromArray(Buffer[iClientID], Size[iClientID]);puts("Login Request:");printf("%s\n", LoginRequest.username().c_str());printf("%s\n", LoginRequest.password().c_str());if (UserLoginInfo.count(LoginRequest.username()) && UserLoginInfo[LoginRequest.username()] == LoginRequest.password()){puts("right");++NowLoginCount;isClientLogin[iClientID] = true;FdToClientID[ClientIDToFd[iClientID]] = iClientID;puts("filling LoginRespond");PLoginRespond LoginRespond;LoginRespond.set_allowlogin(1);LoginRespond.set_selfid(iClientID);uint8_t SingleMessageType = static_cast<uint8_t>(MType::LoginRespond);uint8_t SingleMessageLen = static_cast<uint8_t>(LoginRespond.ByteSizeLong());memcpy(Buffer[iClientID] + 0, &SingleMessageType, 1);memcpy(Buffer[iClientID] + 1, &SingleMessageLen, 1);LoginRespond.SerializeToArray(Buffer[iClientID] + 2, SingleMessageLen);uint32_t sendLen = send(ClientIDToFd[iClientID], Buffer[iClientID], SingleMessageLen + 2, 0); // DANGERprintf("New Client (%d)\n", iClientID);if (NowLoginCount == 2) // HARD CODE,如果登录2人,则open{PGameBegin GameBegin;    //再发一个GameBegin.set_selfid(1); // HARD CODESingleMessageType = static_cast<uint8_t>(MType::GameBegin);SingleMessageLen = static_cast<uint8_t>(GameBegin.ByteSizeLong());memcpy(Buffer[iClientID] + 0, &SingleMessageType, 1);memcpy(Buffer[iClientID] + 1, &SingleMessageLen, 1);GameBegin.SerializeToArray(Buffer[iClientID] + 2, SingleMessageLen);SendAll(iClientID, SingleMessageLen + 2);isBegin = true;}}else //登陆失败{PLoginRespond LoginRespond;LoginRespond.set_allowlogin(0);LoginRespond.set_selfid(1); // HARD CODEuint8_t SingleMessageType = static_cast<uint8_t>(MType::LoginRespond);uint8_t SingleMessageLen = static_cast<uint8_t>(LoginRespond.ByteSizeLong());memcpy(Buffer[iClientID] + 0, &SingleMessageType, 1);memcpy(Buffer[iClientID] + 1, &SingleMessageLen, 1);LoginRespond.SerializeToArray(Buffer[iClientID] + 2, SingleMessageLen);uint32_t sendLen = send(ClientIDToFd[iClientID], Buffer[iClientID], SingleMessageLen + 2, 0); // DANGER}}break;case MType::ActionRequest:{PActionRequest ActionRequest;ActionRequest.ParseFromArray(Buffer[iClientID], Size[iClientID]);uint32_t ActionPlayerID = iClientID; // DANGER,客户端IDPPlayerAction PlayerAction;PlayerAction.set_framecount(iFrameCount);PlayerAction.set_playerid(ActionPlayerID);PlayerAction.set_actiontype(ActionRequest.actiontype());uint8_t SingleMessageType = static_cast<uint8_t>(MType::PlayerAction);uint8_t SingleMessageLen = static_cast<uint8_t>(PlayerAction.ByteSizeLong());memcpy(Buffer[iClientID] + 0, &SingleMessageType, 1);memcpy(Buffer[iClientID] + 1, &SingleMessageLen, 1);PlayerAction.SerializeToArray(Buffer[iClientID] + 2, SingleMessageLen);printf("get a %d messgae from %d\n", SingleMessageType, iClientID);FrameQueue_PushMessage(iClientID, SingleMessageLen + 2);// SendAll(iClientID, SingleMessageLen + 2);// uint32_t sendLen = send(fd[i], Buffer[i], SingleMessageLen + 8, 0); // DANGER}break;case MType::MoveRequest:{PMoveRequest MoveRequest;MoveRequest.ParseFromArray(Buffer[iClientID], Size[iClientID]);uint32_t MovePlayerID = iClientID;PPlayerMove PlayerMove;PlayerMove.set_framecount(iFrameCount);PlayerMove.set_playerid(MovePlayerID);PlayerMove.set_movetype(MoveRequest.movetype());PlayerMove.set_movevalue(MoveRequest.movevalue());uint8_t SingleMessageType = static_cast<uint8_t>(MType::PlayerMove);uint8_t SingleMessageLen = static_cast<uint8_t>(PlayerMove.ByteSizeLong());memcpy(Buffer[iClientID] + 0, &SingleMessageType, 1);memcpy(Buffer[iClientID] + 1, &SingleMessageLen, 1);PlayerMove.SerializeToArray(Buffer[iClientID] + 2, SingleMessageLen);printf("get a %d messgae from %d\n", SingleMessageType, iClientID);FrameQueue_PushMessage(iClientID, SingleMessageLen + 2);// SendAll(iClientID, SingleMessageLen + 2);//  uint32_t sendLen = send(fd[i], Buffer[i], SingleMessageLen + 8, 0); // DANGER}break;default:{printf("error message type\n");}break;}
}int main()
{Init();struct epoll_event event;struct epoll_event wait_event[MaxEvents];//创建socketint sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr));my_addr.sin_family = AF_INET;my_addr.sin_port = htons(3004);// 0.0.0.0 是指本地的地址(也就是代表了所有本地的地址,同一个网卡上也可能有多个地址).这点上linux,windows系统都是相同的.my_addr.sin_addr.s_addr = htonl(INADDR_ANY);bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));listen(sockfd, 10);printf("Server Start\n");//服务器的sockfd放在第一个ClientIDToFd[0] = sockfd;int epfd = epoll_create(MaxEvents);if (-1 == epfd){printf("error in creating epfd\n");return -1;}event.data.fd = sockfd;event.events = EPOLLIN;int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);if (-1 == ret){printf("error in epoll adding server\n");return -1;}//时间戳struct timeval tv;gettimeofday(&tv, NULL);long long lastFrameSendTime = tv.tv_sec * 1000 + tv.tv_usec / 1000;while (true){ret = epoll_wait(epfd, wait_event, MaxEvents, -1);gettimeofday(&tv, NULL);if (isBegin){if (tv.tv_sec * 1000 + tv.tv_usec / 1000 - lastFrameSendTime >= 33){lastFrameSendTime = tv.tv_sec * 1000 + tv.tv_usec / 1000;iFrameCount++;//发出缓冲区的消息FrameQueue_SendAllMessages();}}switch (ret){case -1:printf("epoll_wait Erro\n");exit(2);default:{for (int i = 0; i < ret; i++){//有新的客户端连接if ((sockfd == wait_event[i].data.fd) && (wait_event[i].events & EPOLLIN)){struct sockaddr_in cli_addr;unsigned int clilen = sizeof(cli_addr);int connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);//连接数量达到最大溢出则不注册if (ClientCount + 1 >= MaxClient){printf("Client is maximum\n");continue;}//最大ID给新来的客户端++ClientCount;if (ClientIDToFd[ClientCount] < 0){//注册客户端号与fd!!!ClientIDToFd[ClientCount] = connfd;FdToClientID[connfd] = ClientCount;event.data.fd = connfd;event.events = EPOLLIN;ret = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);if (-1 == ret){printf("error in adding client\n");return -1;}else{printf("new client connection,PlayerID is: %d\n", ClientCount);}}else{printf("PlayerIDToFd not init or error\n");}}else if (wait_event[i].events & EPOLLIN){int iPlayerID = FdToClientID[wait_event[i].data.fd];int len = 0;if (!MessageType[iPlayerID] || !MessageLen[iPlayerID]){len = recv(wait_event[i].data.fd, Buffer[iPlayerID] + Size[iPlayerID], 2 - Size[iPlayerID] /*处理沾包*/, 0);Size[iPlayerID] += len;if (Size[iPlayerID] >= 2){memcpy(&MessageType[iPlayerID], Buffer[iPlayerID] + 0, 1);memcpy(&MessageLen[iPlayerID], Buffer[iPlayerID] + 1, 1);Size[iPlayerID] = 0;}}else{len = recv(wait_event[i].data.fd, Buffer[iPlayerID] + Size[iPlayerID], MessageLen[iPlayerID] - Size[iPlayerID] /*处理沾包*/, 0);Size[iPlayerID] += len;if (Size[iPlayerID] >= MessageLen[iPlayerID]){ProcessEvent(iPlayerID);MessageType[iPlayerID] = 0;MessageLen[iPlayerID] = 0;Size[iPlayerID] = 0;}}}}}}}return 0;
}

基于epoll,socket与protobuf的简单帧同步游戏服务器相关推荐

  1. 帧同步游戏 服务器相关实现

    每隔 LGOIC_FRAME_TIME 调用 on_logic_frame on_logic_frame里边主要是同步消息,做了以下几件事情 1:把过去的这一帧时间内收集的数据 插入到 match_f ...

  2. java android长连接_基于Java Socket的自定义协议,实现Android与服务器的长连接(一)...

    一.基础知识准备 在正式给大家介绍自定义协议之前,我们先对网络传输和协议解析的相关知识点做一个基本的介绍,尽管这些知识点我们在学校里学过,但难免会有所遗忘,这里先做一个简单的介绍,以便对后文的内容理解 ...

  3. 简单的golang游戏服务器框架《railgun》的文档目录索引

    使用golang写的框架.使用的是require response的状态同步 使用了第三方protobuf库作为报文和序列化,关于如何在windows下安装参考:windows下安装golang pr ...

  4. 帧同步游戏开发基础指南

            最近一个月休了个假,体验了一下类似欧洲的田园生活.所以更新几乎荒废了,但是总结和积累是一直持续着的.根据前一阶段对于实时对战游戏的开发思考,写了这一篇入门级的文章,希望能记录下自己的想 ...

  5. Unity 帧同步游戏实现高光时刻

    一.前言: 高光时刻这个功能,对于常玩游戏的应该都不陌生,比如王者荣耀的高光分享功能.以前很多人为了分享自己的游戏高光,还需要全程录制,然后自己截取,非常的麻烦,现在王者荣耀已经可以云端生成视频了,大 ...

  6. 多人网络游戏服务器开发基础学习笔记 II: 帧同步 | 游戏客户端预测原理分析 | FPS 游戏状态同步

    这篇是对书本 网络多人游戏架构与编程 的学习第二篇(第一篇:多人网络游戏服务器开发基础学习笔记 I:基本知识 | 游戏设计模式 | 网游服务器层次结构 | 游戏对象序列化 | 游戏 RPC 框架 | ...

  7. 类似王者荣耀帧同步游戏的相关技术

    游戏开发 王者荣耀属于典型的Moba类游戏,和英雄联盟属于同一种游戏类型,那么王者荣耀这种游戏是如何制作的?又需要学习哪些技术点呢?今天我们一起来分析一下. 这里有个教学视频可以学习一下, 或者加入U ...

  8. 服务器的使用:基于centos7 搭建我的世界(Minecraft)游戏服务器

    前言:对于现公开的游戏服务器不太和谐的情况下,三两好友可以自己搭建一个属于自己的游戏服务器. 我们系统选择的是centos7(Linux) Minecraft服务是java运行的,1.17之前的版本都 ...

  9. 如何实现一个简单的网络帧同步方案

    在网络游戏中,网络同步方案大概有下面三种: 状态同步,即state synchronization 快照同步,即 snapshot synchronization 帧同步,即lock step syn ...

  10. 帧同步优化难点及解决方案

    帧同步这部分比较复杂,细枝末节有很多优化点,也有一些不同的优化方向,根据不同项目类型.对操作手感的要求.联机玩家的个数等,会有不同的难点和痛点.不同的优化方向,优化手法的差异,可能导致一些争论.并且, ...

最新文章

  1. 【学习笔记】git 使用文档
  2. 双十一,程序员前女友发来消息。。。
  3. 业界丨OpenAI 发布通用人工智能研究纲领:以全人类的名义承诺
  4. 解决启动httpd报: apr_sockaddr_info_get() failed for错误
  5. JSON Web Tokens(JWT)
  6. 9.03-Springboot要点记录
  7. hao123电脑版主页_hao123浏览器 原生网民的记忆 一代站长的传奇
  8. 最大公约数PHP算法,php计算两个整数的最大公约数常用算法小结
  9. MQTT从入门到放弃
  10. CF 86D 莫队(卡常数)
  11. 安卓3d游戏引擎_万达院线游戏、莉莉丝推新作;《天龙八部手游》不限号不删档测试开启...
  12. OpwnWrt 路由器MWAN3多线多拨实现方法
  13. dede源码详细分析之--全局变量覆盖漏洞的防御
  14. m3u8格式转MP4(ffmpeg方法)
  15. 想知道如何在Mac上剪切文件吗?一定要看这篇文章!
  16. 微信注册验证成功之后不跳转_微信为什么会被限制登录?被限制后我们该怎么办?...
  17. Ubuntu桌面卡成狗,如何有效解决卡顿问题
  18. 前序+中序 =〉后序
  19. 如何区分Workflow、BPM与PRA?三者之间有什么关系?
  20. ES--IK分词器安装

热门文章

  1. vmware共享文件夹不显示
  2. 【亚伦博客】《蝙蝠侠前传2:黑暗骑士》里发生了什么
  3. C/C++ - http协议发送字段,文件,单个和多张图片
  4. win10文件夹当作服务器,win10文件夹加密不了怎么办_网站服务器运行维护,win10
  5. EXCEL如何快速拆分合并单元格数据
  6. pytorch 机器翻译 seq2seq 模型和注意力机制
  7. Linux VGA驱动移植实验
  8. vue怎么使用eval_eval()的使用和兼容性问题
  9. 承认你的父母其实不那么爱你
  10. ASU计算机科学专业大学排名,2013年U.S.News美国大学排名--计算机科学专业研究生排名...