之前已经讲解了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. 如何检查显卡类型,DirectX和OpenGL的版本

    How To: Check the graphics card type and OpenGL version From: http://support.esri.com/technical-arti ...

  2. 国内A股16家上市银行的財务数据与股价的因子分析报告(1)(工具:R)

    分析人:BUPT_LX 研究目的 用某些算法对2014年12月份的16家国内A股上市的商业银行当中11项財务数据(资产总计.负债合计.股本.营业收入.流通股A.少数股东权益.净利润.经营活动的现金流量 ...

  3. Linux安装pear包

    一.安装pear包. 1.安装: $ sudo wget http://pear.php.net/go-pear.phar $ sudo php go-pear.har 2.查看pear下安装的包: ...

  4. 《React-Native系列》44、基于多个TextInput的键盘遮挡处理方案优化

    曾经写过两篇关于在ReactNative上处理键盘遮挡输入表单TextInput的情况.建议读者能够先看看 1.<React-Native系列>33. 键盘遮挡问题处理 2.<Rea ...

  5. JSjs获取当前时间的前一天/后一天(昨天/明天)

    Date curDate = new Date(); var preDate = new Date(curDate.getTime() - 24*60*60*1000); //前一天 var next ...

  6. Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'系列二:reset slave

    reset slave会清除从库的所有复制信息.一般应用场景:如切换为不同的Master, 主从重做等: 1. 命令在slave上执行,执行前一定要stop slave. 2. 执行reset sla ...

  7. 顺利编译 binutiles-gcc-glibc

    恩,前面一篇弃了,先知道怎么能成功,还有要避开哪些坑,然后再去仔细研究到底咋回事. 这里顺利编译 arm-lfs-linux-gnueabi , 参考了下面的资料: 1. <Linux From ...

  8. Mysql Left Join Where On

    select t1.id,t2.idfrom t1left join t2 on t1.id = t2.id and t1.id>1 and t2.id<>3在mysql的left ...

  9. Response的返回内容类型

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6682514.html  服务器在返回结果给浏览器时,通常需要先设置响应头的contentType属性.那么,c ...

  10. Linux下通用打印系统CUPS使用教程

    昨天研究了一下关于在Linux下实现打印操作的相关内容,整理记录如下: 1.什么是CUPS CUPS(Common UNIX Printing System,即通用Unix打印系统)是FedoraCo ...