[Update]: Easy implementation using API
Described what was practiced about socket communication in order to create a multi-person simultaneous communication on the net. I want multiple real-time communications such as chat and online games.
I wanted to build a program in "Java" that can be executed in a "web browser", but it doesn't appear much even if I google it, so I will describe it. (Because I didn't know the word network programming due to lack of knowledge, there may be a problem with how to google ...)
Start from super basics such as reading and writing data.
A type of communication method. Real-time two-way communication is possible between the server and client instead of unidirectional communication like HTTP get access and post access. ⇒ You need two programs, a server program and a client program.
Please google for details.
Server program: Java Client program: JavaScript
The client-side program is written in JavaScript. It's almost perfect here. No server-side programs required.
<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>WebSocket communication</title>
		<script type="text/javascript">
		
			var wSck= new WebSocket("echo.websocket.org");//WebSocket object generation
			
			wSck.onopen = function() {//Action when connecting socket
				document.getElementById('show').innerHTML += "Connected." + "<br/>";
			};
			
			wSck.onmessage = function(e) {//Action when receiving a message
				document.getElementById('show').innerHTML += e.data + "<br/>";
			};
			
			var sendMsg = function(val) {//Actions when sending a message
				var line = document.getElementById('msg');//Get input
				wSck.send(line.value);//Send to socket
				line.value = "";//Clear the contents
			};
		</script>
	</head>
	<body>
		<div
			style="width: 500px; height: 200px; overflow-y: auto; border: 1px solid #333;"
			id="show"></div>
		<input type="text" size="80" id="msg" name="msg" />
		<input type="button" value="Send" onclick="sendMsg();" />
	</body>
</html>
var variable = new WebSocket ("ws: // IP address: port number ");This time, "echo.websocket.org" is used for the address. ⇒ It will return what was sent from the client as it is. Convenient because socket communication is possible without creating a server program.
Describe the action when connecting a socket
socket.onopen = function () {・ ・ ・};
If the socket connection is successful, this function is executed first.
socket.onmessage = function () {・ ・ ・};
This function is executed when data is sent from the server.Four. Describe the content to send a message
socket.send (...);

The sent content is sent back from the fictitious server as it is and displayed.
Instead of a fictitious server, actually create a server and reply as it is sent from the client. Write the server-side program in Java.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Base64.Encoder;
class SocketFree {
	private static ServerSocket sSck;//Socket for server
	private static Socket sck;//Reception socket
	private static InputStream is;//Input stream
	private static InputStreamReader isr;//Read the input stream
	private static BufferedReader in;//Reading text by buffering
	private static OutputStream os;//Output stream
	
	public static void main(String[] args) {
		try {
			sSck=new ServerSocket(60000);//Create an instance of a server socket(Port is 60000)
			System.out.println("I connected to the server!");
			sck=sSck.accept();//Waiting for connection. Substitute in the socket when it comes.
			System.out.println( "Participants have connected!");
			
			//Create the required I / O stream
			is=sck.getInputStream();//Read the input from the socket as a string of bytes
			isr=new InputStreamReader(is);//Convert the read byte string and read the character string
			in=new BufferedReader(isr);//Buffering strings(collect)Read
			os=sck.getOutputStream();//Write a string of bytes to the socket
			
			//Return connection permission to client(handshake)
			handShake(in , os);
			
			//Return the input to the socket as it is * Up to 125 characters(Header frame changes for 126 characters or more)
			echo(is , os);
			
		} catch (Exception e) {
			System.err.println("An error has occurred: " + e);
		}
	}
	
	//Method that returns connection permission to client(handshake)
	public static void handShake(BufferedReader in , OutputStream os){
		String header = "";//Variable declaration in header
		String key = "";//Variable declaration of websocket key
		try {
			while (!(header = in.readLine()).equals("")) {//Substitute the header obtained from the input stream into the string and loop all lines.
				System.out.println(header);//Show header contents on console line by line
				String[] spLine = header.split(":");//One line ":And put it in the array
				if (spLine[0].equals("Sec-WebSocket-Key")) {//Sec-WebSocket-Key line
					key = spLine[1].trim();//Trim blanks and get websocket key
				}
			}
			key +="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";//Add a mysterious string to the key
			byte[] keyUtf8=key.getBytes("UTF-8");//Key to "UTF-Convert to a byte array of "8"
			MessageDigest md = MessageDigest.getInstance("SHA-1");//Returns an object that implements the specified digest algorithm
			byte[] keySha1=md.digest(keyUtf8);//Key(UTF-8)Do a digest calculation using
			Encoder encoder = Base64.getEncoder();//Base64 encoder available
			byte[] keyBase64 = encoder.encode(keySha1);//Key(SHA-1)Is Base64 encoded
			String keyNext = new String(keyBase64);//Key(Base64)To String
			byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n"
		            + "Connection: Upgrade\r\n"
		            + "Upgrade: websocket\r\n"
		            + "Sec-WebSocket-Accept: "
		            + keyNext
		            + "\r\n\r\n")
		            .getBytes("UTF-8");//Create HTTP response
			os.write(response);//Send HTTP response
		} catch (IOException e) {
			System.err.println("An error has occurred: " + e);
		} catch (NoSuchAlgorithmException e) {
			System.err.println("An error has occurred: " + e);
		}
	}
	//A method that monitors the input to the socket in an infinite loop
	public static void echo(InputStream is , OutputStream os) {
		try{
			while(true) {
				byte[] buff = new byte[1024];//An array that contains the binary data sent by the client
				int lineData =is.read(buff);//Read data
				for (int i = 0; i < lineData - 6; i++) {
					buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]);//3 after the 7th byte-Decode using the 6th byte key
				}
				String line = new String(buff, 6, lineData - 6, "UTF-8");//Convert the decoded data to a character string
				byte[] sendHead = new byte[2];//Prepare header to send back
				sendHead[0] = buff[0];//The first byte is the same
				sendHead[1] = (byte) line.getBytes("UTF-8").length;//The second byte is the length of the string
				os.write(sendHead);//Header output
				os.write(line.getBytes("UTF-8"));//Converts the character string to binary data after the 3rd byte and outputs it
				
				if (line.equals("bye")) break;//If "bye" is sent, reception ends
			}
		} catch (Exception e)  {
			System.err.println("An error has occurred: " + e);
		}
	}
}
Create an instance of the server socket.
ServerSocket variable = new ServerSocket (port number)
Four. Create an I / O stream for the connected client.
Five. Returns a response to a connection request from a client. (handShake method)
Since the required information is described in the request header, edit it and send it back. For details of the edited contents, refer to the code comment and reference site. In short, you need to send back the "WebSocket key" in the request header. ⇒ ** "Handshake" **
The data sent by the client is encoded as binary data. Decode on the server side, re-encode and send to the client. For details of the decoded contents, refer to the code comment and reference site.

var variable = new WebSocket ("ws: //127.0.0.1:60000 ");I got the same result as when I used a fictitious server (echo.websocket.org). This time it's just echoing, but it's also possible to play around with the data on the server side and reply.
Edit the server program to allow connections from multiple clients. In addition, real-time communication will be provided between each client.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Base64.Encoder;
class SocketFree {
	private static ServerSocket sSck;//Socket for server
	private static Socket[] sck;//Reception socket
	private static InputStream[] is;//Input stream
	private static InputStreamReader[] isr;//Read the input stream
	private static BufferedReader[] in;//Reading text by buffering
	private static OutputStream[] os;//Output stream
	private static ClientThread user[];//Instance of each client
	private static int member;//Number of connected members
	
	public static void main(String[] args) {
		int n=0;
		int maxUser=100;
		//Prepare an array of each field
		sck=new Socket[maxUser];
		is=new InputStream[maxUser];
		isr=new InputStreamReader[maxUser];
		in=new BufferedReader[maxUser];
		os=new OutputStream[maxUser];
		user=new ClientThread[maxUser];
				
		try {
				sSck=new ServerSocket(60000);//Create an instance of a server socket(Port is 60000)
				System.out.println("I connected to the server!");
				while(true) {
					sck[n]=sSck.accept();//Waiting for connection. Substitute in the socket when it comes.
					System.out.println( (n+1)+"The second participant has connected!");
					
					//Create the required I / O stream
					is[n]=sck[n].getInputStream();//Read the input from the socket as a string of bytes
					isr[n]=new InputStreamReader(is[n]);//Convert the read byte string and read the character string
					in[n]=new BufferedReader(isr[n]);//Buffering strings(collect)Read
					os[n]=sck[n].getOutputStream();//Write a string of bytes to the socket
					
					//Return connection permission to client(handshake)
					handShake(in[n] , os[n]);
					
					//Create a thread for each client
					user[n] = new ClientThread(n , sck[n] , is[n] , isr[n] , in[n] , os[n]);
					user[n].start();
					
					member=n+1;//Update the number of connections
					n++;//To the next connecter
				}
			} catch (Exception e) {
				System.err.println("An error has occurred: " + e);
		}
	}
	
	//Method that returns connection permission to client(handshake)
	public static void handShake(BufferedReader in , OutputStream os){
		String header = "";//Variable declaration in header
		String key = "";//Variable declaration of websocket key
		try {
			while (!(header = in.readLine()).equals("")) {//Substitute the header obtained from the input stream into the string and loop all lines.
				System.out.println(header);//Show header contents on console line by line
				String[] spLine = header.split(":");//One line ":And put it in the array
				if (spLine[0].equals("Sec-WebSocket-Key")) {//Sec-WebSocket-Key line
					key = spLine[1].trim();//Trim blanks and get websocket key
				}
			}
			key +="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";//Add a mysterious string to the key
			byte[] keyUtf8=key.getBytes("UTF-8");//Key to "UTF-Convert to a byte array of "8"
			MessageDigest md = MessageDigest.getInstance("SHA-1");//Returns an object that implements the specified digest algorithm
			byte[] keySha1=md.digest(keyUtf8);//Key(UTF-8)Do a digest calculation using
			Encoder encoder = Base64.getEncoder();//Base64 encoder available
			byte[] keyBase64 = encoder.encode(keySha1);//Key(SHA-1)Is Base64 encoded
			String keyNext = new String(keyBase64);//Key(Base64)To String
			byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n"
		            + "Connection: Upgrade\r\n"
		            + "Upgrade: websocket\r\n"
		            + "Sec-WebSocket-Accept: "
		            + keyNext
		            + "\r\n\r\n")
		            .getBytes("UTF-8");//Create HTTP response
			os.write(response);//Send HTTP response
		} catch (IOException e) {
			System.err.println("An error has occurred: " + e);
		} catch (NoSuchAlgorithmException e) {
			System.err.println("An error has occurred: " + e);
		}
	}
	
	//A method that sends data from each client to all clients
	public static void sendAll(int number , byte[] sendHead , String line){
		try {
			for (int i = 0; i <member ; i++) {
				os[i].write(sendHead);//Header output
				os[i].write(line.getBytes("UTF-8"));//Converts the character string to binary data after the 3rd byte and outputs it
				System.out.println((i+1)+"Second"+(number+1)+"I sent the second message!" );
			}
		} catch (IOException e) {
			System.err.println("An error has occurred: " + e);
		}
	}
}
class ClientThread extends Thread{
	//Fields for each client
	private int myNumber;
	private Socket mySck;
	private InputStream myIs;
	private InputStreamReader myIsr;
	private BufferedReader myIn;
	private OutputStream myOs;
	
	//Assign each value to the field of the instance in the constructor
	public ClientThread(int n , Socket sck , InputStream is , InputStreamReader isr , BufferedReader in , OutputStream os) {
		myNumber=n;
		mySck=sck;
		myIs=is;
		myIsr=isr;
		myIn=in;
		myOs=os;
	}
	
	//Thread class main
	public void run() {
		try {
			echo(myIs , myOs , myNumber);
		} catch (Exception e) {
			System.err.println("An error has occurred: " + e);
		}
	}
	
	//Monitor the input to the socket in an infinite loop * Up to 125 characters(Header frame changes for 126 characters or more)
	public void echo(InputStream is , OutputStream os , int myNumber) {
		try{
			while(true) {
				byte[] buff = new byte[1024];//An array that contains the binary data sent by the client
				int lineData =is.read(buff);//Read data
				for (int i = 0; i < lineData - 6; i++) {
					buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]);//3 after the 7th byte-Decode using the 6th byte key
				}
				String line = new String(buff, 6, lineData - 6, "UTF-8");//Convert the decoded data to a character string
				byte[] sendHead = new byte[2];//Prepare header to send back
				sendHead[0] = buff[0];//The first byte is the same
				sendHead[1] = (byte) line.getBytes("UTF-8").length;//The second byte is the length of the string
				
				SocketFree.sendAll(myNumber , sendHead , line);//Send to each client is executed by sedAll method of original class
				
				if (line.equals("bye")) break;//If "bye" is sent, reception ends
			}
		} catch (Exception e)  {
			System.err.println("An error has occurred: " + e);
		}
	}
}
Make each field an array to accommodate multiple clients. Initialize the array with the main function and edit the variables so far.
Thread class: Can be branched from the main function and processed at the same time. A mysterious specification where run () is executed by .start () ;.
Four. Moved the echo function to the ClientThread class. Data reception ⇒ Decoding ⇒ Data transmission Since data transmission is executed in the class to which the main function belongs, a new sendAll method is created.
Five. Other minor corrections such as method types and variable names.

When sent from one client, the same text is displayed in all browsers. The display result is the same regardless of which client sends the text.
-Error handling when the browser is closed If you send "bye", you can exit the monitoring loop and exit without error, but if you close the browser during monitoring, an error will occur and the server will stop.
-Addition of close method Originally, when terminating socket communication, the close method is used to disconnect, but this time it is not used.
・ Enhancement of decoding process Since the decoding process has been spoiled, communication of 125 characters or less is possible. Since the frame of the web socket changes when it becomes 126 characters or more, it is necessary to classify the cases.
・ Strengthening security Since no measures have been taken this time and the security is loose, it is necessary to think about the method of sending and receiving.
・ Port release If the port specified in the program is already in use, an error will occur when starting the server.
> netstat -ano at the command prompt
·handshake An agreement must be reached between the client and server before socket communication can take place. If there is a connection request from the client to the server, it needs to respond to it. The content of the response is described in detail on the reference page.
・ Decoding of received data There is a frame format for the data in the web socket, and binary data is transmitted along that frame. To decode the data, it is necessary to understand the frame structure and convert it byte by byte. Details of the frame format and decoding method are described in detail on the reference page.
It's more complicated than I expected.
Even if I google it, it doesn't come out easily, is it a minor method? I often see server programs written in "Node.js". The dot installation video was created with Node.js, and complicated processing such as response and decoding was not performed. Maybe it's faster to study Node.js.
Even in Java, I saw an article that allows communication without decoding by using annotations, but this time it passed. It might have been better not to pass.
I should have been studying programming, but before I knew it, I was studying protocols ... I didn't think it was a place for beginners to poke their necks, but it was good because it was a learning experience.
If you make a mistake, Sman. If you notice it, fix it. There are quite a lot of things to improve, so I'll update if possible.
-Site that I managed to manage -Site that is easy to understand for multiple clients -Detailed site 1 about response headers and decoding -Detailed site 2 about response headers and decoding -Sites that are familiar with websockets in general -WebSockets in general + Sites using annotations -Commentary: A site that creates a few details, but quite fine details -Create client program with JavaScript
Recommended Posts