首页 > 代码库 > WebSokcet之ServerEndPoint

WebSokcet之ServerEndPoint

WebSocket是JavaEE7新支持的:

 

The javax.websocket.server package contains annotations, classes, and interfaces to create and configure server endpoints.

    Javax.websocket.server包含注解,类,接口用于创建和配置服务端点

The javax.websocket package contains annotations, classes, interfaces, and exceptions that are common to client and server endpoints.

    Javax.websocket包则包含服务端点和客户断电公用的注解,类,接口,异常

 

To create a programmatic endpoint, you extend the Endpoint class and override its lifecycle methods.

创建一个编程式的端点,需要继承Endpoint类,重写它的方法。

To create an annotated endpoint, you decorate a Java class and some of its methods with the annotations provided by the packages mentioned previously.

创建一个注解式的端点,将自己的写的类以及类中的一些方法用前面提到的包中的注解装饰(@EndPoint,@OnOpen等等)。

 

编程式注解示例:

 

@ServerEndpoint("/WebSocketServer")

public class ServerEndPoint808

{

 

@OnOpen

public void start(Session session)

{

System.out.println("连接成功 " + session.getId());

}

 

@OnMessage

public void reMessage(Session session, String str)

{

try

{

session.getBasicRemote().sendText(str + " who are you");

}

catch (IOException e)

{

e.printStackTrace();

}

}

 

@OnError

public void error(Session session, Throwable t)

{

t.printStackTrace();

 

}

 

@OnClose

public void close()

{

 

}

 

After you have created an endpoint, you deploy it to an specific URI in the application so that remote clients can connect to it.

当创建好一个(服务)端点之后,将它以一个指定的URI发布到应用当中,这样远程客户端就能连接上它了。

 

WebSocket endpoints are represented by URIs that have the following form:

Websocket(服务)端点以URI表述,有如下的访问方式:

ws://host:port/path?query

wss://host:port/path?query

 

注解详解:

@ServerEndPoint:

    Required Elements :

         Value: URI映射

    Optional Elemens:

         subprotocols:

         decoders:解码器

         encoders:编码器

        configurator:

Annotation

Event

Example

OnOpen

Connection opened

@OnOpen

Public void open(Session session,

EndpointConfig conf) { }

OnMessage

Message received

@OnMessage

public void message(Session session,

String msg) { }

OnError

Connection error

@OnError

public void error(Session session,

Throwable error) { }

OnClose

Connection closed

@OnClose

public void close(Session session,

CloseReason reason) { }

 

建立连接相关:

The Session parameter represents a conversation between this endpoint and the remote endpoint.

Session代表着服务端点与远程客户端点的一次会话。

 

Because the container creates an instance of the endpoint class for every connection, you can define and use instance variables to store client state information.

容器会为每一个连接创建一个EndPoint的实例,需要利用实例变量来保存一些状态信息。

 

the Session.getUserProperties method provides a modifiable map to store user

Session.getUserProperties提供了一个可编辑的map来保存properties,

properties. For example, the following endpoint replies to incoming text messages

例如,下面的端点在收到文本消息时,将前一次收到的消息回复给其他的端点

with the contents of the previous message from each client:

 

@ServerEndpoint("/delayedecho")

public class DelayedEchoEndpoint

{

@OnOpen

public void open(Session session)

{

session.getUserProperties().put("previousMsg", " ");

}

 

@OnMessage

public void message(Session session, String msg)

{

 

String prev = (String) session.getUserProperties().get("previousMsg");

 

session.getUserProperties().put("previousMsg", msg);

try {

session.getBasicRemote().sendText(prev);

 

     } catch (IOException e) { ... }

}

}

To store information common to all connected clients, you can use class (static) variables; however, you are responsible for ensuring thread-safe access to them

 

发送、接收消息:

WebSocket endpoints can send and receive text and binary messages. In addition, they can also send ping frames and receive pong frames.

Websocket endpoint能够发送和接收文本、二进制消息,另外,也可以发送ping帧和接收pong 帧

发送消息:

  1. Obtain the Session object from the connection.

    从连接中获得Session对象

    The Session object is available as a parameter in the annotated lifecycle methods of the endpoint, like those in Table 18–1.

        Session对象是endPoint中那些被注解标注的方法中可得到的参数

When your message is a response to a message from the peer,

当你的message作为另外的消息的响应

you have the Session object available inside the method that received the message (the method annotated with @OnMessage).

在@OnMessage标注的方法中,有session对象接收message

If you have to send messages that are not responses, store the Session object as an instance variable of the endpoint class in the method annotated with @OnOpen

如果你必须主动发送message,需要在标注了@OnOpen的方法中将session对象作为实例变量保存

so that you can access it from other methods.

这样,你可以再其他方法中得到该session对象

 

  1. Use the Session object to obtain a Remote Endpoint object.

    通过Session对象获得Remote endpoint对象

    The Session.getBasicRemotemethod and the Session.getAsyncRemotemethod

    return RemoteEndpoint.Basicand RemoteEndpoint.Asyncobjects respectively.

    The RemoteEndpoint.Basicinterface provides blocking methods to send

    messages; the RemoteEndpoint.Asyncinterface provides nonblocking methods.

  2. Use the RemoteEndpoint object to send messages to the peer.

    利用RemoteEndpoint对象来发送message

    The following list shows some of the methods you can use to send messages to the

    peer.

    ■ void RemoteEndpoint.Basic.sendText(String text)

    Send a text message to the peer. This method blocks until the whole message

    has been transmitted.

    ■ void RemoteEndpoint.Basic.sendBinary(ByteBuffer data)

    Send a binary message to the peer. This method blocks until the whole

    message has been transmitted.

    ■ void RemoteEndpoint.sendPing(ByteBuffer appData)

    Send a ping frame to the peer.

    ■ void RemoteEndpoint.sendPong(ByteBuffer appData)

    Send a pong frame to the peer.

代码示例:

@ServerEndpoint("/echoall")

public class EchoAllEndpoint

{

@OnMessage

public void onMessage(Session session, String msg)

{

try {

for (Session sess : session.getOpenSessions())

{

if (sess.isOpen())

sess.getBasicRemote().sendText(msg);

}

} catch (IOException e) { ... }

}

}

接收消息:

The OnMessage annotation designates methods that handle incoming messages.

OnMessage注解指定方法来处理接收的messages

You can have at most three methods annotated with @OnMessage in an endpoint,

在一个端点类中,至多可以为三个方法标注@OnMessage注解

one for each message type: text, binary, and pong.

消息类型分别为:textbinarypong

 

Encoders and Decoders(编码器和解码器):

The Java API for WebSocket provides support for converting between WebSocket messages and custom Java types using encoders and decoders.

WebSocket Api 提供了encoders 和 decoders用于 Websocket Messages 与传统java 类型之间的转换

An encoder takes a Java object and produces a representation that can be transmitted as a WebSocket message;

编码器输入java对象,生成一种表现形式,能够被转换成Websocket message

for example, encoders typically produce JSON, XML, or binary representations.

例如:编码器通常生成json、XML、二进制三种表现形式

A decoder performs the reverse function; it reads a WebSocket message and creates a Java object.

解码器执行相反的方法,它读入Websocket消息,然后输出java对象

编码器编码:

  1. Implement one of the following interfaces:

    Encoder.Text<T>for text messages

    Encoder.Binary<T>for binary messages

    These interfaces specify the encode method. Implement an encoder class for each custom Java type that you want to send as a WebSocket message.

    这些接口指定编码方法,为你想作为Websocket Message传递的java 类型实现编码类

  2. Add the names of your encoder implementations to the encoders optional parameter of the ServerEndpoint annotation.

     

    将实现的编码器类的names添加到@ServerEndPoint注解中

     

  3. Use the sendObject(Object data) method of the RemoteEndpoint.Basic or RemoteEndpoint.Async interfaces to send your objects as messages. The container

looks for an encoder that matches your type and uses it to convert the object to a WebSocket message.

利用RemoteEndpoint.Basic 或者RemoteEndpoint.Async的sendObject(Object data)方法将对象作为消息发送,容器寻找一个符合此对象的编码器,

利用此编码器将此对象转换成Websocket message

代码示例:

public class MessageATextEncoder implements Encoder.Text<MessageA>

{

@Override

public void init(EndpointConfig ec) { }

@Override

public void destroy() { }

@Override

public String encode(MessageA msgA) throws EncodeException

{

// Access msgA‘s properties and convert to JSON text...

return msgAJsonString;

}

}

Then, add the encodersparameter to the ServerEndpointannotation as follows:

@ServerEndpoint(

value = http://www.mamicode.com/"/myendpoint",

encoders = { MessageATextEncoder.class, MessageBTextEncoder.class }

)

解码器解码:

  1. Implement one of the following interfaces:

     

    Decoder.Text<T>for text messages

Decoder.Binary<T>for binary messages

These interfaces specify the willDecode and decode methods.

  1. Add the names of your decoder implementations to the decoders optional parameter of the ServerEndpoint annotation.

     

  2. Use the OnMessage annotation in the endpoint to designate a method that takes your custom Java type as a parameter.

     

    When the endpoint receives a message that can be decoded by one of the decoders you specified,

the container calls the method annotated with @OnMessage that takes your custom Java type as a parameter if this method exists.

public class MessageTextDecoder implements Decoder.Text<Message>

{

@Override

public void init(EndpointConfig ec)

{

}

 

@Override

public void destroy()

{

}

 

@Override

public Message decode(String string) throws DecodeException

{

// Read message...

if ( /* message is an A message */ )

return new MessageA(...);

else if ( /* message is a B message */ )

return new MessageB(...);

}

 

@Override

public boolean willDecode(String string)

{

// Determine if the message can be converted into either a

// MessageA object or a MessageB object...

return canDecode;

}

}

 

Then, add the decoderparameter to the ServerEndpointannotation as follows:

 

@ServerEndpoint(

value = http://www.mamicode.com/"/myendpoint",

encoders = { MessageATextEncoder.class, MessageBTextEncoder.class },

decoders = { MessageTextDecoder.class }

)

 

处理错误:

To designate a method that handles errors in an annotated WebSocket endpoint, decorate it with @OnError:

 

为一个注解式的端点指定一个处理error的方法,为此方法加上@OnError注解:

 

@ServerEndpoint("/testendpoint")

public class TestEndpoint {

...

@OnError

public void error(Session session, Throwable t)

{

t.printStackTrace();

...

}

}

 

This method is invoked when there are connection problems, runtime errors from message handlers, or conversion errors when decoding messages.

 

当出现连接错误,运行时错误或者解码时转换错误,该方法才会被调用

 

指定端点配置类:

The Java API for WebSocket enables you to configure how the container creates server endpoint instances.

 

Websocketapi允许配置容器合适创建server endpoint 实例

 

You can provide custom endpoint configuration logic to:

 

Access the details of the initial HTTP request for a WebSocket connection

Perform custom checks on the OriginHTTP header

Modify the WebSocket handshake response

Choose a WebSocket subprotocol from those requested by the client

Control the instantiation and initialization of endpoint instances

 

To provide custom endpoint configuration logic, you extend the ServerEndpointConfig.Configurator class and override some of its methods.

继承ServerEndpointConfig.Configurator 类并重写一些方法,来完成custom endpoint configuration 的逻辑代码

In the endpoint class, you specify the configurator class using the configurator parameter of the ServerEndpoint annotation.

 

代码示例:

public class CustomConfigurator extends ServerEndpointConfig.Configurator

{

@Override

public void modifyHandshake(ServerEndpointConfig conf,

HandshakeRequest req, HandshakeResponse resp)

{

conf.getUserProperties().put("handshakereq", req);

}

}

 

The following endpoint class configuresendpoint instances with the custom configurator, which enables them to access the handshake request object:

 

@ServerEndpoint(

value = "http://www.mamicode.com/myendpoint",

configurator = CustomConfigurator.class

)

 

public class MyEndpoint

{

@OnOpen

public void open(Session s, EndpointConfig conf)

{

HandshakeRequest req = (HandshakeRequest) conf.getUserProperties()

.get("handshakereq");

Map<String,List<String>> headers = req.getHeaders();

...

}

}