Skip to content

Instantly share code, notes, and snippets.

@hide1202
Last active August 24, 2023 12:43
Show Gist options
  • Save hide1202/3ae71fd794ac76aa72c456f632e12c5f to your computer and use it in GitHub Desktop.
Save hide1202/3ae71fd794ac76aa72c456f632e12c5f to your computer and use it in GitHub Desktop.
Simple Echo Websocket using Java NIO
package org.viewpoint;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Set;
// 1st References to https://developer.mozilla.org/ko/docs/WebSockets/Writing_WebSocket_servers#Step_4_Closing_the_connection
// 2nd References to https://www.websocket.org/aboutwebsocket.html
// 3rd References to https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_server
public class Server {
private static final String MAGIC_NUMBER = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private static String encodeSha1AndBase64(String secWebSocketKey) {
String string = secWebSocketKey + MAGIC_NUMBER;
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-1");
byte[] sha1Result = digest.digest(string.getBytes());
return Base64.getEncoder().encodeToString(sha1Result);
} catch (NoSuchAlgorithmException e) {
}
return null;
}
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(8000));
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int select = selector.select(1);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey key : selectionKeys) {
if (key.isAcceptable()) {
SocketChannel channel = serverSocketChannel.accept();
if (channel != null) {
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
}
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(2048);
int count = socketChannel.read(buffer);
buffer.flip();
//String byteString = toByteString(buffer);
String string = new String(buffer.array());
if (string.startsWith("GET / HTTP/1.1")) {
int swkIndex = string.indexOf("Sec-WebSocket-Key:");
int endIndex = string.indexOf("\r\n", swkIndex);
String swk = string.substring(swkIndex + 19, endIndex);
String s = encodeSha1AndBase64(swk);
String response = "HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: " + s + "\r\n\r\n";
socketChannel.write(ByteBuffer.wrap(response.getBytes()));
} else {
if (buffer.limit() <= 0)
continue;
byte firstByte = buffer.get();
byte secondByte = buffer.get();
byte fin = (byte) ((firstByte & 128) >> 7);
byte rsv1 = (byte) ((firstByte & 64) >> 6);
byte rsv2 = (byte) ((firstByte & 32) >> 5);
byte rsv3 = (byte) ((firstByte & 16) >> 4);
byte opCode = (byte) ((firstByte & 8) | (firstByte & 4) | (firstByte & 2) | (firstByte & 1));
byte mask = (byte) ((secondByte & 128) >> 7);
long length = (long) ((secondByte & 64) | (secondByte & 32) | (secondByte & 16) | (secondByte & 8) | (secondByte & 4) | (secondByte & 2) | (secondByte & 1));
if (length == 126) {
length = buffer.getShort();
} else if (length == 127) {
length = buffer.getLong();
}
byte[] dataBytes = new byte[(int) length];
byte[] maskValue = null;
if (mask == 1) {
maskValue = new byte[4];
buffer.get(maskValue);
for (int i = 0; i < length; i++) {
byte data = buffer.get();
dataBytes[i] = (byte) (data ^ maskValue[i % 4]);
}
}
System.out.println(new String(dataBytes));
}
}
}
}
}
private static String toByteString(ByteBuffer buffer) {
StringBuilder builder = new StringBuilder();
int count = buffer.remaining();
for (int i = 0; i < count; i++) {
if (i > 0)
builder.append(',');
builder.append(buffer.get());
}
return builder.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment