Secular wanderer: a programmer who focuses on technical research
Back to the previous point
There is no actual case of the theoretical basis is playing rogue, so today is mainly want to through the case here can let you deepen the understanding of the previous
In this section we will implement a point-to-point chat applet step by step
Socket implementation in Java
InetAddress
InetAddress is Java’s encapsulation of an IP address. This class is the base class that both ServerSocket and DatagramSocket depend on
InetAddress cannot be initialized with new and can only be called with the static method it provides:
// Get the local address
InetAddress localHost = InetAddress.getLocalHost();
Copy the code
Here are some methods of InetAddress:
// Host name: desktop-atg4kke
System.out.println("Host name:" + localHost.getHostName());
// IP address: 192.168.87.1
System.out.println("IP address:" + localHost.getHostAddress());
// Normal: true
System.out.println("Normal or not:" + localHost.isReachable(5000));
Copy the code
Here’s the output from my test,
The isReachable() method is used to check if the address isReachable. From there, we can do some health checks, such as:
// Get the InetAddress object by host IP or domain name
InetAddress inetAddress = InetAddress.getByName("192.168.87.139");
System.out.println("Normal or not:" + inetAddress.isReachable(5000));
Copy the code
Try to connect to the host as much as possible within 5 seconds. If not, the host is considered unavailable due to firewall and server configuration
Of course, doing a health check is a low point, and certainly not done in a production environment
PS: Network operations in production environments do not use the stuff in this section, and most of the time use Netty
ServerSocket
ServerSocket is a ServerSocket based on TCP/IP protocol implementation
Initialize the
Usually we build like this:
ServerSocket serverSocket = new ServerSocket(9999);
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(9999));
Copy the code
This completes the initialization of the server and binds port 9999
Waiting for the connection
If the client wants to establish a connection to the ServerSocket, we need to do so
for(;;) {
Socket socket = serverSocket.accpet();
// Socket[addr=/0:0:0:0:0:0:0:1,port=62445,localport=9999]
System.out.println(socket);
}
Copy the code
Accpet () listens for connections to ServerSocket, which is a blocking method that waits for connections to come in
If there is an incoming connection, we can return the value to get the current incoming Socket
communication
Data is actually transmitted in the same way as IO streams, but we can only get byte streams:
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
Copy the code
InputStream reads data and OutputStream writes data. These basic operations were introduced in IO streams and won’t be covered here
In order to improve efficiency, we can use the wrapper flow or the processing flow, which was introduced earlier
Complete small example
In fact, the ServerSocket key introduction is finished, let’s do a small example:
- When a client is connected, return to the client:
Hello World
public class _ServerSocket {
// Stores the mapping between the requesting client and the Socket
static Map<String, Socket> MAP = new HashMap<>();
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(9999));
for(; ;) { String token = UUID.randomUUID().toString().replace("-"."").toLowerCase();
Socket socket = serverSocket.accept();
/ / the correspondingMAP.put(token, socket); outHtml(socket); }}catch(IOException e) { e.printStackTrace(); }}public static void outHtml(Socket socket) {
OutputStream outputStream = null;
try {
outputStream = socket.getOutputStream();
outputStream.write(("HTTP / 1.1 200 OK \ n \ nHello World").getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null! = outputStream) {try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Copy the code
HTTP / 1.1 200 OK \ n \ nHello World \ n
This is the HTTP return type, preceded by the Response fixed format, and Hello World is the actual return, so that our ServerSocket can be accessed through the browser
Socket
The Socket belongs to the client Socket. Only after the connection is established with the server Socket can other operations be performed. The way of using the Socket is very simple
Establish a connection
Socket socket = new Socket("127.0.0.1".9999);
// Verify that the connection is successful
if (socket.isConnected()) {
System.out.println("Connection to server successful");
}
Copy the code
That’s one way to construct it, but more often than not, it’s this way
After the connection to the server is successfully established, the subsequent operation is the same as the ServerSocket communication step, so there is no more nonsense here
Let’s use a complete example to reinforce this
Example: TCP point-to-point chat
The service side
public class Server {
/** * associate the client id with the socket */
private static final Map<String, Socket> SOCKET_MAP = new HashMap<>();
/** * reverse correlation, used to get the identity */
private static final Map<Socket, String> SOCKET_TOKEN_MAP = new HashMap<>();
public static void main(String[] args) throws IOException {
/**
* 开启ServerSocket并监听9999端口
*/
ServerSocket serverSocket = new ServerSocket(9999);
for (;;) {
/** ** Waiting for the client to connect */
Socket socket = serverSocket.accept();
/** * IO reads are blocking methods, so new threads need to be started, which can be optimized to thread pool */
new Thread(() -> {
try {
saveToMap(socket);
getClientMsg(socket);
} catch(IOException e) { e.printStackTrace(); } }).start(); }}/** * bind SOCKET */
private static void saveToMap(Socket socket) throws IOException {
String token = StringUtil.uuid();
SOCKET_MAP.put(token, socket);
SOCKET_TOKEN_MAP.put(socket, token);
System.out.println("-- Client connected successfully, no. :" + token);
System.out.println("Current user :" + SOCKET_MAP.size());
/** * Because there is no login, the client is told its identity */
send(token, token, token);
}
/** * gets the message from the client and sends it to the specified client */
private static void getClientMsg(Socket socket) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while((line = reader.readLine()) ! =null) {
// After reading a line, send it from heresend(socket, line); }}/** * Send message */
private static void send(Socket socket, String line) throws IOException {
String[] s = line.split("#");
final String from = SOCKET_TOKEN_MAP.get(socket);
send(s[0], s[1], from);
}
/** * Send message *@param token
* @param msg
* @paramFrom here is displayed on the target client@throws IOException
*/
private static void send(String token, String msg, String from) throws IOException {
Socket sk = SOCKET_MAP.get(token);
if (null == sk)
return;
String s = from + ":" + msg;
System.out.println("-- Send to client :" + s );
// Character stream output
BufferedWriter writer = new BufferedWriter(newOutputStreamWriter(sk.getOutputStream())); writer.write(s); writer.newLine(); writer.flush(); }}Copy the code
The client
public class Client {
public static void main(String[] args) throws IOException {
/** * Connect to the server */
Socket socket = new Socket("127.0.0.1".9999);
/** * open a new thread to read messages, which can be optimized */
new Thread(() -> {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while(StringUtil.isNotBlank(line = reader.readLine())) { System.out.println(line); }}catch (IOException e) {
e.printStackTrace();
}
}).start();
/** * Writes a message from the console and sends it */
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) { String next = scanner.next(); send(next, socket); }}private static void send(String msg, Socket socket) throws IOException {
BufferedWriter writer = new BufferedWriter(newOutputStreamWriter(socket.getOutputStream())); writer.write(msg); writer.newLine(); writer.flush(); }}Copy the code
The code has been tested and the comments are very clear, so you can try it out and follow the format of the # message to start a peer-to-peer chat.
If you want a group chat:
- Simply save the Socket to the collection and loop through the collection
For a long time did not write Socket chat program, almost gave up
Next time use Netty to write, Netty is much more convenient than Socket
DatagramSocket
DatagramSocket is a socket used to send and receive datagram packets. It is implemented under UDP protocol. According to the official introduction of the class:
A datagram socket is a sending or receiving point for a packet delivery service. Each packet sent or received on a datagram socket is individually addressed and routed. Multiple packets sent from one machine to another may be routed in different ways and may arrive in any order
We can also understand the characteristics of UDP protocol.
DatagramPacket
This class represents a datagram packet and is used to pass and receive data in the DatagramSocket, for example:
- Receive data
byte[] buffer = new byte[1024];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
Copy the code
- To send data
DatagramPacket p = new DatagramPacket("123".getBytes(), "123".getBytes().length, InetAddress.getByName("localhost"), 9999);
Copy the code
To send data out, the DatagramPacket must specify the IP address and port number of the receiving end
Now let’s see how it works. Okay
Initialize the
DatagramSocket socket = new DatagramSocket(9999);
DatagramSocket s = new DatagramSocket(null);
s.bind(new InetSocketAddress(9999));
Copy the code
You can do initialization either way, what’s the difference
Receives the message
byte[] buffer = new byte[1024];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
socket.receive(p);
System.out.println(new String(p.getData(), 0, p.getLength()));
Copy the code
A byte[] is constructed from the receive parameter of the DatagramPacket and receive() is called so that the message is received
Receive () is a blocking method that continues execution until a message is received
Send a message
DatagramPacket p = new DatagramPacket("123".getBytes(), "123".getBytes().length, InetAddress.getByName("localhost"), 9999);
socket.send(p);
Copy the code
Construct the send packet and call the send() method to finish sending the packet
UDP does not need to connect, directly through the IP+PORT mode can send data
Example: UDP chat
public class _DatagramPacket {
public static void main(String[] args) throws IOException {
// Get the port to bind and the port to send data from the command line
DatagramSocket datagramSocket = new DatagramSocket(Integer.parseInt(args[0]));
System.out.println("Started");
new Thread(() -> {
byte[] buffer = new byte[1024];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
try {
for (;;) {
// Build the received data
datagramSocket.receive(p);
System.out.println(p.getPort() + ":" + new String(buffer, 0, p.getLength())); }}catch (IOException e) {
e.printStackTrace();
}
}).start();
Scanner scanner = new Scanner(System.in);
DatagramPacket p = new DatagramPacket(new byte[0].0.new InetSocketAddress("127.0.0.1", Integer.parseInt(args[1)));while (scanner.hasNext()) {
String next = scanner.next();
// Build send packetp.setData(next.getBytes()); datagramSocket.send(p); }}Copy the code
There are defects, the space will be newline, here you go to modify
The last word
Here, about the Socket programming aspects of the thing is finished, there is no introduction to a lot of API methods, these in the use of time to see the same.
Here is the directory where Java.net is located:
Click here to see