Ibragimov Ruslan, ruslan@ibragimov.by
// On client side
// client socket (TCP or UDP, default TCP)
// @since JDK 1.0
Socket socket = new Socket(hostName, portNumber);
// On server side
// server socket
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket connectedClient = serverSocket.accept();
// Server logic:
while (true) {
accept a connection;
create a thread to deal with the client;
}
// Or in case of NIO:
ServerSocketChannel
Alexey Diomin - Need for Speed: Netty & Protobuf (youtube)
A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.What Is a Socket?
An HTTP session is a sequence of network request-response transactions.
Okay
An HTTP/1.1 session is a sequence of network request-response transactions.
A layer on TCP
Full-duplex, stateful connection
Stream of messages (rather than bytes)
HTTP used for the initial handshake
HANDSHAKE REQUEST
GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
Part of JavaEE 7
Not using Servlet API
@ServerEndpoint("/ws")
public class Getter {
@OnMessage
public void getValue(String data, Session client) {
String returnText = getTimeStamp();
client.getAsyncRemote().sendText(returnText);
}
}
No fallback
No sub-protocol support
Too low level
Single WebSocket connection per client
results in single @ServerEndpoint per application
var socket = new WebSocket('ws://itx.by:12010/updates');
socket.onopen = function () {
setInterval(function() {
if (socket.bufferedAmount == 0)
socket.send(getUpdateData());
}, 50);
};
socket.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
socket.onmessage = function (message) {
console.log('Server: ' + message.data);
};
socket.onclose = function() {
console.log('Closed.');
};
W3C: The WebSocket API and W3C: Server-Sent Events | MDN: WebSocket
Simple protocol for asynchronous message passing
Originally for scripting languages (Ruby, Python)
Supported by message brokers
Suited for use on the web
COMMAND
header1:value1
header2:value2
body^@
SEND ===>>>
SUBSCRIBE, UNSUBCRIBE ===>>>
MESSAGE <<<===
ERROR <<<===
RECEIPT <<<===
ACK, NACK ===>>>
A key concept in STOMP
Opaque string, syntax left to server
Typically URI path-like ("/queue/a", "/topic/a")
Produce messages: via SEND frame with "destination" header
Consume messages: SUBSCRIBE frame w/ "destination" + MESSAGE frames from server
Server cannot send unsolicited messages!
SEND
destination:/topic/trade
content-type:application/json
content-lenght:46
{"action":"Buy","ticker":"EMC","shares":"44"}^@
@Configuration
@EnableWebSocketMessageBroker
public class Config implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry r) {
r.addEndpoint("/ws").withSockJS(); // WebSocket URL prefix
}
@Override
public void configureMessageBroker(MessageBrokerConfigurer c) {
c.enableSimpleBroker("/topic/"); // destination prefix
}
}
@Controller
public class TradeController {
@MessageMapping("/trade")
@SendTo("/topic/trade")
public String trade(Trade trade) {
// Return value broadcast to "/topic/trade"
return "[" + getTimestamp() + "]: ";
}
}
@RestController
public class TradeController {
@Autowired
private SimpMessagingTemplate template;
@RequestMapping(value="/trade", method=POST)
public void greet(Trade trade) {
this.template.convertAndSend("/topic/trade", trade);
}
}
@RestController
public class TradeController {
// ...
@MessageExceptionHandler
@SendToUser("/queue/errors")
public String handleException(IllegalStateException ex) {
return ex.getMessage();
}
}
var socket = new SockJS('/ws');
var client = Stomp.over(socket);
client.connect('', '', function(frame) {
var user = frame.headers['user-name'];
var suffix = frame.headers['queue-suffix'];
client.subscribe("/queue/trade" + suffix, function(msg) {
// ...
});
client.subscribe("/queue/errors" + suffix, function(msg) {
// ...
});
}
@Configuation
public class WebSocketSecurityConfig extends
AbstractSecurityWebSocketMessageBrokerConfigurer {
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
. simpDestMatchers("/user/queue/errors").permitAll()
. simpDestMatchers("/**").hasRole("ADMIN");
}
}
// or "hasRole('ROLE_ADMIN')"
@PreAuthorize("hasRole('ADMIN')")
@MessageMapping("/update")
public void update(Update update, Principal principal) {
// ...
}