WebSocket
我们可以通过WebSocket类使用WebSocket功能,只需要将服务器的Uri传递给WebSocket的构造函数即可:
void WebSocket()
{
WebSocket webSocket = new WebSocket(new Uri("wss://html5labs-interop.cloudapp.net/echo"));
//webSocket.OnOpen...
//注册事件之后,我们就可以开始连接
webSocket.Open();
//在这一步之后,我们将收到一个OnOpen事件,我们可以开始发送消息到服务器
webSocket.Send("Message to the Server");
byte[] buffer = new byte[1024];
webSocket.Send(buffer);
//所有通信完成之后,就关闭连接
webSocket.Close();
}
在这一步之后,我们可以注册我们的事件处理程序来处理这几个事件:
OnOpen事件:建立与服务器的连接时调用。 在此事件之后,WebSocket的IsOpen属性将为True,直到我们或服务器关闭连接或发生错误
OnMessage事件:当从服务器收到文本消息时调用
OnBinary事件: 当从服务器收到二进制信息时调用
OnClosed事件:当客户端或服务器关闭连接或发生内部错误时调用。
当客户端通过关闭功能关闭连接时,它可以提供一个代码和一个消息,指出关闭的原因。服务器通常会回应我们的代码和消息。
OnError事件:当我们无法连接到服务器时发生内部错误或连接丢失时调用。第二个参数是一个Exception对象,但它可以为null
OnErrorDesc事件:OnError是一个更具信息性的事件,因为后者仅通过Exception参数调用。 此事件在OnError事件之后调用,但它可以提供更详细的错误报告。
OnIncompleteFrame 事件: 在下面的Advanced Websocket中有介绍
Advanced WebSocket
Ping消息:通过在收到OnOpen事件之前将StartPingThread属性设置为True,可以启动一个新线程以将Ping消息发送 到服务器。这样Ping消息将定期发送到服务器,两次Ping之间的延迟可以在PingFrequency属性中设置(默认值为1000ms)。
Pong消息:从服务器接收到的所有ping消息都会自动生成Pong应答
Streaming:过长的文本或二进制信息将被分割。 这些片段默认由插件自动组装。
如果我们向WebSocket的OnIncompleteFrame事件注册事件处理程序,则可以覆盖此机制。
每次客户端收到不完整的片段时都会调用此事件。 这些片段将被插件忽略,它不会尝试组装这些片段或将它们存储起来。 此事件可用于实现流式传输体验。
Socket.IO
Socket.IO实现使用插件已具有的功能
它将发送HTTPRequests来获取握手数据,当轮询传输使用其所有功能(cookie,连接重用等)时发送和接收数据包。 WebSocket实现用于WebSocket传输。
这个Socket.IO实现的简单功能列表:
易于使用和熟悉的API
兼容最新的Socket.IO规范
从轮询传输到websocket传输的无缝升级
断开时自动重新连接
简单高效的二进制数据发送和多种方式的接收
在高级模式下使用它的强大工具(切换默认编码器,禁用自动解码等)
如果你想连接到一个Socket.IO服务,你可以使用BestHTTP.SocketIO.SocketManager类来完成。
首先你必须创建一个SocketManager实例:
var manager = new SocketManager(new Uri(“http://chat.socket.io/socket.io/“));
url中的/socket.io/路径非常重要,默认情况下,Socket.IO服务器将监听此查询。 所以不要忘记把它也加到你的测试网址上
Connecting to namespaces
void ConnectingToNamespaces()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
//默认情况下,SocketManager将在连接到服务器时连接到根(“/”)名称空间。 你可以通过SocketManager的Socket属性来访问它:
Socket root = manager.Socket;
//可以通过GetSocket(“/ nspName”)函数或通过管理器的索引器属性访问非默认名称空间:
Socket nsp1 = manager["/customNamespace"];
Socket nsp2 = manager.GetSocket("/customNamespace");
//首次访问命名空间将会启动内部连接程序
}
Subscribing and receiving events
//您可以订阅预定义和自定义事件
void SubscribingAndReceivingEvents()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
//预定义事件
//connect:当命名空间打开时发送
//connecting:当SocketManager开始连接到socket.io服务器时发送
//event:根据自定义(程序员定义的)事件发送
//disconnect:在传输断开时,SocketManager关闭,Socket关闭或在握手数据中指定的给定时间内未收到服务器的Pong消息时发送
//reconnect:插件成功重新连接到socket.io服务器时发送
//reconnecting:当插件尝试重新连接到socket.io服务器时发送
//reconnect_attempt:当插件尝试重新连接到socket.io服务器时发送
//reconnect_failed:当重新连接尝试无法连接到服务器并且ReconnectAttempt达到选项'ReconnectionAttempts'值时发送
//error:发送到服务器或内部插件错误。 该事件的唯一参数将是一个BestHTTP.SocketIO.Error对象
//自定义事件
//自定义事件是程序员定义的事件,您的服务器将发送给您的客户端。 您可以通过调用套接字的On函数来订阅事件
manager.Socket.On("login", (socket, packet, args) => { });
//socket参数将是服务器发送此事件的名称空间套接字对象。
//packet参数包含事件的内部数据包数据。 该数据包可用于访问服务器发送的二进制数据,或使用定制的Json解析器库来解码有效载荷数据
//args参数是一个可变长度数组,它包含来自数据包有效负载数据的已解码对象。
//使用默认的Json编码器,这些参数可以是对象的“原始”类型(int,double,string)或对象列表(List <object>)或Dictionary <string,object>
//服务器上发出的消息
//socket.emit('message', ‘MyNick’, ‘Msg to the client’);
//客户端捕获的消息
//订阅message事件
manager.Socket.On("message", (socket, packet, args) =>
{
Debug.Log(string.Format("Message from {0}: {1}", args[0], args[1]));
});
//其它与事件相关的功能
//Once:你可以订阅一个仅调用一次的事件
manager.Socket.Once("connect", (socket, packet, args) => { });
//off:取消订阅
manager.Socket.Off();//取消所有订阅的事件
manager.Socket.Off("connect");//对事件"connect"取消订阅
//manager.Socket.Off("connect", OnConnected); //从事件"connect"中移除OnConnected方法
}
Sending acknowledgement to the server
//向服务器发送确认
void SendingAcknowledgement()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
//您可以通过调用套接字的EmitAck函数向服务器发回确认
//您必须传递原始数据包和可选数据:
manager["/customNamespace"].On("customEvent", (socket, packet, args) =>
{
socket.EmitAck(packet, "Event", "Received", "Successfully");
});
}
Sending binary data
void SendingBinaryData()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
//有两种方式发送二进制数据
//一.
//通过Emit函数传递,插件将扫描参数,如果它找到一个参数,它会将其转换为二进制附件(如在Socket.IO 1.0中介绍的)。
//这是最有效的方法,因为它不会将字节数组转换为客户端上的Base64编码字符串,并且在服务器端将其转换为二进制。
byte[] data = new byte[10];
manager.Socket.Emit("eventWithBinary", "textual param", data);
//二.
//如果二进制数据作为字段或属性嵌入对象中,则Json编码器必须支持该转换。
//默认的Json编码器不能将嵌入的二进制数据转换为Json,你必须使用更高级的Json解析器库(比如“JSON .NET for Unity” - http://u3d.as/5q2)
}
Receiving binary data
void ReceivingBinaryData()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
//在Socket.IO服务器中,当二进制数据发送到客户端时,它将用Json对象({'_ placeholder':true,'num':xyz})替换数据,并将二进制数据发送到另一个数据包中
//在客户端,这些数据包将被收集并合并为一个数据包
//二进制数据将位于数据包的Attachments属性中
//在这里你将有一些使用这个数据包的选择:
//一、
//在您的事件处理函数中,您可以通过数据包的Attachments属性访问所有二进制数据
manager.Socket.On("frame", (socket, packet, args) =>
{
Texture2D texture2D = new Texture2D(0, 0);
texture2D.LoadImage(packet.Attachments[0]);
});
//二、
//第二个选项与前一个选项几乎相同,但有一点改进:我们不会将发送的Json字符串解码为c#对象
//我们可以这样做,因为我们知道服务器只发送二进制数据,这个事件没有其他信息。 所以我们会让插件知道不要解码有效载荷:
manager.Socket.On("frame", (socket, packet, args) =>
{
Texture2D texture2D = new Texture2D(0, 0);
texture2D.LoadImage(packet.Attachments[0]);
}, false);
//三、
//我们可以将“{'_placeholder':true,'num':xyz}”字符串替换为Attachments列表中Attachment的索引
manager.Socket.On("frame", (socket, packet, args) =>
{
//用索引替换Json对象
packet.ReconstructAttachmentAsIndex();
//解码有效载荷到object[]
args = packet.Decode(socket.Manager.Encoder);
//现在args只包含一个索引号(可能是0)
byte[] data = packet.Attachments[Convert.ToInt32(args[0])];
Texture2D texture2D = new Texture2D(0, 0);
texture2D.LoadImage(data);
}, false);
}
Set the default Json encoder
//设置默认的Json编码器
//如果由于各种原因想要更改默认的Json编码器,首先必须编写一个新的Json编码器
//为此,您必须编写一个新的类,该类可以从BestHTTP.SocketIO.JsonEncoders命名空间实现IJsonEncoder
//剥离的IJsonEncoder非常小,你只需要实现两个功能:
public interface IJsonEncoder
{
List<object> Decode(string json);
string Encode(List<object> obj);
}
//Decode函数必须将给定的json字符串解码为对象列表。 由于Socket.IO协议的性质,发送的json是一个数组,第一个元素是事件的名称。
//编码功能用于对客户想要发送到服务器的数据进行编码
//该列表的结构与Decode相同:列表的第一个元素是事件的名称,其他任何元素都是用户发送的参数。
//下面是使用示例文件夹中的LitJson库的完整示例:
public sealed class LitJsonEncoder : IJsonEncoder
{
public List<object> Decode(string json)
{
JsonReader reader = new JsonReader(json);
return JsonMapper.ToObject<List<object>>(reader);
}
public string Encode(List<object> obj)
{
JsonWriter writer = new JsonWriter();
JsonMapper.ToJson(obj, writer); return writer.ToString();
}
}
AutoDecodePayload
已经在“Receiving binary data”中讨论过AutoDecodePayload,但是您不仅可以在每个事件中设置该值,套接字也可以
套接字具有AutoDecodePayload属性,该属性用作事件订阅的默认值
其默认值为true - 所有有效载荷都被解码并分派给事件订户。 如果设置为false,则插件不会执行解码,您必须自行完成解码。
你不想每次都施放参数:当然! 您可以在Socket对象上设置AutoDecodePayload,并且可以使用您最喜欢的Json解析器将数据包的有效负载解码为强类型对象
但请记住,有效负载将包含事件的名称,它是一个json数组。 示例有效内容如下所示:“['eventName',{'field':'stringValue'},{'field':1.0}]”
Error handling
//发生服务器端或客户端错误时发生的“error”事件
//事件的第一个参数将是一个Error对象。 这将包含Code属性中的错误代码和Message属性中的字符串消息
//ToString()函数在这个类中被覆盖,你可以使用这个函数写出它的内容。
void ErrorHandling()
{
SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
manager.Socket.On(SocketIOEventTypes.Error, (socket, packet, args) =>
{
Error error = args[0] as Error;
switch (error.Code)
{
case SocketIOErrors.User:
Debug.Log("Exception in an event handler!");
break;
case SocketIOErrors.Internal:
Debug.Log("Internal error!");
break;
default:
Debug.Log("Server error!");
break;
}
Debug.Log(error.ToString());
});
}
Available options in the SocketOptions class
SocketOptions类中的可用选项
您可以将SocketOptions实例传递给SocketManager的构造函数
您可以更改以下选项:
Reconnection:断开连接后是否自动重新连接。它的默认值是true。
ReconnectionAttempts:放弃之前的尝试次数。它的默认值是Int.MaxValue
ReconnectionDelay:尝试重新连接之前最初等待多久。受+/- RandomizationFactor影响。例如,默认的初始延迟将在500毫秒到1500毫秒之间。其默认值是10000ms
ReconnectionDelayMax:重新连接之间等待的最长时间。如上所述,每次尝试都会增加重新连接延迟以及随机化。其默认值是5000ms
RandomizationFactor:它可以用来控制ReconnectionDelay范围。它的默认值是0.5,可以在0..1的值之间进行设置。
Timeout:发出“connect_error”和“connect_timeout”事件之前的连接超时。它不是底层的tcp套接字的连接超时,而是socket.io协议。它的默认值是20000ms
AutoConnect:通过将此设置为false,只要您决定适当,就必须调用SocketManager的Open()。
当你创建一个新的SocketOptions对象时,它的属性被设置为它们的默认值。
//SignalR(命名空间)
//ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信
//像Socket.IO这样使用插件的基本特性实现SignalR
//HTTPRequests和WebSockets用于连接和利用连接池进行通信
//Cookies随请求一起发送,记录器用于记录有关协议和错误的信息。
//SignalR实现的特性简要列表:
//与最新的SignalR服务器实现兼容
//易于使用的API
//传输回退
//重新连接逻辑
//支持所有集线器功能
The Connection class
//BestHTTP.SignalR命名空间中的Connection类管理到SignalR服务器的抽象连接
//连接到SignalR服务器从创建Connection对象开始
//该类将跟踪协议的当前状态并将触发事件
void TheConnectionClass()
{
//你有多个途径创建一个连接对象
Uri uri = new Uri("http://besthttpsignalr.azurewebsites.net/raw-connection/");
//通过仅将服务器的URI传递给构造函数来创建连接,而不使用集线器
Connection signlRConnection1 = new Connection(uri);
//通过将集线器名称也传递给构造函数来创建连接,并使用集线器
Connection signlRConnection2 = new Connection(uri, "hub1", "hub2", "hubN");
//通过将Hub对象传递给构造函数来创建连接,并使用Hub
//using BestHTTP.SignalR.Hubs;
Hub hub1 = new Hub("hub1");
Hub hub2 = new Hub("hub2");
Hub hubN = new Hub("hubN");
Connection signlRConnection3 = new Connection(uri, hub1, hub2, hubN);
//在创建Connection之后,我们可以通过调用Open()函数来开始连接到服务器
signlRConnection1.Open();
}
Handling general events
void HandlingGeneralEvents()
{
Uri uri = new Uri("http://besthttpsignalr.azurewebsites.net/raw-connection/");
Connection signlRConnection = new Connection(uri);
//Connection类将允许您订阅多个事件,这些事件如下:
//OnConnected:当connection类成功连接并且SignalR协议用于通信时,会触发此事件
signlRConnection.OnConnected += (con) => Debug.Log("Connected to the SignalR server!");
//OnClosed:当SignalR协议关闭时会触发此事件,并且不再发送或接收更多消息
signlRConnection.OnClosed += (con) => Debug.Log("Connection Closed");
//OnError:发生错误时调用。 如果连接已经打开,插件将尝试重新连接,否则连接将被关闭
signlRConnection.OnError += (con, err) => Debug.Log("Error: " + err);
//OnReconnecting:当重新连接尝试开始时,将触发此事件
//在此事件之后,将调用OnError或OnReconnected事件
//在OnReconnected / OnClosed事件之前可以触发多个OnReconnecting-OnError事件对,因为插件会在给定的时间内尝试重新连接多次。
signlRConnection.OnReconnecting += (con) => Debug.Log("Reconnecting");
//OnReconnected:重新连接尝试成功时触发
signlRConnection.OnReconnecting += (con) => Debug.Log("Reconnected");
//OnStateChnaged:连接状态改变时触发,事件处理程序将收到旧状态和新状态
signlRConnection.OnStateChanged += (conn, oldState, newState) => Debug.Log(string.Format("State Changed {0} -> {1}", oldState, newState));
//OnNonHubMessage:服务器向客户端发送非集线器消息时触发
//客户端应该知道服务器期望的消息类型,并且应该相应地转换接收到的对象
signlRConnection.OnNonHubMessage += (con, data) => Debug.Log("Message from server: " + data.ToString());
//RequestPreparator:每个HTTPRequest都会调用这个委托并将发送到服务器, 它可以用来进一步自定义请求
signlRConnection.RequestPreparator = (con, req, type) => req.Timeout = TimeSpan.FromSeconds(30);
}
Sending non-Hub messages
void SendingNonHubMessages()
{
Uri uri = new Uri("http://besthttpsignalr.azurewebsites.net/raw-connection/");
Connection signlRConnection = new Connection(uri);
//发送非集线器消息到服务器像在connection对象上调用一个函数一样容易:
signlRConnection.Send(new { Type = "Broadcast", Value = "Hello SignalR World!" });
//此函数将使用Connection的JsonEncoder将给定对象编码为Json字符串,并将其发送到服务器
//已编码的Json字符串可以使用SendJson函数发送:
signlRConnection.SendJson("{ Type: ‘Broadcast’, Value: ‘Hello SignalR World!’ }");
}
Hubs
//为了定义客户端上Hub可以从服务器调用的方法,并在服务器上调用Hub上的方法,必须将Hubs添加到Connection对象中
//这可以通过将集线器名称或集线器实例添加到Connection构造函数中完成,在Connection Class部分中已进行演示
//using BestHTTP.SignalR.Messages;
void Hubs()
{
Uri uri = new Uri("http://besthttpsignalr.azurewebsites.net/raw-connection/");
Connection signalRConnection = new Connection(uri);
//Accessing hubs (访问集线器)
Hub hub1 = signalRConnection[0];
Hub hub2 = signalRConnection["hubName"];
//Register server callable methods(注册服务器可调用方法)
//要处理服务器可调用方法的调用,我们必须调用集线器的On函数:
signalRConnection["hubName"].On("joined", (hub, msg) =>
{
Debug.Log(string.Format("{0} joined at {1}", msg.Arguments[0], msg.Arguments[1]));
});
//On的第二个参数类型是MethodCallMessage
//MethodCallMessage是一个服务器发送的对象,它包含以下属性:
//Hub:包含该方法必须调用的集线器名称的字符串
//Method:包含方法名称的字符串
//Arguments:包含方法调用参数的对象数组。 它可以是一个空数组
//State:包含其他自定义数据的字典。
//该插件将使用Hub和Method属性将消息发送到正确的集线器和事件处理程序。 处理方法调用的函数只能使用参数和状态属性
//Call server-side methods (调用服务端方法)
//调用服务器端方法可以通过调用Hub的Call函数来完成
//重载的调用函数能够满足每个需求
//Call函数是非阻塞函数,它们不会阻塞,直到服务器发送有关该呼叫的任何消息
//重载如下:
//Call(string method, params object[] args):
//这可用于以fireand -forget样式调用服务器端函数
//我们不会收到有关方法调用成功或失败的消息。 这个函数可以在没有任何'args'参数的情况下调用,以调用无参数方法
signalRConnection["hubName"].Call("Ping");
signalRConnection["hubName"].Call("Message", "param1", "param2");
//Call(string method, OnMethodResultDelegate onResult, params object[] args):
//该函数可以作为前一个函数使用,但函数可以传递第二个参数,该函数将在服务器端函数成功调用时调用。
signalRConnection["hubName"].Call("GetValue", OnGetValueDone);
//此回调函数接收调用此函数的Hub,发送给服务器的原始ClientMessage消息以及由服务器作为该方法调用结果发送的ResultMessage实例
//ResultMessage对象包含一个ReturnValue和一个State属性。
//如果方法的返回类型为void,则ReturnValue为null
//Call(string method, OnMethodResultDelegate onResult, OnMethodFailedDelegate onError, params object[] args):
//此函数可指定当方法在服务器上运行失败时调用的回调。 没有找到方法,参数错误或未处理的异常,在方法调用时都可能会引发故障
signalRConnection["hubName"].Call("GetValue",
OnGetValueDone,
OnGetValueFailed);
//FailureMessage包含以下属性:
//IsHubError:如果是Hub错误,则为True
//ErrorMessage:关于错误本身的简短消息
//StackTrace:如果服务器上打开了详细的错误报告,那么它将包含错误的堆栈跟踪
//AdditionalData:如果不为空,则它包含有关错误的其他信息
// Call(string method, OnMethodResultDelegate onResult, OnMethodFailedDelegate onError, OnMethodProgressDelegate onProgress, params object[] args):
//该函数可用于向服务器端方法调用添加额外的进度消息处理程序。 对于长时间运行的作业,服务器可以向客户端发送进度消息
signalRConnection["hubName"].Call("GetValue", OnGetValueDone, OnGetValueFailed, OnGetValueProgress);
}
void OnGetValueDone(Hub hub, ClientMessage originalMessage, ResultMessage result)
{
Debug.Log("GetValue executed on the server. Return value of the function:" + result.ReturnValue.ToString());
}
void OnGetValueFailed(Hub hub, ClientMessage originalMessage, FailureMessage error)
{
Debug.Log("GetValue failed. Error message from the server: " + error.ErrorMessage);
}
void OnGetValueProgress(Hub hub, ClientMessage originalMessage, ProgressMessage progress)
{
Debug.Log(string.Format("GetValue progressed: {0}%", progress.Progress));
}
Using the Hub class as a base class to inherit from
//使用Hub类作为从中继承的基类
//Hub类可以用作封装集线器功能的基类
class SampleHub : Hub
{
// Default constructor. Every hubs have to have a valid name.
public SampleHub() : base("SampleHub")
{
// Register a server-callable function
base.On("ClientFunction", ClientFunctionImplementation);
}
// Private function to implement server-callable function
private void ClientFunctionImplementation(Hub hub, MethodCallMessage msg)
{
// TODO: implement
}
// Wrapper function to call a server-side function.
public void ServerFunction(string argument)
{
base.Call("ServerFunction", argument);
}
}
//这个SampleHub可以被实例化并传递给Connection的构造函数
void SampleHubImplement()
{
Uri uri = new Uri("http://besthttpsignalr.azurewebsites.net/raw-connection/");
SampleHub sampleHub = new SampleHub();
Connection signalRConnection = new Connection(uri, sampleHub);
}
Authentication
Connection类具有AuthenticationProvider属性,可以将其设置为实现IAuthenticationProvider接口的对象
实现者必须实现以下属性和函数:
bool IsPreAuthRequired:如果必须在Connection类向服务器发出任何请求之前运行身份验证,则返回true。
示例:cookie身份验证器必须返回false,因为它必须发送用户凭据并接收必须随请求一起发送的cookie
StartAuthentication:仅当IsPreAuthRequired为true时才需要的函数。 否则它不会被调用
PrepareRequest:用请求和请求类型枚举调用的函数。 此功能可用于在请求发送到服务器之前准备请求
OnAuthenticationSucceded:当IsPreAuthRequired为true且认证过程成功时必须调用的事件
OnAuthenticationFailed:当IsPreAuthRequired为true且认证过程失败时必须调用的事件
//一个非常简单的基于Header的验证器看起来像这样:
//using BestHTTP.SignalR.Authentication;
class HeaderAuthenticator : IAuthenticationProvider
{
public string User { get; private set; }
public string Roles { get; private set; }
// No pre-auth step required for this type of authentication
public bool IsPreAuthRequired { get { return false; } }
// Not used event as IsPreAuthRequired is false
public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
// Not used event as IsPreAuthRequired is false
public event OnAuthenticationFailedDelegate OnAuthenticationFailed;
// Constructor to initialise the authenticator with username and roles.
public HeaderAuthenticator(string user, string roles)
{
this.User = user;
this.Roles = roles;
}
// Not used as IsPreAuthRequired is false
public void StartAuthentication() { }
// Prepares the request by adding two headers to it
public void PrepareRequest(BestHTTP.HTTPRequest request, RequestTypes type)
{
request.SetHeader("username", this.User);
request.SetHeader("roles", this.Roles);
}
}
Writing custom Json encoders
编写自定义Json编码器
就像Socket.IO的Manager类一样,SignalR的Connection类具有JsonEncoder属性,并且也可以设置静态Connection.DefaultEncoder
JsonEncoder必须从BestHTTP.SignalR.JsonEncoders名称空间实现IJsonEncoder接口
此软件包包含一个样本LitJsonEncoder,也被一些例子使用
Server-Sent Events (EventSource)
Server-Sent Events是一种基于字符串的单向协议
数据来自服务器,并且没有选择向服务器发送任何内容。 它使用最新的草案实施
虽然协议的名称是Server-Sent Events,但该类本身被命名为EventSource。
当发生错误时,插件会在发送LastEventId后尝试重新连接,让服务器发送我们应该收到的任何缓冲消息
The EventSource class
//using BestHTTP.ServerSentEvents;
void EventSourceClass()
{
EventSource eventSource = new EventSource(new Uri("http://server.com"));
//Properties
//这些是EventSource类公开公开的属性:
//Uri:这是协议尝试连接的端点。 它通过构造函数设置。
//State:EventSource对象的当前状态。
//ReconnectionTime:尝试执行重新连接尝试需要等待多少时间。 它的默认值是2秒。
//LastEventId:最近收到的事件的ID。 如果没有接收到事件ID,它将为空。
//InternalRequest:将在Open函数中发出的内部HTTPRequest对象。
//Events
//OnOpen:它在协议成功升级时调用
eventSource.OnOpen += (source) => Debug.Log("EventSource Opened!");
//OnMessage:它在客户端收到来自服务器的新消息时调用
//该函数将接收一个Message对象,该对象包含Data属性中消息的有效内容
//每次客户端收到消息时都会调用此事件,即使消息具有有效的事件名称,并且我们为此事件分配了事件处理程序!
eventSource.OnError +=(source,error)=> Debug.Log("Error: " + error);
//OnRetry:在插件尝试重新连接到服务器之前调用此函数。 如果函数返回false,则不会进行尝试,并关闭EventSource。
eventSource.OnRetry += (source)=> false;
//OnClosed:EventSource关闭时会调用此事件
eventSource.OnClosed += (source) => Debug.Log("EventSource Closed!");
//OnStateChanged:当State属性变化时调用
eventSource.OnStateChanged += (source,oldState,newState)=> Debug.Log(string.Format("State Changed {0} => {1}", oldState, newState));
//Functions
//这些是EventSource对象的公有方法
// Open: 调用此函数后,插件将开始连接到服务器并升级到ServerSent Events协议
eventSource.Open();
// On: 使用这个功能,客户端可以订阅事件
eventSource.On("userLogon", (source, msg) => { Debug.Log(msg.Data); });
// Off: 它可以用来取消订阅活动
eventSource.Close();
}
The Message class
Message类是一个逻辑单元,它包含服务器可以发送的所有信息。
属性
Id:发送事件的ID。 如果没有ID发送,可以为空。 它由插件使用。
Event:事件的名称。 如果没有发送事件名称,则可以为null。
Data:消息的实际有效负载。
Retry:服务器发送插件在尝试重新连接之前等待的时间。 它由插件使用
Logging
为了能够转储一些重要的 - 有时甚至是不太重要的 - 插件的功能,v1.7.0中引入了一个记录器接口和实现
默认的记录器可以通过HTTPManager.Logger属性进行访问
默认的日志级别是“调试版本的警告”和“其他版本的错误”
默认的记录器实现使用Unity的Debug.Log / LogWarning / LogError函数
可以通过从BestHTTP.Logger命名空间实现ILogger接口来编写新的记录器。