This example shows you how to create a WebSocket API server using Oracle Java.
Although other server-side languages can be used to create a WebSocket server, this example uses Oracle Java to simplify the example code.
This server conforms to RFC 6455, so it only handles connections from Chrome version 16, Firefox 11, IE 10 and higher.
WebSockets communicate over a TCP (Transmission Control Protocol) connection. Java's ServerSocket class is located in the java.net package.
Constructor:
ServerSocket(int port)
When you instantiate the ServerSocket class, it is bound to the port number you specified by the port argument.
Here's how to implement what we have learnt:
import java.net.ServerSocket; import java.net.Socket; public class Server{ public static void main(String[] args){ ServerSocket server = new ServerSocket(80); System.out.println("Server has started on 127.0.0.1:80.\r\nWaiting for a connection..."); Socket client = server.accept(); System.out.println("A client connected."); } }
Methods:
java.net.
Socket getInputStream()
java.net.
Socket getOutputStream()
Methods:
write(byte[] b, int off, int len)
Writes len
bytes from the specified byte array starting at offset off
to this output stream.
Methods:
read(byte[] b, int off, int len)
Reads up to len bytes of data from the input stream into an array of bytes.
Let us extend our example.
Socket client = server.accept(); System.out.println("A client connected."); InputStream in = client.getInputStream(); OutputStream out = client.getOutputStream(); new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next();
When a client connects to a server, it sends a GET request to upgrade the connection to a WebSocket from a simple HTTP request. This is known as handshaking.
import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; //translate bytes of request to string String data = new Scanner(in,"UTF-8").useDelimiter("\\r\\n\\r\\n").next(); Matcher get = Pattern.compile("^GET").matcher(data); if (get.find()) { } else { }
Creating the response is easier than understanding why you must do it in this way.
You must,
if (get.find()) { Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data); match.find(); byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n" + "Connection: Upgrade\r\n" + "Upgrade: websocket\r\n" + "Sec-WebSocket-Accept: " + DatatypeConverter .printBase64Binary( MessageDigest .getInstance("SHA-1") .digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11") .getBytes("UTF-8"))) + "\r\n\r\n") .getBytes("UTF-8"); out.write(response, 0, response.length); }
After a successful handshake, client can send messages to the server, but now these are encoded.
If we send "abcdef", we get these bytes:
129 | 134 | 167 | 225 | 225 | 210 | 198 | 131 | 130 | 182 | 194 | 135 |
- 129:
FIN (Is this the whole message?) | RSV1 | RSV2 | RSV3 | Opcode |
---|---|---|---|---|
1 | 0 | 0 | 0 | 0x1=0001 |
FIN: You can send your message in frames, but now keep things simple.
Opcode 0x1 means this is a text. Full list of Opcodes
- 134:
If the second byte minus 128 is between 0 and 125, this is the length of the message. If it is 126, the following 2 bytes (16-bit unsigned integer), if 127, the following 8 bytes (64-bit unsigned integer, the most significant bit MUST be 0) are the length.
I can take 128 because the first bit is always 1.
- 167, 225, 225 and 210 are the bytes of the key to decode. It changes every time.
- The remaining encoded bytes are the message.
decoded byte = encoded byte XOR (position of encoded byte BITWISE AND 0x3)th byte of key
Example in Java:
byte[] decoded = new byte[6]; byte[] encoded = new byte[] {198, 131, 130, 182, 194, 135}; byte[] key = byte[4] {167, 225, 225, 210}; for (int i = 0; i < encoded.length; i++) { decoded[i] = (byte)(encoded[i] ^ key[i & 0x3]); }
© 2005–2018 Mozilla Developer Network and individual contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java