summary
Network programming is inseparable from data transmission, and data transmission uses IO stream in java. The most commonly used are InputStream byte input stream and OutputStream ` ` character output stream, BufferReader character input stream and BufferWirter ` ` character output stream. Here are some important concepts
-
O
S
I
seven
layer
number
according to
model
type
\color{green}{OSI seven layer data model}
OSI seven layer data model
OSI has developed a framework for data communication mark accurate \color{red} {standard} Standard, this mark accurate \color{red} {standard} The standard is a seven layer model, application layer, presentation layer, session layer, transport layer, network layer, data link layer, physical layer
Each time has its own specific role, and the data will be packaged once. Socket programming is at the transport layer. TCP and UDP protocols are transport layer protocols. -
with
step
And
different
step
\color{green} {synchronous and asynchronous}
Synchronous and asynchronous
Synchronization and asynchrony: synchronization means that when calling, the caller will not wait for the return value before processing is completed. In short, the caller actively waits for the result to return, while asynchrony is on the contrary. When calling, the result will not be obtained immediately, but the client will notify when it will be returned. -
Resistance
stopper
And
wrong
Resistance
stopper
\color{green} {blocking and non blocking}
Blocking and non blocking
Blocking and non blocking: the difference between blocking and non blocking is the state of the caller while waiting for the return value. Blocking means that the current thread will not do anything else before waiting for the result to be returned. It will only wait obediently, rather than blocking. On the contrary, it can do other things during the waiting process and wait until the asynchronous notification is returned. -
B
I
O
yes
number
according to
with
step
Resistance
stopper
type
\color{green}{BIO is data synchronization blocking}
BIO is a data synchronization blocking type
It means that when the server receives the request from the client, it will wait for some columns of the client to be operated (including reading and writing) before making requests from other clients. And will always be blocked and do nothing. Until the modified client exits, connect and read / write to another client
text
Demonstrates the sample code of the server during synchronization
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try { //1. Create ServerSocket locally and bind port 9999 ServerSocket server = new ServerSocket(9999); //2 accept client connection (this method is blocking. If there is no connection, it will wait all the time) Socket socket = server.accept(); //3 get the byte input stream of the client InputStream inputStream = socket.getInputStream(); //Input byte character into stream BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String msg = ""; //4 accept the information of the client by line (this method is blocking and will always read the information of the client) while((msg = bufferedReader.readLine())!=null){ System.out.println("Information received from client"+msg); } } catch (IOException e) { e.printStackTrace(); } } }
Demonstrates the code of the synchronization client
package com.demo.bio.one; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { //Create client socket Socket socket = new Socket(); try { //Connect to local port 9999 socket.connect(new InetSocketAddress(9999),1000); //Get byte output stream OutputStream outputStream = socket.getOutputStream(); //Transfer byte output to print stream PrintStream printStream =new PrintStream(outputStream); //Get keyboard input Scanner scanner = new Scanner(System.in); while(scanner.hasNext()){ String next = scanner.next(); //Output data printStream.println(next); } } catch (IOException e) { e.printStackTrace(); } } }
Start the server first and then the client. At this time, the customer simply enters text in the console, and then the server can receive the information and print it on the console of the server. If there is a server with socket = server, it will be unable to connect at one time When accepting (), after accepting a client connection, the code at this time will not be executed. If it is necessary to execute, we will use the server code at this time
public class Server { public static void main(String[] args) { try { //1. Create ServerSocket locally and bind port 9999 ServerSocket server = new ServerSocket(9999); //2 accept client connection (this method is blocking. If there is no connection, it will wait all the time) while(true){ Socket socket = server.accept(); //3 get the byte input stream of the client InputStream inputStream = socket.getInputStream(); //Input byte character into stream BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String msg = ""; //4 accept the information of the client by line (this method is blocking and will always read the information of the client) while((msg = bufferedReader.readLine())!=null){ System.out.println("Information received from client"+msg); } } } catch (IOException e) { e.printStackTrace(); } } }
At the same time, when two clients connect to the server, they will find that the data of the second client cannot reach the server anyway. This is because BIO is blocked. When the main thread processes the first client, as long as the current client is online, it cannot process other clients. At this time, if the server is required to have multiple clients at the same time, you need to use Line Cheng \color{red} {thread} Threads handle a client separately.
Multi client request server code modification
package com.demo.bio.two; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try{ ServerSocket serverSocket = new ServerSocket(9999); while (true){ Socket socket = serverSocket.accept(); //When a new client arrives, start a new thread to process it. The main thread then continues to accept new clients new Thread( new HandlerSocket(socket)).start(); } }catch (Exception e){ e.printStackTrace(); } } }
Client processing request HandlerSocket thread
package com.demo.bio.two; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class HandlerSocket implements Runnable { private Socket socket; public HandlerSocket(Socket socket) { this.socket = socket; } public void run() { try(InputStream inputStream = socket.getInputStream()){ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String msg =null; while((msg=bufferedReader.readLine())!=null){ System.out.println("Client message received"+msg); } }catch (Exception e){ } } }
The original client code remains unchanged. At this time, data from different clients can be accepted and input in different client consoles
Then a problem will arise. With the increasing number of clients, the number of threads on the server increases with the increasing number of clients. If the JVM cannot create stack space for new threads when the number of threads reaches a certain value, an error of ` ` ` ` outofmemoroy ` ` ` will occur. The system crashed. This is what we don't want to see. At this time, we need to control the number of threads. If we control the number of threads, since threads are used to handle the connection of the client, we will use thread related technology and thread pool technology to transform the code of the server
Thread pool transformation server code
package com.demo.bio.three; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try (ServerSocket server = new ServerSocket(9999)) { //Create a thread pool HandlerSocketThreadPools pools = new HandlerSocketThreadPools(3,10); while(true){ Socket socket = server.accept(); pools.execute(new HandlerSocket(socket)); } }catch (Exception e){ e.printStackTrace(); } } }
The code of HandlerSocketThreadPools is as follows
package com.demo.bio.three; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class HandlerSocketThreadPools { private ThreadPoolExecutor threadPoolExecutor; public HandlerSocketThreadPools(int maxSize,int size){ threadPoolExecutor= new ThreadPoolExecutor(3,maxSize,120, TimeUnit.MICROSECONDS, new ArrayBlockingQueue(size)); } public void execute(Runnable runnable){ threadPoolExecutor.execute(runnable); } }
At this time, the original code can be executed in a certain number of thread pools, but the number of core threads is set to 3, which means that only three clients can connect at most. When the fourth client connects, it can only enter the blocking queue and wait. At this time, NIO can only be used to solve it.
Through this article, we summarize.
BIO is an IO model of synchronous blocking. A client corresponds to this thread. If there are too many clients, it is easy to crash the program.
Now use BIO to develop a chat room
Chat server code
package com.demo.bio.chatroom; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.CopyOnWriteArrayList; public class Server { //Create a thread safe collection and save all online clients public static CopyOnWriteArrayList<Socket> onLine = new CopyOnWriteArrayList(); public static void main(String[] args) { try{ ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress(9999)); while(true){ Socket socket = server.accept(); //Save socket to online list onLine.add(socket); new Thread(new HandlerSocket(socket)).start(); } }catch (Exception e){ e.printStackTrace(); } } }
The server handles the client thread separately
package com.demo.bio.chatroom; import java.io.*; import java.net.Socket; import java.util.concurrent.CopyOnWriteArrayList; public class HandlerSocket implements Runnable{ //Currently connected clients private Socket socket; private int port; public HandlerSocket(Socket socket){ this.socket = socket; this.port = socket.getPort(); } @Override public void run() { System.out.println("client"+port+"Join the chat room"); try{ //Gets the character input stream of the current client BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String msg; //Send new client online messages to all online clients sendLoginToOnline(socket); //Read the data sent by the client while((msg=reader.readLine())!=null){ System.out.println("client:"+port+"Messages sent"+msg); sendMsgToOnline(socket,msg); } reader.close(); }catch (Exception e){ e.printStackTrace(); Server.onLine.remove(socket); } } //Send online messages to all clients private void sendLoginToOnline(Socket socket) { CopyOnWriteArrayList<Socket> onLine = Server.onLine; for (Socket data : onLine) { if(socket!=data){ try{ PrintStream printStream = new PrintStream( data.getOutputStream()); printStream.println(socket.getPort()+"Join the chat room"); printStream.flush(); }catch (Exception e){ System.out.println("Error sending data"); onLine.remove(data); } } } } //Want to forward messages to all online clients private void sendMsgToOnline(Socket socket,String msg) { CopyOnWriteArrayList<Socket> onLine = Server.onLine; for (Socket data : onLine) { if(socket!=data){ try{ PrintStream printStream = new PrintStream( data.getOutputStream()); printStream.println(socket.getPort()+":"+msg); printStream.flush(); }catch (Exception e){ System.out.println("Error sending data"); onLine.remove(data); } } } } }
Client code
package com.demo.bio.chatroom; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { Socket socket=null; PrintStream printStream = null; try{ socket = new Socket(); socket.connect(new InetSocketAddress(9999)); //Start a thread to read the messages forwarded by the server to the client new Thread(new HandlerRead(socket)).start(); OutputStream outputStream = socket.getOutputStream(); printStream = new PrintStream(outputStream); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ String msg = scanner.nextLine(); printStream.println(msg); printStream.flush(); } }catch (Exception e){ e.printStackTrace(); try { socket.close(); printStream.close(); } catch (IOException e1) { e1.printStackTrace(); } } } }
The client independently accepts the thread that the server forwards the message
package com.demo.bio.chatroom; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; public class HandlerRead implements Runnable { private Socket socket; public HandlerRead(Socket socket){ this.socket = socket; } @Override public void run() { try{ InputStream inputStream = socket.getInputStream(); BufferedReader read = new BufferedReader(new InputStreamReader(inputStream)); String msg; while((msg=read.readLine())!=null){ System.out.println(msg); } }catch (Exception e){ e.printStackTrace(); } } }