Java 网络编程

Posted by whaler404 on January 25, 2024

网络通讯

网络通信简介

网络通信协议主要包含两个方面的定义:

  • 定义了进程之间交换消息所必需遵循的顺序

  • 定义进程之间所交换的消息的格式

两个进程只要遵循相同的协议,就可以相互交换信息,而这两个进程可以用不同的编程语言编写,可以位于两个完全不同的计算机上。

URL通信

  • 统一资源定位符:<传输协议>://<主机名>:<端口号>/<文件名>#<引用>

  • URL类

    import java.io.*;
    import java.net.*;
    public class URL1{
    	public static void main(String[] args) throws IOException	{
    		URL url = new URL("http://www.javajeff.com/articles/articles/html");
    		System.out.println("Authority = " + url.getAuthority());
    		System.out.println("Default port = " + url.getDefaultPort());
    		System.out.println("File = " + url.getFile());
    		System.out.println("Host = " + url.getHost());
    		System.out.println("Path = " + url.getPath());
    		System.out.println("Port = " + url.getPort());
    		System.out.println("Protocol = " + url.getProtocol());
    		System.out.println("Query = " + url.getQuery());
    		System.out.println("Ref = " + url.getRef());
    		System.out.println("User Info = " + url.getUserInfo());
    	}
      
    
  • 字节流访问www资源:通过URL对象访问指定的www资源,调用URL的openStream方法

    import java.io.*; 
    import java.net.*; 
    public class URL2{
        // 对于不想处理的Exception直接throws,不用catch
    	public static void main (String [] args) throws IOException{
            // 需要说明协议
            URL url = new URL (http://www.javajeff.com/articles/articles/html”);
            InputStreamReader isr = new InputStreamReader (url.openStream (),"UTF-8");
            BufferedReader br=new BufferedReader(isr);
            String s;
            while ((s = br.readLine ()) != null)
                System.out.print(s);
            br.close();
        } 
    }
    
  • URLConnection实现双向通信:

    import java.io.*;
    import java.net.*;
    public class ComWithCgi{
    	public static void main(String[] args) throws Exception	{
                                  // 建立指向本地磁盘上cgi的URL对象
    		URL url = new URL(http:/java.sun.com/test.cgi);	                     		
            URLConnection connection = url.openConnection();
    		connection.setDoOutput(true);
    		PrintStream ps = new PrintStream(connection.getOutputStream());
    		ps.println("0123456789");
    		ps.close(); // 向服务器输出数据
    		DataInputStream dis = new DataInputStream(connection. getInputStream());
    		String inputLine;
    		while ((inputLine = dis.readLine()) != null) {
    			System.out.println(inputLine);
    		}
    		dis.close();// 从服务器读数据
    	}
    }
    
  • HttpURLConnection:提供了对http协议的支持

Socket通信

  • 服务端

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
      
    public class Server {
        public static void main(String[] args) {
            final int PORT = 12345;
      
            try (ServerSocket serverSocket = new ServerSocket(PORT)) {
                System.out.println("Server is running and waiting for connections...");
      
                // 等待客户端连接
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected.");
      
                // 从客户端接收数据
                BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                String message = reader.readLine();
                System.out.println("Received message from client: " + message);
      
                // 关闭连接
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
      
    
  • 客户端

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;
      
    public class Client {
        public static void main(String[] args) {
            final String SERVER_ADDRESS = "localhost";
            final int PORT = 12345;
      
            try (Socket socket = new Socket(SERVER_ADDRESS, PORT)) {
                System.out.println("Connected to server.");
      
                // 发送数据到服务端
                //自动刷新缓冲区
                PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
                writer.println("Hello, Server!");
      
                // 关闭连接
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
      
    
  • 服务多个客户:调用accept等待新的连接,一旦accept返回,获得对应的socket,创建新的线程,然后调用accept,继续等待下一次连接请求

    • 服务端

      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      import java.util.ArrayList;
      import java.util.List;
          
      class ClientHandler extends Thread {
          private Socket clientSocket;
          private MultiClientServer server;
          private BufferedReader reader;
          private PrintWriter writer;
          
          public ClientHandler(Socket clientSocket, MultiClientServer server) {
              this.clientSocket = clientSocket;
              this.server = server;
          
              try {
                  reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                  writer = new PrintWriter(clientSocket.getOutputStream(), true);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          
          public Socket getClientSocket() {
              return clientSocket;
          }
          
          public void sendMessage(String message) {
              writer.println(message);
          }
          
          @Override
          public void run() {
              try {
                  String username = reader.readLine();
                  System.out.println("New user joined: " + username);
          
                  // 向所有客户端广播新用户加入的消息
                  server.broadcastMessage(username + " joined the chat.", this);
          
                  String clientMessage;
                  while ((clientMessage = reader.readLine()) != null) {
                      // 向所有客户端广播收到的消息
                      server.broadcastMessage(username + ": " + clientMessage, this);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  // 客户端断开连接,移除自身
                  server.removeClient(this);
                  server.broadcastMessage("User disconnected.", this);
          
                  try {
                      clientSocket.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
          
      public class MultiClientServer {
          private List<ClientHandler> clients = new ArrayList<>();
          
          public static void main(String[] args) {
              MultiClientServer server = new MultiClientServer();
              server.startServer();
          }
          
          public void startServer() {
              final int PORT = 12345;
          
              try (ServerSocket serverSocket = new ServerSocket(PORT)) {
                  System.out.println("Server is running and waiting for connections...");
          
                  while (true) {
                      Socket clientSocket = serverSocket.accept();
                      System.out.println("Client connected: " + clientSocket);
          
                      // 创建新的客户端处理线程
                      ClientHandler clientHandler = new ClientHandler(clientSocket, this);
                      clients.add(clientHandler);
                      clientHandler.start();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          
          // 向所有客户端广播消息
          public void broadcastMessage(String message, ClientHandler sender) {
              for (ClientHandler client : clients) {
                  // 不向消息发送者发送消息
                  if (client != sender) {
                      client.sendMessage(message);
                  }
              }
          }
          
          // 移除断开连接的客户端
          public void removeClient(ClientHandler client) {
              clients.remove(client);
              System.out.println("Client disconnected: " + client.getClientSocket());
          }
      }
      
    • 客户端

      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.Socket;
          
      public class ChatClient {
          public static void main(String[] args) {
              ChatClient client = new ChatClient();
              client.startClient();
          }
          
          public void startClient() {
              final String SERVER_ADDRESS = "localhost";
              final int PORT = 12345;
          
              try (Socket socket = new Socket(SERVER_ADDRESS, PORT)) {
                  BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
                  BufferedReader serverReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
          
                  System.out.print("Enter your username: ");
                  String username = consoleReader.readLine();
                  writer.println(username);
          
                  Thread messageReceiver = new Thread(() -> {
                      try {
                          String serverMessage;
                          while ((serverMessage = serverReader.readLine()) != null) {
                              System.out.println(serverMessage);
                          }
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  });
                  messageReceiver.start();
          
                  String clientMessage;
                  while (true) {
                      clientMessage = consoleReader.readLine();
                      writer.println(clientMessage);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
    • 对于服务端,同一主机和端口上只能有一个监听的ServerSocket;而对于客户端,可以同时存在多个连接到相同主机和端口的 Socket。

    public class test{
    	public class ServerCreater implements Runnable{
    		public void run(){
    			test t=new test();
    			int i=0;
    			try(ServerSocket serverSocket=new ServerSocket(65432)){
    				while(i<5){
    					System.out.println("server");
    					Socket socket=serverSocket.accept();
    					Thread server=new Thread(t.new Server(socket));
    					server.start();
    					i++;
    				}
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    		}
    	}
    	public class Server implements Runnable{
    		private Socket socket;
    		Server(Socket s){
    			socket=s;
    		}
    		public void run(){
    			try{
    				BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
    				String s;
    				while((s=bufferedReader.readLine())!=null){
    					System.out.println("receive:"+s);
    				}
    				socket.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
      			
    		}
    	}
    	public class Client implements Runnable{
    		public void run(){
    			try(Socket socket=new Socket("localhost", 65432)){
    				Thread.sleep(1000);
    				System.out.println("client");
    				String s[]={"I","love","you"};
    				PrintWriter bufferedWriter=new PrintWriter(socket.getOutputStream(),true);
    				for(String ss:s){
    					bufferedWriter.println(ss);
    				}
    				socket.close();
    			}catch(IOException|InterruptedException e){
    				e.printStackTrace();
    			}
      			
    		}
    	} 
    	public static void main(String[]args)throws Exception{
    		test t=new test();
    		Thread serverCreater=new Thread(t.new ServerCreater());
    		serverCreater.start();
    		for(int i=0;i<5;i++){
    			Thread client=new Thread(t.new Client());
    			client.start();
    		}
    	}
    }
    
  • 数据报通信

    • 服务端

      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
          
      public class DatagramServer {
          public static void main(String[] args) {
              final int PORT = 9876;
          
              try (DatagramSocket serverSocket = new DatagramSocket(PORT)) {
                  System.out.println("Server is running and waiting for messages...");
          
                  byte[] receiveData = new byte[1024];
          
                  while (true) {
                      DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                      serverSocket.receive(receivePacket);
          
                      String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
                      System.out.println("Received message from client: " + message);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
          
      
    • 客户端

      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;
      import java.util.Scanner;
          
      public class DatagramClient {
          public static void main(String[] args) {
              final String SERVER_ADDRESS = "localhost";
              final int PORT = 9876;
          
              try (DatagramSocket clientSocket = new DatagramSocket()) {
                  InetAddress serverAddress = InetAddress.getByName(SERVER_ADDRESS);
          
                  Scanner scanner = new Scanner(System.in);
          
                  while (true) {
                      System.out.print("Enter a message to send to server: ");
                      String message = scanner.nextLine();
          
                      byte[] sendData = message.getBytes();
          
                      DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, PORT);
                      clientSocket.send(sendPacket);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
          
      

远程方法调用(RMI)

程序可以方便调用远程计算机上的函数

相关资料