CSE116的学习笔记-Lec5-4:WebSocket_Server
WebSocket Server
Teach you how to write a simple server:)
The Problem
- In CSE115 you used HTTP request / responses to build web apps
- If you wanted more data from the server after the page loads, you used AJAX
- Server hosts JSON data at certain end points
- Client makes an AJAX call to retrieve the most current data
- But the server has to wait for a request before sending a response
- What if the server wants to send time-sensitive data without waiting for a request?
- In CSE115
- Built a chat app using polling
- Client sent AJAX requests at regular intervals
- Only get updates when AJAX request is sent
- Can use long-polling
- Server hangs on poll requests until it has new data to send
- A newer solution (Standardized in 2011)
- Establishes a lasting connection
- Enables 2-way communication between server and client
- Server can push updates to clients over the web socket without waiting for the client to make a new request
socket.io
- A library built on top of web sockets
- Maintains connections and reconnecting
- Uses message types
- Similar to actors, except the message type is always a string
- Add listeners to react to different message types
- Receiving a message is an event
- Listener code will be called when the event occurs
socket.io Server in Scala
- New library
- Link on the course website
- Dependency included in pom.xml in examples repo
Web Socket Server
- Import from the new library
- Setup and start the server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import com.corundumstudio.socketio.listener.{ConnectListener, DataListener, DisconnectListener}
import com.corundumstudio.socketio.{AckRequest, Configuration, SocketIOClient, SocketIOServer}
class Server() {
val config: Configuration = new Configuration {
setHostname("localhost")
setPort(8080)
}
val server: SocketIOServer = new SocketIOServer(config)
server.addConnectListener(new ConnectionListener())
server.addDisconnectListener(new DisconnectionListener())
server.addEventListener("chat_message", classOf[String], new MessageListener())
server.addEventListener("stop_server", classOf[Nothing], new StopListener(this))
server.start()
}
- Create a configuration object for the server
- This server will run on localhost port 8080
1
2
3
4val config: Configuration = new Configuration {
setHostname("localhost")
setPort(8080)
}
- Create and start the server
- Use the configuration to tell the library how to setup the server
- Call the start() method to start listening for connections
1
2
3
4
5val server: SocketIOServer = new SocketIOServer(config) // Create a server
...
server.start() // Start the server
- Add listener to handle different event types
- Connect and disconnect listeners to react to clients connecting and disconnecting
- Event listeners for each different message tyoe received from clients
1
2
3
4server.addConnectListener(new ConnectionListener()) // added connect listener
server.addDisconnectListener(new DisconnectionListener()) // added disconnect listener
server.addEventListener("chat_message", classOf[String], new MessageListener()) // added event listener
server.addEventListener("stop_server", classOf[Nothing], new StopListener(this)) // added event listener
- For connect and disconnect
- Create classes overriding ConnectListener and DisconnectListener
- Implement the onConnect / onDisconnect methods
- These methods take a reference to the sending socket as a parameter
- Can use this reference to send messages to the client
- Usually want to store each reference to send messages later
1
2server.addConnectListener(new ConnectionListener())
server.addConnectListener(new DisconnectionListener())1
2
3
4
5class ConnectionListener() extends ConnectListener {
override def onConnect(socket: SocketIOClient): Unit = {
println("Connected: " + socket)
}
}1
2
3
4
5class DisconnectionListener() extends DisconnectListener {
override def onDisconnect(socket: SocketIOClient): Unit = {
println("Disconnected: " + socket)
}
}
- To receive messages, specify the message type and the class of the message
- Create classes extending DataListener[message_type]
- For message class we’ll use
- String to receive text data
- Nothing if it’s just a message (Similar to an actor receiving a case object)
1
2server.addEventListener("chat_message", classOf[String], new MessageListener())
server.addEventListener("stop_server", classOf[Nothing], new StopListener(this))1
2
3
4
5
6class MessageListener() extends DataListener[String] {
override def onData(socket: SocketIOClient, data: String, ackRequest: AckRequest): Unit = {
println("received_message: " + data + "from: " + socket)
socket.sendEvent("ACK", "I received your message of " + data)
}
}1
2
3
4
5
6
7class StopListener(server: Server) extends DataListener[Nothing] {
override def onData(socket: SocketIOClient, data: Nothing, ackRequest: AckRequest): Unit = {
println("stopping server")
server.server.stop()
println("safe to stop program")
}
}
- Use the reference to the Socket to send messages to the client
- Specify the type of the message as a String
- If the message contains data, use a second String
1
socket.sendEvent("ACK", "I received your message of " + data)
Web Socket Clients
- We’ve set up a web socket server that will listen for connections and process message
- Now, let’s build a web socket client that will connect to the server
WebSocket Client - Web
- First, setup the HTML
- Layout and style of the page
- Could add CSS for more style
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web Socket Client Example</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
</head>
<body>
<input type="text" id="chat_input"/>
<button id="gold" onclick="sendMessage();">Submit</botton>
<div id="display_message"></div>
<script src="WebClient.js"></script>
</body>
</html>
- Could add CSS for more style
- Download the socket.io JavaScript client library
- This library contains all the code we’ll need to connect to pur server
1
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
- Add elements for the user to enter and send a message
- In JavaScript, we’ll implement the sendMessage() function
1
2
3
4<input type="text" id="chat_input"/>
<button id="gold" onclick="sendMessage();">Submit</botton>
<div id="display_message"></div>
- Download our JavaScript file
- This script runs codes to connect to the server as soon as it’s downloaded
- Include this at the end of the body so the page loads before connecting to the server
1
<script src="WebClient.js"></script>
- Include this at the end of the body so the page loads before connecting to the server
- In WebClinet.js
- Call io.connect to the server
- Returns a reference to the created socket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const socket = io.connect("http://localhost:8080", {transports: {'websocket'}});
socket.on('ACK', function (event) {
document.getElementById("display_message").innerHTML = event;
});
socker.on('server_stopped', function (event) {
document.getElementById("display_message").innerHTML = "The server has stopped";
});
function sendMessage() {
let message = document.getElementById("chat_input").value
document.getElementById("chat_input").value = "";
socket.emit("chat_message", message);
}
- Returns a reference to the created socket
- Define how the socket will react to different message types with the “on” method
- The “on” method takes the message type and a function as arguments
- Call the function whenever a message of that type is received from the server
1
2
3
4
5
6
7socket.on('ACK', function (event) {
document.getElementById("display_message").innerHTML = event;
});
socker.on('server_stopped', function (event) {
document.getElementById("display_message").innerHTML = "The server has stopped";
});
- Call the function whenever a message of that type is received from the server
- The function should take a parameter which will contain the data of the message if there is any
- We receive an ACK message containing a string which we display on the page (Similar to case class)
- We receive a server_stopped message and inform he user that the server stopped (Similar to case object)
- To send a message, call emit
- Takes the message type and the content of the message, if any
- Can call emit with only message type to send a message with no content (Similar to case object)
Web Socket Demo
Lecture Question
Task:
Write a Web Socket Server that counts the number of messages it receives
In a package named server, write a class named LectureServer
that:
- When created, sets up a web socket server listening for connections on localhost:8080
- Listens for messages of type “increment” with no data
- Has a method named
numberOfMessages
that returns (as an Int) the number of times a message of type “increment” was received
Testing:
No test:)
Hint:
If you have no idea how to write, check prof. example repo -> link
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment
TwikooValine