使用Beetle简单构建聊天室程序
之前已经讲解了Beetle简单地构建网络通讯程序,那程序紧紧是讲述了如何发送和接收数据;这一章将更深入的使用Beetle的功能,主要包括消息制定,协议分析包括消息接管处理等常用的功能。为了更好的描述所以通过创建一个聊天室程序来体现以上功能的易用性。
在实现功能之前先想好通讯上的协议需要什么功能,总结一下有:登陆,登陆成功返回,登陆和退出通过,获取现有其他用户和发送聊天信息等。需要的基础功能已经明确那就制定消息了.
通过Beetle处理消息对象必须实现IMessage接口,主要目的是由组件更好地管理buffer,避免重复的byte[]构建开销.
public interface IMessage
{
void Save(BufferWriter writer);
void Load(BufferReader reader);
}
注册和返回
public class Register:MsgBase
{
public string Name;
public override void Load(Beetle.BufferReader reader)
{
base.Load(reader);
Name = reader.ReadString();
}
public override void Save(Beetle.BufferWriter writer)
{
base.Save(writer);
writer.Write(Name); } }
public class RegisterResponse : MsgBase
{ }
注册和断开通知
public class OnRegister : MsgBase
{
public OnRegister()
{
User = new UserInfo();
}
public UserInfo User;
public override void Load(Beetle.BufferReader reader)
{
base.Load(reader);
User = reader.ReadObject<UserInfo>();
}
public override void Save(Beetle.BufferWriter writer)
{
base.Save(writer);
writer.Write(User);
}
}
public class UnRegister :OnRegister
{ }
获取其他用户
public class ListUsers:MsgBase
{
}
public class ListUsersResponse:MsgBase
{
public ListUsersResponse()
{
Users = new List<UserInfo>();
}
public override void Load(Beetle.BufferReader reader)
{
base.Load(reader);
Users = reader.ReadObjects<UserInfo>();
}
public override void Save(Beetle.BufferWriter writer)
{
base.Save(writer);
writer.Write(Users);
}
public IList<UserInfo> Users;
}
发送了聊天信息
public class Say:MsgBase
{
public Say()
{
User = new UserInfo();
}
public override void Load(Beetle.BufferReader reader)
{
base.Load(reader);
User = reader.ReadObject<UserInfo>();
Body = reader.ReadString();
}
public override void Save(Beetle.BufferWriter writer)
{
base.Save(writer);
writer.Write(User);
writer.Write(Body);
}
public UserInfo User;
public string Body; }
协议制订完成后就进入服务端的编写了,之前已经讲述了如何构建一个socket tcp服务这里的不重复了,主要描述一下在连接事件中如何对连接进行ChannelAdapter实例化实现自动分析协议和消息分发处理。
static void OnConnect(object sender, ChannelEventArgs e)
{
e.Channel.ChannelError += OnError;
ChannelAdapter adapter = new ChannelAdapter(e.Channel,
new HeadSizePackage(Logic.MsgBase.GetMessage));
adapter.RegisterHandler(new Program());
e.Channel.BeginReceive();
Console.WriteLine("{0} Connected!", e.Channel.EndPoint);
}
当产生连接的时候只需要针对构建一个ChannelAdapter对象即可实现协议分析,以上代码是采用头描述大小来分析协议包,组件还提供基于自定义结束符的分包方式。HeadSizePackage提供了默认的封包方式,不过可以承继它重写相关方法实现更细的封包和解包(在后面再一一讲述)。
构建了Adapter的就要注册消息处理对象,通过RegisterHandler方法进行注册,对象必须实现
public interface IMessageHandler
{
void ProcessMessage(ChannelAdapter adapter, MessageHandlerArgs message);
}
接下来我们来实现服务端处理的代码
public void _Register(Beetle.ChannelAdapter adapter, Logic.Register e)
{
adapter.Channel.Name = e.Name;
Logic.RegisterResponse response = new Logic.RegisterResponse();
adapter.Send(response);
Logic.OnRegister onreg = new Logic.OnRegister();
onreg.User = new Logic.UserInfo { Name= e.Name, IP= adapter.Channel.EndPoint.ToString() };
foreach (TcpChannel channel in mServer.GetOnlines())
{
if (channel != adapter.Channel)
channel.Adapter.Send(onreg);
}
Console.WriteLine("{0} login from {1}", e.Name, adapter.Channel.EndPoint);
}
public void _Say(Beetle.ChannelAdapter adapter, Logic.Say e)
{
e.User.Name = adapter.Channel.Name;
e.User.IP = adapter.Channel.EndPoint.ToString();
foreach (TcpChannel channel in mServer.GetOnlines())
{
if (channel != adapter.Channel)
channel.Adapter.Send(e);
}
Console.WriteLine("{0} say", e.User.Name);
}
public void _List(Beetle.ChannelAdapter adapter, Logic.ListUsers e)
{
Logic.ListUsersResponse response = new Logic.ListUsersResponse();
foreach (TcpChannel channel in mServer.GetOnlines())
{
if (channel != adapter.Channel)
{
response.Users.Add(new Logic.UserInfo { Name=channel.Name,IP= channel.EndPoint.ToString() });
}
}
adapter.Send(response);
}
public void ProcessMessage(ChannelAdapter adapter, MessageHandlerArgs message)
{ }
从上面的实现估计有同学感觉奇怪,为什么ProcessMessage什么都没有做。的确这个方法可以什么都不需要做,不过它可以做很多事情所有消息都经过这个方法,通过message参数的一个属性确定是否分发到具体方法中;如果不改变那个值组件会放发到具体的消息方法中。对于方法的对应关系是根据Message的类型来确定,还有方法的定义必须是public否则无法处理.
到这里服务端的工作已经完成,代码并不复杂简单的几句就完成了。接下来就是客户端的工作,相对服务端来的客户也是一样简单。为了省时间创建连接和绑定Adapter部分就不说了,其代码和服务端基本一致。
public void _ReceiveSay(Beetle.ChannelAdapter adapter, Logic.Say e)
{
string message = string.Format(@"\viewkind4\uc1\pard\sa200\sl276\slmult1\lang2052\f0\cf1\fs22 {0} \cf0 {2} IP:{1} \cf0\line {3}",
e.User.Name, e.User.IP, DateTime.Now, e.Body);
Invoke(new Action<string>(msg => { addSay(msg); }), message);
}
public void _OtherUnRegister(Beetle.ChannelAdapter adapter, Logic.UnRegister e)
{
Invoke(new Action<Logic.UnRegister>(o =>
{
lstUsers.Items.Remove(o.User);
}), e);
}
public void _OthreRegister(Beetle.ChannelAdapter adapter, Logic.OnRegister e)
{
Invoke(new Action<Logic.OnRegister>(o =>
{
if (!lstUsers.Items.Contains(o.User))
lstUsers.Items.Add(o.User);
}), e);
}
public void _OnLogin(Beetle.ChannelAdapter adapter, Logic.RegisterResponse e)
{
Logic.ListUsers list = new Logic.ListUsers();
adapter.Send(list);
Invoke(new Action<object>(o =>
{ toolStrip2.Enabled = false;
groupBox2.Enabled = true;
}), new object());
}
public void _OnList(Beetle.ChannelAdapter adapter, Logic.ListUsersResponse e)
{
Invoke(new Action<Logic.ListUsersResponse>(o =>
{
lstUsers.Items.Clear();
foreach (Logic.UserInfo item in o.Users)
{
lstUsers.Items.Add(item);
} }), e);
}
客户端的代码主要是接收后更新UI,下面看来这个聊天室程序的效果,为了能显示图片采用了richTextBox控件,直接发送rft格式对方接收后添加到对应的richTextBox即可.
详细可以下载代码了解。
下载代码
测试服务器:109.169.59.115
使用Beetle简单构建聊天室程序的更多相关文章
- 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序
对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...
- 基于AJAX的长轮询(long-polling)方式实现简单的聊天室程序
原理: 可以看:http://yiminghe.javaeye.com/blog/294781 AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP ...
- ASP.NET 使用application和session对象写的简单聊天室程序
ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览 ...
- 高级IO复用应用:聊天室程序
简单的聊天室程序:客户端从标准输入输入数据后发送给服务端,服务端将用户发送来的数据转发给其它用户.这里采用IO复用poll技术.客户端采用了splice零拷贝.服务端采用了空间换时间(分配超大的用户数 ...
- 使用Beetle简单构建高性能Socket tcp应用
beetle是基于c#编写的高性能Socket tcp组件,它基于SocketAsyncEventArgs的实现并提供了发送队列和接收队列的支持,可以根据情况灵活地设置1-N个发送队列和接收队列.除了 ...
- 简易的命令行聊天室程序(Winsock,服务器&客户端)
代码中使用WinSock2函数库,设计并实现了简单的聊天室功能.该程序为命令行程序.对于服务器和客户端,需要: 服务器:创建监听套接字,并按本地主机绑定:主线程监听并接受来自客户端的请求,并为该客户端 ...
- ASP.NET Signalr 2.0 实现一个简单的聊天室
学习了一下SignalR 2.0,http://www.asp.net/signalr 文章写的很详细,如果头疼英文,还可以机翻成中文,虽然不是很准确,大概还是容易看明白. 理论要结合实践,自己动手做 ...
- [SignalR]一个简单的聊天室
原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...
- Android简单的聊天室开发(client与server沟通)
请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...
随机推荐
- OCR 基本知识
OCR,optical character recognition 的简称,也就是光学识别系统,属于图形识别的一个分支,OCR是针对印刷体字符,採用光学的方式将文档资料转换成原始资料黑白点阵的图像文件 ...
- Try Before Choosing
 Try Before Choosing Erik Doernenburg CREATing An AppliCATion REquiRES MAKing MAny dECiSionS. Some ...
- jQuery 1
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8& ...
- Android Developers:按钮
按钮是有文本或者图标(或者文本和图标)组成,它传达用户触摸它的时候所发生的动作. 你可以在你的布局中使用三种方式创建按钮,取决于你是否想创建文本按钮,突变按钮或者两者都有: 设置文本,使用Button ...
- Android总结之WebView与Javascript交互[转]
Android总结之WebView与Javascript交互 前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.We ...
- 基于TQ2440开发板的WiFi模块的使用经验总结
一.软.硬件资源准备: 内核版本:linux-2.6.30.4 交叉编译器版本:4.3.3 wpa_supplicant工具:wpa_supplicant-0.7.3.tar ; openssl-0. ...
- POSTGRESQL 支持正则表达式
昨天遇到了一个奇葩的问题,需要在WHERE条件里面添加正则表达式,抱着试试看的态度,查看了一下postgresql,发现确实可以支持正则,例如: select * from user where em ...
- angularjs也支持script形式的template
<script type="text/ng-template" id="name"> https://docs.angularjs.org/api/ ...
- 创新大师Steve Blank: 你真的知道什么是真正的精益创业吗?
编者注:本文来自被誉为当代创新大师的Steve Blank的博客. 中文版由天地会珠海分舵编译. 全文从当今非常多人对精益创业的误解作为一个切入点,深入的分析了为什么人们这么easy就对精益创业产生误 ...
- eclipse/STS 提升注解提示速度
window -- preference -- 输入content -- java -- editor -- content Assist --auto delay 选项 改为100或者更低 提示速 ...