ET服务器框架学习笔记(二十一)

ET服务器框架学习笔记(二十一)

最近一直忙着搞自己的项目,终于在年前得空补充一下之前没写清楚的东西


前言

本篇主要补充的是ET服务器中,有关于socket异步在ET服务器中的具体处理方式。


一、ET的异步处理

首先,ET的服务器架构是单线程多进程的方式(ET5.0)。多线程的处理,对于小白来说非常麻烦,而且很容易导致各种锁的问题,所以猫大决定采用这种架构方式。
这里又会出一个问题,我们自己的服务器当然单线程多进程没问题,那些网络,IO等等,不可能让他们阻塞线程吧,所以有了异步处理。
而C#的async,与await异步语法,好用又方便,感觉就是在以同步的语法写异步操作,所以猫大给与了ETTask这种方式,具体可以看之前的文章。
最后,由于类似socket本身有异步处理,但是他的异步处理,很有可能是多线程的,所以猫大又想了一个方法,来解决这种异步处理,即:SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext.Instance);

二、ET网络方面的异步处理

1.SynchronizationContext

简单来说,这个东西就是用来,线程之间通信用的一种机制。比如线程A,它有一个SynchronizationContext,那么我想在线程B中调用线程A跑一段代码,就可以用SynchronizationContext的Send,或者Post方法来实现。具体可以看微软官方解释:微软官方文档

那么ET中是怎么使用的呢,首先在服务器入口函数,APP-Program-Main函数开始的地方,设置一个当前线程的同步上下文,

// 异步方法全部会回掉到主线程
			SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext.Instance);

内部实现方式就是,ThreadSynchronizationContext类继承一个SynchronizationContext,然后走单例方式就好。然后内部实现一个Post,所以异步的回调(不管是否是其他线程抛过来的)都可以放到这个类里面。这个类在主线程中,每1毫秒检测一次是否有回调,然后调用回调方法就好,这样所有异步回调都集中到主线程中了。

2.ET中的TService

TService主要用于监听客户端的连接请求,当有客户的请求过来时,与其建立一个新的socekt连接,保持客户端与服务器之间的通信。
绑定端口之类的服务器socekt使用方式就不多说了,主要是一个函数Socket.AcceptAsync,它开始一个异步操作来接受一个传入的连接尝试。
由于这个函数是异步,而且是要客户端连接触发的,所以我们并不能知道他到底是会在何时回调,有可能我们一调用,就是同步操作,也有可能要等一下才会完成。
首先假设它是异步完成,那么我们就需要将它扔到上面所说的ThreadSynchronizationContext中进行后续处理。猫大的实现方式:

this.ThreadSynchronizationContext.PostNext(this.AcceptAsync);
private void AcceptAsync()
		{
			this.innArgs.AcceptSocket = null;
			if (this.acceptor.AcceptAsync(this.innArgs))
			{
				return;
			}
			OnAcceptComplete(this.innArgs.SocketError, this.innArgs.AcceptSocket);
		}

如果是异步的话,那么this.acceptor.AcceptAsync肯定是挂起状态了,所以OnAcceptComplete不会走,同时操作完成时的回调靠的是,下面的回调。至于这个回调是多线程,还是单线程就是socket的事情了(我个人理解是多线程的,毕竟是网络),在OnComplete中,将OnAcceptComplete函数处理抛到ThreadSynchronizationContext中,得以在主线程中处理。

this.innArgs.Completed += this.OnComplete;
private void OnAcceptComplete(SocketError socketError, Socket acceptSocket)
		{
			if (this.acceptor == null)
			{
				return;
			}
			
			// 开始新的accept
			this.AcceptAsync();
			
			if (socketError != SocketError.Success)
			{
				Log.Error($"accept error {socketError}");
				return;
			}

			try
			{
				long id = this.CreateAcceptChannelId(0);
				TChannel channel = new TChannel(id, acceptSocket, this);
				this.idChannels.Add(channel.Id, channel);
				long channelId = channel.Id;
				
				this.OnAccept(channelId, channel.RemoteAddress);
			}
			catch (Exception exception)
			{
				Log.Error(exception);
			}			
		}

第二种情况是,this.acceptor.AcceptAsync一调用马上就处理,直接同步完成了,IO没有挂起,那么this.acceptor.AcceptAsync返回false,可以直接处理了,直接调用OnAcceptComplete就是在主线程中处理了。在OnAcceptComplete中,开启新的一轮等待下一个客户端的连接,同时对这个已经连接上的客户端连接通过acceptSocket封装成一个TChannel与session去处理他们后续的业务。

总结

ET服务器框架网路方面,有一点绕,主要就是在异步处理上,加上socket监听可能异步也可能同步,所以只要理解这一点,加上对ET的异步处理方式,就能理解ET服务器在网络方面的设计了。当然,ET强大之处在于,你不需要完全理解他的做法(实际上我了解也不深)就可以直接上手开撸了,最近猫大对ET6.0来了一波大改动,大家有时间可以去看看源码,对于自身技术,思维方式,架构理解方面,都可以得到很大的提升。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值