WebSocket - ScutGame/Scut GitHub Wiki
此章节介绍如何创建WebSocket的服务端项目
项目搭建参考如何搭建服务端项目工程
注:Scut在6.7.9.5以上版本提供了支持WebSocket协议的服务端与客户端,支持WebSocket协议的版本:Hybi00, Hybi10和Rfc6455版本;
了解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();
}
}