之前已经讲解了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:作业基本运行原理

    Spark作业基本运行原理: 我们使用spark-submit提交一个spark作业之后,这个作业就会启动一个对应的Driver进程.根据你使用的部署模式(deploy-mode)不同:1)Drive ...

  2. windows 通过Web.config添加mimetype映射

    在Web.config里添加以下代码即可 <configuration> <system.webServer> <staticContent> <!-- re ...

  3. 在SpringTest中将Mockito的mock对象通过spring注入使用

    转载:https://blog.csdn.net/m0_38043362/article/details/80111957 1. 原理介绍 通过BeanFactoryPostProcessor向Bea ...

  4. 小教程:自己创建一个jQuery长阴影插件

    长阴影设计是平面设计的一个变体,添加了阴影,产生了深度的幻觉,并导致了三维的设计.在本教程中,我们将创建一个jQuery插件,通过添加完全可自定义的长阴影图标,我们可以轻松地转换平面图标. 戳我查看效 ...

  5. MVC4发布到IIS,出现HTTP 错误 404.0 - Not Found

    web.config中添加 <system.webServer> <modules runAllManagedModulesForAllRequests="true&quo ...

  6. DELL平板如何安装WIN10系统 -标记活动分区的问题

    在计算机管理中没有这个选项   可以在分区助手软件中,选中C分区之后,左边有设置活动分区,然后左上角提交执行即可        

  7. css背景全屏-视差

    <!DOCTYPE html> <html> <head> <title></title> <style> *{margin:0 ...

  8. 使用docker api

    前提: 系统centos 7 docker version 1.10.3 使用systemd启动docker 访问方式: 修改/usr/lib/systemd/system/docker.servic ...

  9. Android 在闹钟开机时,如何解决开机动画没有播完就进入Launcher M

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  10. 深度学习-Caffe中启用MatlabSupport编译出错的解决方案

    一.如果编译前打算生成支持Matlab的库,则设置MatlabSupport为true之后. 二.记得添加Matlab的安装路径.我的是:D:\Application\DevTools\Matlab ...