|
package com.sanofc.ws; |
|
|
|
import java.io.BufferedReader; |
|
import java.io.IOException; |
|
import java.io.InputStreamReader; |
|
import java.io.OutputStreamWriter; |
|
import java.io.PrintStream; |
|
import java.net.ServerSocket; |
|
import java.net.Socket; |
|
import java.nio.ByteBuffer; |
|
import java.nio.file.Files; |
|
import java.nio.file.Path; |
|
import java.nio.file.Paths; |
|
import java.security.MessageDigest; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.util.Base64; |
|
import java.util.HashSet; |
|
|
|
public class WebSocketServer { |
|
|
|
private static HashSet<Socket> socketSet = new HashSet<Socket>(); |
|
|
|
public static void main(String[] args) throws IOException { |
|
int port = 5000; |
|
ServerSocket serverSocket = new ServerSocket(port); |
|
while (true) { |
|
Socket socket = serverSocket.accept(); |
|
System.out.println("accept"); |
|
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); |
|
String line; |
|
boolean isWebSocket = false; |
|
String webSocketKey = ""; |
|
|
|
while (!(line = in.readLine()).equals("")) { |
|
System.out.println(line); |
|
String[] spLine = line.split(":"); |
|
if (isWebSocket && spLine[0].equals("Sec-WebSocket-Key")) { |
|
webSocketKey = spLine[1].trim(); |
|
} |
|
if (spLine[0].equals("Upgrade") && spLine[1].trim().equals("websocket")) { |
|
isWebSocket = true; |
|
} |
|
} |
|
|
|
if (isWebSocket) { |
|
socketSet.add(socket); |
|
WebSocketThread webSocketThread = new WebSocketThread(socket, webSocketKey); |
|
webSocketThread.start(); |
|
} else { |
|
HttpResponseThread httpRequest = new HttpResponseThread(socket); |
|
httpRequest.start(); |
|
} |
|
} |
|
|
|
} |
|
} |
|
|
|
class HttpResponseThread extends Thread { |
|
|
|
Socket socket; |
|
|
|
public HttpResponseThread(Socket socket) { |
|
this.socket = socket; |
|
} |
|
|
|
public void run() { |
|
PrintStream client = null; |
|
try { |
|
Path indexPath = Paths.get("index.html"); |
|
byte[] indexBytes = Files.readAllBytes(indexPath); |
|
client = new PrintStream(socket.getOutputStream()); |
|
client.println("HTTP/1.1 200 OK"); |
|
client.println("Content_type:text/html"); |
|
client.println(); |
|
client.write(indexBytes); |
|
} catch (IOException e) { |
|
e.printStackTrace(); |
|
} finally { |
|
client.flush(); |
|
client.close(); |
|
} |
|
} |
|
} |
|
|
|
class WebSocketThread extends Thread { |
|
|
|
Socket socket; |
|
String webSocketKey; |
|
|
|
WebSocketThread(Socket socket, String webSocketKey) { |
|
System.out.println("Start WebSocket Thread"); |
|
this.socket = socket; |
|
this.webSocketKey = webSocketKey; |
|
} |
|
|
|
public void run() { |
|
OutputStreamWriter os = null; |
|
try { |
|
|
|
//Create Sec-WebSocket-Accept field. |
|
webSocketKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
|
MessageDigest md = MessageDigest.getInstance("SHA-1"); |
|
byte[] cryptedKey = md.digest(webSocketKey.getBytes()); |
|
byte[] encodedKey = Base64.getEncoder().encode(cryptedKey); |
|
System.out.println(new String(encodedKey)); |
|
|
|
//Response HTTP Upgrade Response Header. |
|
StringBuffer header = new StringBuffer(); |
|
header.append("HTTP/1.1 101 Switching Protocols\r\n"); |
|
header.append("Upgrade: websocket\r\n"); |
|
header.append("Connection: Upgrade\r\n"); |
|
header.append("Sec-WebSocket-Accept: " + new String(encodedKey) + "\r\n"); |
|
header.append("\r\n"); |
|
os = new OutputStreamWriter(socket.getOutputStream()); |
|
os.write(header.toString()); |
|
System.out.println(header.toString()); |
|
os.flush(); |
|
|
|
//Parse received data. |
|
byte[] b = new byte[1024]; |
|
socket.getInputStream().read(b); |
|
ByteBuffer buf = ByteBuffer.wrap(b); |
|
byte firstByte = buf.get(); |
|
int fin = (firstByte & 0x80) >>> 7; |
|
int opcode = firstByte & 0x0F; |
|
byte secondByte = buf.get(); |
|
int mask = (secondByte & 0x80) >>> 7; |
|
int payloadLength = secondByte & 0x7F; |
|
int maskingKey = buf.getInt(); |
|
int applicationData = buf.getInt(); |
|
int unmaskedData = applicationData ^ maskingKey; |
|
byte[] unmaskedByteData = new byte[4]; |
|
unmaskedByteData[3] = (byte)(unmaskedData & 0xff); |
|
unmaskedByteData[2] = (byte)(unmaskedData >> 8 & 0xff); |
|
unmaskedByteData[1] = (byte)(unmaskedData >> 16 & 0xff); |
|
unmaskedByteData[0] = (byte)(unmaskedData >> 24 & 0xff); |
|
|
|
//Print received data. |
|
System.out.println("fin:" + fin); |
|
System.out.println("opcode:" + opcode); |
|
System.out.println("mask:" + mask); |
|
System.out.println("payloadLength:" + payloadLength); |
|
System.out.println("maskingKey:" + maskingKey); |
|
System.out.println("applicationData:" + new String(unmaskedByteData)); |
|
|
|
//Send data. |
|
ByteBuffer ob = ByteBuffer.allocate(6); |
|
ob.put((byte)0x81); |
|
ob.put((byte)0x4); |
|
ob.put("test".getBytes()); |
|
socket.getOutputStream().write(ob.array()); |
|
socket.close(); |
|
|
|
} catch (IOException | NoSuchAlgorithmException e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
} |