之前已经讲解了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即可.

详细可以下载代码了解。

下载代码

Beelet.ChatRoom.rar (1.16 mb)

测试服务器:109.169.59.115

使用Beetle简单构建聊天室程序的更多相关文章

  1. 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序

    对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...

  2. 基于AJAX的长轮询(long-polling)方式实现简单的聊天室程序

    原理: 可以看:http://yiminghe.javaeye.com/blog/294781 AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP ...

  3. ASP.NET 使用application和session对象写的简单聊天室程序

    ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览 ...

  4. 高级IO复用应用:聊天室程序

    简单的聊天室程序:客户端从标准输入输入数据后发送给服务端,服务端将用户发送来的数据转发给其它用户.这里采用IO复用poll技术.客户端采用了splice零拷贝.服务端采用了空间换时间(分配超大的用户数 ...

  5. 使用Beetle简单构建高性能Socket tcp应用

    beetle是基于c#编写的高性能Socket tcp组件,它基于SocketAsyncEventArgs的实现并提供了发送队列和接收队列的支持,可以根据情况灵活地设置1-N个发送队列和接收队列.除了 ...

  6. 简易的命令行聊天室程序(Winsock,服务器&客户端)

    代码中使用WinSock2函数库,设计并实现了简单的聊天室功能.该程序为命令行程序.对于服务器和客户端,需要: 服务器:创建监听套接字,并按本地主机绑定:主线程监听并接受来自客户端的请求,并为该客户端 ...

  7. ASP.NET Signalr 2.0 实现一个简单的聊天室

    学习了一下SignalR 2.0,http://www.asp.net/signalr 文章写的很详细,如果头疼英文,还可以机翻成中文,虽然不是很准确,大概还是容易看明白. 理论要结合实践,自己动手做 ...

  8. [SignalR]一个简单的聊天室

    原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...

  9. Android简单的聊天室开发(client与server沟通)

    请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...

随机推荐

  1. 最全的spark基础知识解答

    原文:http://www.36dsj.com/archives/61155 一. Spark基础知识 1.Spark是什么? UCBerkeley AMPlab所开源的类HadoopMapReduc ...

  2. SharePoint 2010/2013: List view Lookup threshold uncovered

    SharePoint with Large lists is common scenario in any Sharepoint deployment. While there are Several ...

  3. OpenGL ES 3.0之Shading Language(八)

    每个OpenGL ES 3.0程序要求一个顶点着色器和一个片段着色器去渲染一个图形.着色器概念是API 的中心,本篇将介绍着色器语言部分包含下面几项 1.变量和变量类型 2.矢量和矩阵创建及选择 3. ...

  4. 造轮子 | 怎样设计一个面向协议的 iOS 网络请求库

    近期开源了一个面向协议设计的网络请求库 MBNetwork,基于 Alamofire 和 ObjectMapper 实现,目的是简化业务层的网络请求操作. 须要干些啥 对于大部分 App 而言,业务层 ...

  5. CAD2006您没有足够的权限来安装本产品

    在Win10的环境下安装CAD2006,可能会报错"您没有足够的权限来安装本产品". 解决方法是,右键以"兼容性疑难解答"运行 在弹出的对话框中,点击 &quo ...

  6. iOS9中找不到XXX.dylib 与 is unavailable no availabel on ios (app extension) - use view controller 的解决办法

    在 iOS9 中现在找不到 XXX.dylib 了,比如libz.tbd  如果要用到 libz.dylib,可以用下面的办法,来自 Stack Overflow. Go to Build Phase ...

  7. JavaScript Array 对象扩展方法

    /** 删除数组中指定索引的数据 **/ Array.prototype.deleteAt = function (index) { if (index < 0) { return this; ...

  8. Linux中在线安装Mysql和修改密码设置服务启动

    一.说明:本文教大家在linux下在线安装mysql.网上的很多文章写的太乱,我们只取操作最方便的在线安装方式.本文以Centos为例. 二.安装过程. 1.安装客户端和服务端: (1)检查是否已经安 ...

  9. SqlServer插入1000条记录

    1.想在SqlServer中插入指定数量的测试记录怎么办? 2.解决: DECLARE @var INT ) BEGIN INSERT INTO test (Name) VALUES (convert ...

  10. 在hadoop上运行java文件

    hadoop 2.x版本 编译:javac -d . -classpath /usr/lib/hadoop/hadoop-common-2.2.0.2.0.6.0-102.jar TestGetPat ...