WebSocket - ScutGame/Scut GitHub Wiki

此章节介绍如何创建WebSocket的服务端项目

项目搭建参考如何搭建服务端项目工程

注:Scut在6.7.9.5以上版本提供了支持WebSocket协议的服务端与客户端,支持WebSocket协议的版本:Hybi00, Hybi10Rfc6455版本;

了解WebSocket

在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。

  • 在浏览的支持
Chrome              | Supported in version 4+
Firefox             | Supported in version 4+
Internet Explorer   | Supported in version 10+
Opera               | Supported in version 10+
Safari              | Supported in version 5+

##服务端WebSocket

Chat使用WebSocket的Sample

###GameWebSocketHost类

提供注册事件

  • OnHandshaked: 注册客户端握手成功事件
  • OnPing: 注册客户端发送Ping命令处理事件,自己实现增加心跳包刷新处理
  • OnPong: 注册客户端Pong应答命令事件
  • OnClosedStatus: 注册接收客户端关闭事件
  • OnHeartbeatTimeout: 注册心跳包超时事件,可在GameSession.HeartbeatTimeout设置,默认60S超时
  • OnError: 注册接收消息处理出错事件

###WebSocket协议使用

  • MainClass类继承GameWebSocketHost类,即可实现WebSocket通讯方式;示例代码如下:
    #!Csharp
    public class MainClass : GameWebSocketHost
    {
        public MainClass()
        {
            GameEnvironment.Setting.ActionDispatcher = new WebSocketActionDispatcher();
        }

        protected override void OnStartAffer()
        {
        }

        protected override void OnServiceStop()
        {
        }

        protected override void OnHandshaked(ISocket sender, ConnectionEventArgs e)
        {
            Console.WriteLine("client:{0}", e.Socket.Handshake.Url);
            base.OnHandshaked(sender, e);
        }

        protected override void OnRequested(ActionGetter actionGetter, BaseGameResponse response)
        {
            Console.WriteLine("parma action:{0}", actionGetter.GetActionId());
            base.OnRequested(actionGetter, response);
        }

    }
  • 定义WebSocketActionDispatcher类
    #!Csharp
    public class WebSocketActionDispatcher : ScutActionDispatcher
    {

        public override ActionGetter GetActionGetter(RequestPackage package, GameSession session)
        {
            // 可以实现自定的ActionGetter子类
            return new HttpGet(package, session) { OpCode = OpCode.Text };
        }

        public override void ResponseError(BaseGameResponse response, ActionGetter actionGetter, int errorCode, string errorInfo)
        {
            //实现出错处理下发
            response.BinaryWrite(Encoding.UTF8.GetBytes(errorCode + "-" + errorInfo));
        }
    }

  • 定义Action接口协议

排行榜例子:

    public class Action1001 : JsonAction
    {
        private int PageIndex;
        private int PageSize;
        private List<UserRanking> rankingList;

        public Action1001(ActionGetter actionGetter)
            : base(1001, actionGetter)
        {

        }
	
        public override bool GetUrlElement()
        {
            if (httpGet.GetInt("PageIndex", ref PageIndex)
                 && httpGet.GetInt("PageSize", ref PageSize))
            {
                return true;
            }
            return false;
        }
	
        public override bool TakeAction()
        {
            var cache = new ShareCacheStruct<UserRanking>();
            rankingList = cache.FindAll(false);
            rankingList = MathUtils.QuickSort<UserRanking>(rankingList, compareTo);
            rankingList = rankingList.GetPaging(PageIndex, PageSize, out PageCount);
            return true;
        }

        protected override string BuildResponsePack()
        {
            return MathUtils.ToJson(rankingList);         
        }
    }
  • 游戏配置

在项目中的GameServer.exe.config文件中增加以下,使用同Socket配置。

<add key="Game.Port" value="9001" />

参考服务器推送消息

##客户端WebSocket

###ClientWebSocket类

提供方法和注册事件

  • ReadyState: 连接状态属性, 0:未连接, 1:已连接, 2:关闭
  • Connect: 建立WebSocket连接
  • ConnectAsync: 异步建立WebSocket连接
  • Ping: 发送Ping命令方法
  • OnOpened: 注册成功打开WebSocket连接事件
  • OnMessage: 注册接收WebSocket消息事件
  • OnClosed: 注册WebSocket关闭事件
  • OnError: 注册WebSocket异常事件
  • OnPing: 注册接收到服务端Ping命令事件
  • OnPong: 注册服务端Ping应答命令事件

###WebSocket协议使用

    static class Program
    {
        static void Main()
        {
	    AutoResetEvent closeEvent = new AutoResetEvent(false);
	    int messageLen = 0;
	    AutoResetEvent messageEvent = new AutoResetEvent(false);
	    ClientWebSocket client = new ClientWebSocket("ws://127.0.0.1:" + port + "/chat?d=xx", new string[] { "chat" }, "http:///127.0.0.1/", 8);
	    client.OnOpened += (sender, args) => { Console.WriteLine("client open ok"); };
	    client.OnMessage += (sender, args) =>
	    {
		messageLen = args.Data.Length;
		messageEvent.Set();
	    };
	    client.OnError += (sender, args) => { Console.WriteLine("client open error "); };
	    client.OnPong += (sender, args) => { Console.WriteLine("client ping response: " + args.Source.Message); };
	    client.OnClosed += (sender, args) =>
	    {
		closeEvent.Set();
	    };
	    client.Connect();
	    //client.ConnectAsync();
	    while (true)
	    {
		Thread.Sleep(1000);
		if (client.ReadyState == ConnectState.Success)
		{
		    break;
		}
	    }
	    client.Ping();
	}
    }