Last article Understanding UDP and TCP is enough. We have a preliminary understanding of network programming, UDP protocol and TCP protocol related content. This connection-oriented TCP protocol must establish a connection with the other party before formal communication, which is modeled according to the telephone system. For example, when you call someone, you have to wait until the line is connected and the other person picks up the microphone to talk to each other. This article explains TCP programming in detail.
Articles Catalogue
How do computers transmit data?
If there are two computers, the data transmission between them is through the seven-layer protocol, the output (computer A) output data through the seven-layer protocol, and the data transmission to the input (computer B) through the seven-layer protocol. As shown in the following figure:
But from the application layer to the transport layer, how does the computer go to which protocol to use, TCP or UDP? In fact, there is a socket between the two layers, through which you can know which protocol to use.
In Java language, TCP network programming provides good support. In actual implementation, java.net.Socket class represents client connection and java.net.ServerSocket class represents server connection. In network programming, the details of the underlying network communication have been highly encapsulated, so when programmers actually program, they only need to specify the IP address and port number to establish the connection.
2. One-way communication
Step 1: Connect
In Java API, the object of java.net.Socket class represents the network connection, so the client network connection is established, that is, the object of Socket type is created. This object represents the network connection. The example is as follows:
Socket socketA = new Socket("192.168.1.103",8888); Socket socketB = new Socket("www.baidu.com",1000);
socketA represents port 8888 connected to a computer with an IP address of 192.168.1.103.
socketB means port 1000 connected to a computer whose domain name is www.baidu.com.
Step 2: Network Data Exchange
In Java language, the data transmission function is implemented by Java IO, that is to say, only the input stream and output stream can be obtained from the connection, and then the data sent will be written to the output stream of the connection object and read from the input stream after the transmission is completed. The sample code is as follows:
OutputStream os = socket1.getOutputStream(); //Obtain the output stream InputStream is = socket1.getInputStream(); //Get the input stream
Step 3: Close the network, flow
socket1.close();
Example: Client sends information to server
Client:
package com.Stream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class ClientTest//Client { public static void main(String[] args) throws UnknownHostException, IOException { //First step Socket client = new Socket("localhost",9999); //Step 2 OutputStream os = client.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("Hello"); //Step 3 client.close(); os.close(); dos.close(); } }
Server side:
package com.Stream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest//Server { public static void main(String[] args) throws IOException { System.out.println("Server Start————————"); //Create sockets, specify port numbers ServerSocket ss = new ServerSocket(9999); //accept the socket of the server through the method of ServerSocket Socket server = ss.accept(); InputStream in = server.getInputStream(); DataInputStream dis = new DataInputStream(in); String str = dis.readUTF(); System.out.println("The client said: "+ str); //close resource ss.close(); server.close(); in.close(); dis.close(); } }
Note that:
- Run the server first, then the client
- If the Socket client = new Socket("localhost",9999) is created on the client side; when an exception occurs at runtime, the IP address can be changed to localhost.
3. Two-way communication
The above example is just that the client says hello to the server, so it is called one-way communication. In the next example, when the client receives the greeting from the server, it responds to it, which is called two-way communication.
Client:
package com.Stream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class ClientTest//Client { public static void main(String[] args) throws UnknownHostException, IOException { //First step Socket client = new Socket("localhost",9999); //Step 2 OutputStream os = client.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("Hello"); //Client accepts server-side data (new part) client.shutdownOutput(); InputStream is = client.getInputStream(); DataInputStream dis = new DataInputStream(is); String str=dis.readUTF(); System.out.println("The server said to me" + str ); //Step 3 client.close(); os.close(); dos.close(); } }
Server side:
package com.Stream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest//Server { public static void main(String[] args) throws IOException { System.out.println("Server Start————————"); //Create sockets, specify port numbers ServerSocket ss = new ServerSocket(9999); //accept the socket of the server through the method of ServerSocket Socket server = ss.accept(); InputStream in = server.getInputStream(); DataInputStream dis = new DataInputStream(in); String str = dis.readUTF(); System.out.println("The client said: "+ str); //Response Client (New Part) server.shutdownInput(); OutputStream ops = server.getOutputStream(); DataOutputStream dos = new DataOutputStream(ops); dos.writeUTF("I'm fine!"); //close resource ss.close(); server.close(); in.close(); dis.close(); } }
4. Simulated landing
Above, we learned how to communicate in two directions. Next, we use two-way communication to simulate the login account.
Basic idea: When landing an account, the password we entered is sent to the server in the form of stream. After receiving our request, the server searches for the existence of such a password pair in its own database. If so, the login succeeds and if not, the login fails.
Question: We need to fill in the account number and password. What form should we use to store the account password entered by the user?
Solution: We can encapsulate the account password as an object and send it to the server through serialization to text. If you don't understand serialization, please refer to the article Serialization and Deserialization of Java Objects
package com.Stream; import java.io.Serializable; public class Account implements Serializable { private String username; private String password; public Account(String username, String password) { super(); this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
Client:
package com.Stream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class ClientTest { public static void main(String[] args) throws UnknownHostException, IOException { Socket client = new Socket("localhost",8888); //Enter account password from keyboard Scanner sc =new Scanner(System.in); System.out.print("Please enter username: "); String username = sc.next(); System.out.print("Please enter password: "); String password = sc.next(); //Encapsulated as an object Account account = new Account(username,password); //Data transmission OutputStream os = client.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); //Transferring data using object streaming oos.writeObject(account); //Client receives data client.shutdownOutput(); InputStream in1 = client.getInputStream(); DataInputStream dis1 = new DataInputStream(in1); System.out.println(dis1.readUTF()); //close resource client.close(); os.close(); dis1.close(); oos.close(); in1.close(); sc.close(); } }
Server side:
package com.Stream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.DataOutputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest { public static void main(String[] args) throws IOException, ClassNotFoundException { ServerSocket ss = new ServerSocket(8888); Socket server = ss.accept(); InputStream in = server.getInputStream(); ObjectInputStream oos = new ObjectInputStream(in); Account account = (Account)(oos.readObject()); //Converting Object type to Account type //Check String res = null; if((account.getUsername().equals("kevin123")&& (account.getPassword()).equals("123456789"))) { res ="Login successful!"; }else { res ="The credentials provided are invalid."; } //Response Client server.shutdownInput(); OutputStream oos2 = server.getOutputStream(); DataOutputStream oos3 = new DataOutputStream(oos2); oos3.writeUTF(res); //close resource ss.close(); server.close(); in.close(); oos2.close(); oos3.close(); oos.close(); } }
Landing success:
Landing failure:
5. Use try-catch to catch exceptions
Instead of handling exceptions in the form of thrown exceptions, try-catch-final is used to catch exceptions.
In final, if (xxx! = null) prevents null pointer exceptions
Client
package com.Stream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class ClientTest { public static void main(String[] args) { Socket client = null; OutputStream os = null; ObjectOutputStream oos =null; InputStream in1 = null; DataInputStream dis1 =null; try { client = new Socket("localhost",8888); //Enter account password from keyboard Scanner sc =new Scanner(System.in); System.out.print("Please enter username: "); String username = sc.next(); System.out.print("Please enter password: "); String password = sc.next(); sc.close(); //Encapsulated as an object Account acc = new Account(username,password); //Data transmission os = client.getOutputStream(); oos =new ObjectOutputStream(os); //Transferring data using object streaming oos.writeObject(acc); //Client receives data client.shutdownOutput(); in1=client.getInputStream(); dis1 =new DataInputStream(in1); String result = dis1.readUTF(); System.out.println(result); } catch (IOException e) { e.printStackTrace(); }finally { try { if(client != null){ client.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(dis1 != null) { dis1.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(oos!= null) { oos.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(in1 != null){ in1.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
Server side:
package com.Stream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest { public static void main(String[] args) { ServerSocket ss =null; Socket server =null; InputStream in = null; ObjectInputStream oos = null; OutputStream oos2 = null; DataOutputStream oos3 = null; try { ss = new ServerSocket(8888); server = ss.accept(); in = server.getInputStream(); oos=new ObjectInputStream(in); Account account = (Account)(oos.readObject()); //Converting Object type to Account type //Check String res = null; if((account.getUsername().equals("kevin123")&& (account.getPassword()).equals("123456789"))) { res ="Login successful!"; }else { res ="The credentials provided are invalid."; } //Response Client server.shutdownInput(); oos2 = server.getOutputStream(); oos3 =new DataOutputStream(oos2); oos3.writeUTF(res); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { //close resource try { if(ss != null) { ss.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(server != null) { server.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(in != null) { in.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(oos2 !=null) { oos2.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(oos3 != null) { oos3.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(oos !=null) { oos.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
6. How to make the server support multiple clients working at the same time?
In the example above, if the client enters an account password once, the server shuts down after judging the correct error. In real life, a server should work continuously to support multiple client login operations.
A server generally needs to provide communication for multiple clients at the same time. If you need to support multiple clients at the same time, you must use the thread concept described earlier. Simply put, when the server receives a connection, a special thread is started to process the communication with the client.
Server side:
package com.Stream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { ServerSocket ss =null; Socket server =null; try { ss = new ServerSocket(8888); while(true) { server = ss.accept(); //Acquisition of client sockets through accept new ServerThread(server);//Each receive is processed by a thread. } } catch (IOException e) { e.printStackTrace(); } } }
Server-side thread class:
package com.Stream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.net.Socket; public class ServerThread extends Thread { Socket server =null; InputStream in = null; ObjectInputStream oos = null; OutputStream oos2 = null; DataOutputStream oos3 = null; public ServerThread(Socket server) //Use constructors to correlate two methods { super(); this.server = server; start(); } @Override public void run() { try { in = server.getInputStream(); oos=new ObjectInputStream(in); Account account = (Account)(oos.readObject()); //Converting Object type to Account type //Check String res = null; if((account.getUsername().equals("kevin123")&& (account.getPassword()).equals("123456789"))) { res ="Login successful!"; }else { res ="The credentials provided are invalid."; } //Response Client server.shutdownInput(); oos2 = server.getOutputStream(); oos3 =new DataOutputStream(oos2); oos3.writeUTF(res); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if(in != null) { in.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(oos2 != null) { oos2.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(oos3 != null) { oos3.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(oos != null) { oos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
Client:
package com.Stream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) { Socket client = null; OutputStream os = null; ObjectOutputStream oos =null; InputStream in1 = null; DataInputStream dis1 =null; try { client = new Socket("localhost",8888); //Enter account password from keyboard Scanner sc =new Scanner(System.in); System.out.print("Please enter username: "); String username = sc.next(); System.out.print("Please enter password: "); String password = sc.next(); sc.close(); //Encapsulated as an object Account acc = new Account(username,password); //Data transmission os = client.getOutputStream(); oos =new ObjectOutputStream(os); //Transferring data using object streaming oos.writeObject(acc); //Client receives data client.shutdownOutput(); in1=client.getInputStream(); dis1 =new DataInputStream(in1); String result = dis1.readUTF(); System.out.println(result); } catch (IOException e) { e.printStackTrace(); }finally { try { if(client != null){ client.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(dis1 != null) { dis1.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(oos!= null) { oos.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(in1 != null){ in1.close(); } } catch (IOException e) { e.printStackTrace(); } } } }