client: c#+protobuf, server: golang+protobuf
前段时间看到一篇博文《可在广域网部署运行的即时通讯系统 -- GGTalk总览(附源码下载)》,他是用C#实现的即时通讯系统,功能强大,界面漂亮。 就想用golang重写服务端,把代码下载回来,发现通信框架用的是ESFramework,我没用过也不知道ESFramework的协议,重写是不行的了,只能把原作者的客户端界面扣出来,自己写一个,客户端是C#+protobuf, 服务端是golang+protobuf,动起手来才发现,功能细节实在太多了,没精力搞下去了,就权当protobuf的学习例子吧。
一、协议
4个字节的长度 + 4个字节的包长 + protobuf数据包
// 登录的请求和响应
LoginRequestCMD uint32 = 1
LoginResponseCMD uint32 = 2
// 注册用户的请求和响应
RegisterRequestCMD uint32 = 3
RegisterResponseCMD uint32 = 4
// 获取朋友列表的请求和响应
GetFriendsRequestCMD uint32 = 5
GetFriendsResponseCMD uint32 = 6
// 用户下线请求 和 通知
UserOfflineRequestCMD uint32 = 7
UserOfflineNoticeCMD uint32 = 8
// 用户改变状态请求 和 通知
ChangeStatusRequestCMD uint32 = 9
ChangeStatusNoticeCMD uint32 = 10
// 修改用户资料请求 和 响应
UpdateUserInfoRequestCMD uint32 = 11
UpdateUserInfoResponseCMD uint32 = 12
// 好友聊天请求 和 通知
FriendChatRequestCMD uint32 = 13
FriendChatNoticeCMD uint32 = 14
// 获取用户列表请求 和 响应
GetUserListRequestCMD uint32 = 15
GetUserListResponseCMD uint32 = 16
// 增加好友请求 和 响应
AddFriendsRequestCMD uint32 = 17
AddFriendsResponseCMD uint32 = 18
// 心跳请求 和 响应
HeartbeatRequestCMD uint32 = 19
HeartbeatResponseCMD uint32 = 20
// 上传文件请求 和 响应
UploadFileRequestCMD uint32 = 21
UploadFileResponseCMD uint32 = 22
// 获取文件列表请求 和 响应
GetFileListRequestCMD uint32 = 23
GetFileListResponseCMD uint32 = 24
二、客户端
客户端是使用c# + protobuf开发,只是简单的实现了一个TCPClient类,其它的大多是界面上的操作了:
TCPClien:
/// <summary>
/// 发送protobuf对象
/// </summary>
/// <param name="cmd">命令号</param>
/// <param name="sendMessage">protobuf对象</param>
/// <returns>已发送长度</returns>
public Int32 SendProtoMessage(Int32 cmd, IMessage message)
{
}
组装数据包,发送
/// <summary>
/// 接收消息线程
/// </summary>
/// <param name="state"></param>
private void ReceiveThread(Object state)
{
}
启动一个线程接收数据,把接收到的数据扔到队列里,再由DealQueueThread线程处理
在客户端其实有一些场景并不合适使用异步模式,比如 登录命令,注册命令,使用同步模式处理会更方便
/// <summary>
/// 处理消息线程
/// </summary>
/// <param name="state"></param>
private void DealQueueThread(Object state)
{
}
消息队列处理线程,把接收到的消息用 ProtocolDecoder.Singleton.Decode 解包回调
ProtocolDecoder:
协议解析类,通过命令号把byte[]转成相应的protobuf对象,并根据命令号回调Action,最终回调给界面
拿LoginRequest来举例:
首先增加一个Login.proto文件,里面有两个协议结构,LoginRequest用于请求,LoginResponse用于响应,
用protoc --csharp_out=. Login.proto编译成c#类文件,build.bat有编译的命令
message LoginRequest {
string UserID = 1; // 登陆的帐号
string Password = 2; // 密码
int32 Status = 3; // 状态
}
message LoginResponse {
Result Result = 1; // 返回值
UserInfo User = 2; // 用户信息
}
在ProtocolDecoder类里增加一个回调事件:public Action<LoginResponse> OnLoginResponse;
在GetMessage 和 OnEvent方法里增加相关的代码
在LoginForm_Load里注册事件回调方法ProtocolDecoder.Singleton.OnLoginResponse += OnLoginResponse;
最后,使用TCPClient.Singleton.SendProtoMessage(CMD.LoginRequestCMD, request);发送登录命令后,会回调到OnLoginResponse方法。
注意一点哈:登录方法其实使用同步模式更加方便合理,我这里是使用异步,所以要增加一个BaseTask类用于修改按钮的状态
三、服务端
服务端使用golang + protobuf开发,通讯组件使用 [zinx](http://github.com/aceld/zinx), zinx内部已经实现了
4个字节的长度 + 4个字节的包长 + 数据包 的协议
只要把命令号和处理对象绑定,并实现Handle方法就成了,其他的就是业务代码了
// 注册路由
server.AddRouter(models.LoginRequestCMD, &network.LoginRequest{})
server.AddRouter(models.RegisterRequestCMD, &network.RegisterRequest{})
server.AddRouter(models.GetFriendsRequestCMD, &network.GetFriendsRequest{})
server.AddRouter(models.UserOfflineRequestCMD, &network.LogoutRequest{})
server.AddRouter(models.ChangeStatusRequestCMD, &network.ChangeStatusRequest{})
server.AddRouter(models.UpdateUserInfoRequestCMD, &network.UpdateUserInfoRequest{})
server.AddRouter(models.FriendChatRequestCMD, &network.FriendChatRequest{})
server.AddRouter(models.GetUserListRequestCMD, &network.GetUserListRequest{})
server.AddRouter(models.AddFriendsRequestCMD, &network.AddFriendsRequest{})
server.AddRouter(models.HeartbeatRequestCMD, &network.HeartbeatRequest{})
server.AddRouter(models.UploadFileRequestCMD, &network.UploadFileRequest{})
server.AddRouter(models.GetFileListRequestCMD, &network.GetFileListRequest{})
客户端发送LoginRequest到服务后,服务端解析出 LoginRequestCMD 命令号,响应到network.LoginRequest{}里,在network.LoginRequest{}的Handle()里进行业务处理,最后使用LoginResponseCMD 和 pb.LoginResponse{}应答客户端的请求。
源码:https://github.com/bccber/gogotalk
client: c#+protobuf, server: golang+protobuf的更多相关文章
- golang protobuf SetExtension
对golang protobuf 的扩展字段赋值时候一直提示proto: bad extension value type clkUrl:="z.cn" proto.SetExte ...
- manjaro 下golang protobuf的使用
1.下载protobuf compiler sudo pacman -S protobuf 2.添加环境变量GOBIN export GOBIN=~/go/bin 3.下载golang依赖的包 go ...
- deepin 安装golang protobuf
1.安装库文件protobuf,地址:https://github.com/protocolbuffers/protobuf/releases 我电脑是deepin 64位的,所以我直接下载https ...
- Apache2.4:AH01630 client denied by server configuration
问题说明:Apache服务总共有4个,是为了防止单点故障和负载均衡,负载均衡控制由局方的F5提供. 访问的内容在NAS存储上,现象是直接访问每个apache的服务内容都是没有问题,但是从负载地址过来的 ...
- Java虚拟机6:内存溢出和内存泄露、并行和并发、Minor GC和Full GC、Client模式和Server模式的区别
前言 之前的文章尤其是讲解GC的时候提到了很多的概念,比如内存溢出和内存泄露.并行与并发.Client模式和Server模式.Minor GC和Full GC,本文详细讲解下这些概念的区别. 内存溢出 ...
- 十五天精通WCF——第三天 client如何知道server提供的功能清单
通常我们去大保健的时候,都会找姑娘问一下这里能提供什么服务,什么价格,这时候可能姑娘会跟你口述一些服务或者提供一份服务清单,这样的话大 家就可以做到童嫂无欺,这样一份活生生的例子,在wcf中同样是一 ...
- Couldn't open file on client side, trying server side 错误解决
09-09 09:43:21.651: D/MediaPlayer(3340): Couldn't open file on client side, trying server side09-09 ...
- 403 Forbidden client denied by server configuration[apache2, linux]
在LAMP的配置过程中, 由于APACHE的版本问题, 即使是APACHE2和APACHE2.2也有很大的不同. 一般都有同一个环境配置多个虚拟网站的情况, 如果你在配置过程中遇到APACHE的不同版 ...
- ORA-12737: Instant Client Light: unsupported server character set CHS16GBK/ZHS16GBK解决方案
二.Navicat for Oracle的配置 1.启动该工具,出现如下的开始界面,单击“连接”选项,进行连接数据库,如图所示: 6.在“新建连接”对话框中,输入任意的连接名,选择默认的连接类型,输入 ...
随机推荐
- spring自带的MD5加密工具类
Spring 自带的md5加密工具类,本来打算自己找一个工具类的,后来想起来Spring有自带的,就翻了翻 //导入包import org.springframework.util.DigestUti ...
- 图像通道、RGB与色彩体系
通道(Channels) 图像的通道指的是什么?是不是灰度图的通道数为1,彩色图的通道为3 ? 图像通道,在RGB色彩模式下就是指那单独的红色.绿色.蓝色部分.也就是说,一幅完整的图像,是由红色绿色蓝 ...
- window下dos命令
引用 Windows下DOS命令 显示当前目录所有文件 dir 创建文件夹 md test 创建文件 cd>a.txt 删除文件 del a.txt 删除文件夹 rd test 在某磁盘打开不同 ...
- vue项目前端导出word文件(bug解决)
摘要:之前项目中导出价格表是由后端实现,前端只需要调用接口下载word即可,后来业务改变比较大,word模版需要一直改动,后端改起来相对麻烦,后来直接前端自己定义模版,实现下载word文档. 一.需要 ...
- CSS居中的多种方法
1.水平居中:text-align 与 inline-block 的配合 <div id = "div_center_align"> <div id = &quo ...
- SpringIOC初始化过程--详解
SpringIOC初始化过程 相信大家都知道Spring这个东西,我们经常来用他一些特性,比如说他的AOP,IOC,那今天就带大家解析下SpringIOC的加载过程. 我们来看一个例子 Annotat ...
- 用后台开发的逻辑理念学习VUE
前言 近些年前端开发快速发展,现在学习前端已经不像以前那样仅仅学习一个语法就可以了,它已经是一门编程技术了,它们有自己独立的类似Main函数的入口,有像MVC一样规范好的层次结构,有自己的开发工具可以 ...
- Java基础之LinkedHashMap原理分析
知识准备HashMap 我们平时用LinkedHashMap的时候,都会写下面这段 LinkedHashMap<String, Object> map = new LinkedHashMa ...
- yum管理——搭建iso镜像私有yum源仓库(1)
在服务器上一般是没有光驱的,那么我们怎么制作iso本地repo镜像源仓库? 通过本地iso镜像,copy到linux系统中一个目录中,进行伪文件系统挂载,执行如下命令: 挂载:mount -o loo ...
- 在浏览器输入 URL 回车之后发生了什么(超详细版)
前言 这个问题已经是老生常谈了,更是经常被作为面试的压轴题出现,网上也有很多文章,但最近闲的无聊,然后就自己做了一篇笔记,感觉比之前理解更透彻了. 这篇笔记是我这两天看了数十篇文章总结出来的,所以相对 ...