socket programming is provided in Java to build client and server side
TCP
Steps to build the server side:
(1) bind: Bind port number
(2) listen: listen for client connection requests
(3) accept: an instance of returning a connection to the client
(4) read/write: read/write operations, i.e., interaction with the client
(5) close: Close resources
ServiceSocket keyword is provided in Java to build the server. In Java, listen and accept are merged into an accept operation. The following five steps are illustrated by code
public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(); //Bind: bind ip and port serverSocket.bind(new InetSocketAddress(6666)); //listen listens and accpet returns the socket instance Socket accept = serverSocket.accept(); //Get input and output streams through socket BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream())); PrintStream printStream = new PrintStream(accept.getOutputStream()); //Read the data from the client and print it String s = bufferedReader.readLine(); System.out.println("Receive client data:"+s); //Output data to client printStream.println("Lala Server Returns Message:"+s); //Close the stream and socket printStream.close(); bufferedReader.close(); serverSocket.close(); } }
We can also bind the port number while creating the ServerSocket, that is to say
ServerSocket serverSocket = new ServerSocket(6666);
The steps to build the client are as follows:
(1) connect: connect to the server through IP address and port number
(2) read/write: read/write operations, i.e., information exchange with the server
(3) close: Close resources
As you can see, the operation of the client side is much simpler than that of the server side.
Because what we write is under TCP protocol, we should start the server first. After the server starts, the client will wait for the connection in accept, that is to say, the code will block here, and the client can connect at this time.
The following steps are illustrated in code:
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(); //Connecting to the server through ip and port number socket.connect(new InetSocketAddress("127.0.0.1",6666)); //Define read-write streams BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream printStream = new PrintStream(socket.getOutputStream()); //Send data to the server printStream.println("Haha, I'm a client."); //Receiving data recovered by server String s = bufferedReader.readLine(); System.out.println(s); //close resource printStream.close(); bufferedReader.close(); socket.close(); } }
Similarly, we can connect to the server side while creating the Socket.
Socket socket = new Socket("127.0.0.1",6666);
Both demo s use buffers and print streams for read and write operations. Here's a look at the results
Let's describe this process by drawing a picture.
It's also clear from this picture when the three handshakes and the four waves occur, respectively.
Next, consider a requirement. What if there are multiple clients and servers communicating information?
As mentioned earlier, the accpet operation on the server side is an operation waiting for the client to connect, so writing a loop, one accept in each loop body can not solve the problem of connecting multiple clients to the server side, but it should be noted that accpet is a blocking operation, so it requires multiple threads. Yes, here's why:
The first thing you need to understand is that you only need to modify the server side, so this piece is for the server side.
If there is only one thread, then the thread will be used to read and write through the accpet connection, which will also block when reading and writing. If the next accpet is blocked when reading and writing, then the next accpet will not connect properly, and the thread will stop until the first connection is finished. It is obvious that this process is a serial process, which can not achieve the desired effect. This requires multi-threading. The main thread is only used to maintain the connection (accpet), and then the sub-threads are responsible for reading and writing interaction with the client, so that the sub-threads will not affect the main thread when the read and write blockage occurs.
Let's first look at the code for multiple clients and one server:
The following code only shows the server side, the client side and the top remain unchanged
public class MutileServer { public static void main(String[] args) { //Create a thread pool with three fixed number of threads ExecutorService executorService = Executors.newFixedThreadPool(3); try { ServerSocket sockets = new ServerSocket(6666); System.out.println("The server has started and is waiting for a connection"); while(true) { Socket accept = sockets.accept(); System.out.println("Client:"+accept.getInetAddress().getHostAddress()); executorService.execute(new MyThread(accept)); } } catch (IOException e) { e.printStackTrace(); } } } class MyThread implements Runnable { private Socket socket; private BufferedReader bufferedReader; private PrintStream printStream; public MyThread(Socket socket) { this.socket = socket; try { bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); printStream = new PrintStream(new BufferedOutputStream(socket.getOutputStream())); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { String s = bufferedReader.readLine(); System.out.println("Client sends message "+s); printStream.println("echo"+s); printStream.flush(); bufferedReader.close(); printStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
Several points need to be clarified:
(1) In this section, I use thread pool, which is convenient for unified management and efficient without creating threads many times. Multiple threads can also be created individually, and through loops.
(2) I wrote a MyThread class to deal with the information exchange between the reader and the client, that is, the sub-thread completes the read and write operation, and the main thread only needs to care about the connection with the server.
(3) When resources are exhausted, they must be shut down and exceptions should not be thrown as far as possible, so that they can be handled in the current method.
shortcoming
There are drawbacks in using BIO to implement TCP client and server. BIO is a synchronous blocking model, which was used until JDK 1.4. But to think of such a problem, every time a client comes to connect to the server, there must be a thread corresponding to it. So when there are many clients, the server thread will be. Very many, and thread context switching will become a very large consumption, this is the shortcoming of BIO, if we want to improve this shortcoming, we need to introduce NIO.
UDP
Unlike TCP, UDP is not a reliable connection, that is to say, it guarantees the correct delivery of data, and UDP will spread data in the form of datagrams. For example, listen to the radio, when the program arrives, it must turn on the radio in advance, so as not to miss it. UDP is the same. When sending data on the server side, the client needs to wait in advance so as not to miss the data.
UDP requires two classes to complete client and server: DatagramPacket and DatagramSocket
DatagramSocket is a socket for establishing connections, which can be understood as a wharf for transporting goods.
Datagram Packet is a data package, that is to say, the data is packaged into a data package in the process of transmission. If Datagram Socket is a wharf, then Datagram Packet is a box for loading goods.
Look at the code:
Server:
public class Server { public static void main(String[] args) { //Data to be sent String data = "The data was sent..."; byte[] bytes = data.getBytes(); try { //Packed in Packet Form DatagramPacket packet = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"), 8888); //Initialize DatagramSocket DatagramSocket socket = new DatagramSocket(); //send data socket.send(packet); } catch (IOException e) { e.printStackTrace(); } } }
Client:
public class Client { public static void main(String[] args) { try { //Select the port number to listen on DatagramSocket socket = new DatagramSocket(8888); //Initialization of received data packets byte[] bytes = new byte[1024]; DatagramPacket packet = new DatagramPacket(bytes, bytes.length); //receive data socket.receive(packet); //Parsing data package String s = new String(packet.getData(), 0,packet.getLength()); //Print the received data System.out.println(s); } catch (IOException e) { e.printStackTrace(); } } }
Start the client first, then the server