Explicación detallada de la programación de redes Java

Los artículos y códigos se han archivado en [Github warehouse: https://github.com/timerring/java-tutorial] o la cuenta pública [AIShareLab] también se puede obtener respondiendo a java .

Conceptos relacionados con la red

Telecomunicación

  1. Concepto: transmisión de datos entre dos dispositivos a través de la red
  2. Comunicación de red: transferencia de datos de un dispositivo a otro a través de una red
  3. El paquete java.net proporciona una serie de clases o interfaces para que los programadores las utilicen para completar la comunicación de red.

red

  1. Concepto: dos o más dispositivos están conectados a través de ciertos dispositivos físicos para formar una red
  2. Según la cobertura de la red, la red se clasifica de la siguiente manera:
  • LAN: La cobertura es la más pequeña, cubriendo solo un salón de clases o una sala de computación
  • Red de área metropolitana: tiene una gran área de cobertura y puede cubrir una ciudad
  • Red de área amplia: la mayor cobertura, puede cubrir todo el país, incluso todo el mundo, la World Wide Web es el representante de la red de área amplia

dirección IP

  1. Concepto: utilizado para identificar de forma única cada computadora/host en la red

  2. Ver dirección IP:ipconfig

  3. Representación de la dirección IP: punto decimal XX.XX.XX.XX

  4. El rango de cada número decimal: 0 ~ 255

  5. La composición de la dirección IP = dirección de red + dirección de host, por ejemplo: 192.168.16.69

  6. IPv6 es un protocolo IP de próxima generación diseñado por Internet Engineering Task Force para reemplazar a IPv4. Su cantidad de direcciones afirma ser capaz de codificar una dirección por cada grano de arena en el mundo.

  7. El mayor problema con IPv4 es que los recursos de direcciones de red son limitados, lo que restringe seriamente la aplicación y el desarrollo de Internet. El uso de IPv6 no solo puede resolver el problema de la cantidad de recursos de direcciones de red, sino también resolver el obstáculo de conectar varios dispositivos de acceso a Internet.

clasificación de direcciones ipv4

Especial: 127.0.0.1 representa la dirección local

nombre de dominio

  1. www.baidu.com
  2. Beneficios: Para facilitar la memoria y resolver ipla dificultad de recordar
  3. Concepto: ipAsigne la dirección a un nombre de dominio, cómo asignarlo aquí: protocolo HTTP

el número de puerto

  1. Concepto: se utiliza para identificar un programa de red específico en una computadora
  2. Representación: en forma de número entero, rango de puertos 0~65535 [2 bytes representan el puerto 0~2^16-1]
  3. 0~1024 ya ocupado, como ssh 22, ftp 21, smtp 25 http 80
  4. Números de puerto de programas de red comunes
    • gato: 8080
    • mysql: 3306
    • oráculo: 1521
    • servidor SQL: 1433

protocolo de comunicación de red

Protocolo (tcp/ip)

La abreviatura de TCP/IP (Transmission Control Protocol/Internet Protocol), la traducción al chino se llama Transmission Control Protocol/Internet Internet Protocol, también conocido como Network Communication Protocol, este protocolo es el protocolo más básico de Internet, la base de Internet , simplemente , está compuesto por el protocolo IP en la capa de red y el protocolo TCP en la capa de transporte.

TCP y UDP

Protocolo TCP: Protocolo de control de transmisión

  1. Antes de usar el protocolo TCP, se debe establecer una conexión TCP para formar un canal de transmisión de datos
  2. Antes de la transmisión, se utiliza el método de "apretón de manos de tres vías", que es confiable
  3. Dos procesos de aplicación para la comunicación del protocolo TCP: cliente y servidor
  4. Se puede transferir una gran cantidad de datos en la conexión.
  5. Una vez que se completa la transmisión, la conexión establecida debe liberarse, lo cual es ineficiente

Protocolo UDP: Protocolo de datos de usuario

  1. Encapsule datos, origen y destino en paquetes sin establecer una conexión
  2. El tamaño de cada datagrama está limitado a 64K, lo que no es adecuado para transmitir grandes cantidades de datos.
  3. No confiable porque no se requiere conexión
  4. No hay necesidad de liberar recursos al final del envío de datos (porque no está orientado a la conexión), y la velocidad es rápida

Clase InetAddress

método relacionado

  1. Obtenga el objeto nativo InetAddress getLocalHost
  2. Obtenga el objeto de dirección IP getByName de acuerdo con el nombre de host/nombre de dominio especificado
  3. Obtenga el nombre de host del objeto InetAddress getHostName
  4. Obtenga la dirección del objeto InetAddress getHostAddress

Aplicaciones

Escriba el código para obtener el nombre de host de la computadora y la API relacionada con la dirección IP

package com.hspedu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 演示InetAddress 类的使用
 */
public class API_ {
    
    
    public static void main(String[] args) throws UnknownHostException {
    
    

        //1. 获取本机的InetAddress 对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);//DESKTOP-S4MP84S/192.168.12.1

        //2. 根据指定主机名 获取 InetAddress对象
        InetAddress host1 = InetAddress.getByName("DESKTOP-S4MP84S");
        System.out.println("host1=" + host1);//DESKTOP-S4MP84S/192.168.12.1

        //3. 根据域名返回 InetAddress对象, 比如 www.baidu.com 对应
        InetAddress host2 = InetAddress.getByName("www.baidu.com");
        System.out.println("host2=" + host2);//www.baidu.com / 110.242.68.4

        //4. 通过 InetAddress 对象,获取对应的地址
        String hostAddress = host2.getHostAddress();//IP 110.242.68.4
        System.out.println("host2 对应的ip = " + hostAddress);//110.242.68.4

        //5. 通过 InetAddress 对象,获取对应的主机名/或者的域名
        String hostName = host2.getHostName();
        System.out.println("host2对应的主机名/域名=" + hostName); // www.baidu.com
    }
}

Enchufe

introducción básica

  1. El desarrollo de socket (Socket) de aplicaciones de red se adopta ampliamente, por lo que se convierte en el estándar de facto.
  2. Debe haber Socket en ambos extremos de la comunicación, que es el punto final de la comunicación entre dos máquinas.
  3. La comunicación de red es en realidad comunicación entre Sockets.
  4. Socket permite que los programas traten las conexiones de red como un flujo y los datos se transmiten entre dos Sockets a través de IO.
  5. Generalmente, el programa de aplicación que inicia la comunicación es el cliente, y la aplicación que espera la solicitud de comunicación es el servidor.

diagrama esquemático

Programación de comunicación de red TCP

introducción básica

  1. Comunicación de red basada en cliente-servidor
  2. La capa inferior utiliza el protocolo TCP/IP
  3. Ejemplo de escenario de aplicación: el cliente envía datos, el servidor acepta y muestra la consola
  4. Programación TCP basada en socket

Finalmente, debe cerrar el zócalo, de lo contrario, habrá problemas si hay demasiadas conexiones.

Caso de aplicación 1 (usando flujo de bytes)

  1. Escribir un servidor y un cliente.
  2. El servidor escucha en el puerto 9999
  3. El cliente se conecta al servidor, envía "hola, servidor" y sale
  4. El servidor recibe la información enviada por el cliente, emite y sale

ServerSocket puede devolver múltiples sockets a través de accept () [concurrencia de múltiples clientes que se conectan al servidor]

package com.hspedu.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 客户端,发送 "hello, server" 给服务端
 */
public class SocketTCP01Client {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        // 如果链接网络,第一个参数可以改为IP
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        //4. 关闭流对象和socket, 必须关闭
        outputStream.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}
package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端
 */
public class SocketTCP01Server {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
    
    
            System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.
        }
        //5.关闭流和socket
        inputStream.close();
        socket.close();
        serverSocket.close();// 最后也需要关闭
    }
}

Caso de aplicación 2 (usando flujo de bytes)

  1. Escriba un servidor y un cliente.
  2. El servidor escucha en el puerto 9999.
  3. El cliente se conecta al servidor, envía "hola, servidor" y recibe el "hola, cliente" devuelto por el servidor y luego sale.
  4. El servidor recibe la información enviada por el cliente, la emite y envía "hola, cliente" y luego sale.

NOTA: Establece el marcador de cierre. Asegúrese de que finalice la salida.

package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端
 */
@SuppressWarnings({
    
    "all"})
public class SocketTCP02Server {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
    
    
            System.out.println(new String(buf, 0, readLen));//根据读取到的实际长度,显示内容.
        }
        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        // 设置结束标记
        socket.shutdownOutput();

        //6.关闭流和socket
        outputStream.close();
        inputStream.close();
        socket.close();
        serverSocket.close();//关闭

    }
}
package com.hspedu.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端,发送 "hello, server" 给服务端
 */
@SuppressWarnings({
    
    "all"})
public class SocketTCP02Client {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道
        outputStream.write("hello, server".getBytes());
        //   设置结束标记
        socket.shutdownOutput();

        //4. 获取和socket关联的输入流. 读取数据(字节),并显示
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
    
    
            System.out.println(new String(buf, 0, readLen));
        }

        //5. 关闭流对象和socket, 必须关闭
        inputStream.close();
        outputStream.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}

Caso de aplicación 3 (usando flujo de caracteres)

  1. Escribir un servidor y un cliente.
  2. El servidor escucha en el puerto 9999
  3. El cliente se conecta al servidor, envía "hola, servidor" y recibe el "hola, cliente" devuelto por el servidor, y luego sale
  4. El servidor recibe la información enviada por el cliente, emite y envía "hola, cliente", y luego sale

La etiqueta final también se puede usar aquí writer.newLine();, pero esto requiere que la otra parte la lea y debe usarla readLine().

package com.hspedu.socket;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
 * 客户端,发送 "hello, server" 给服务端, 使用字符流
 */
@SuppressWarnings({
    
    "all"})
public class SocketTCP03Client {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回=" + socket.getClass());
        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道, 使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello, server 字符流");
        bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
        bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道


        //4. 获取和socket关联的输入流. 读取数据(字符),并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 关闭流对象和socket, 必须关闭
        bufferedReader.close();//关闭外层流
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}
package com.hspedu.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端, 使用字符流方式读写
 */
@SuppressWarnings({
    
    "all"})
public class SocketTCP03Server {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        System.out.println("服务端 socket =" + socket.getClass());
        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);//输出

        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
       //    使用字符输出流的方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello client 字符流");
        bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//注意需要手动的flush

        //6.关闭流和socket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();//关闭
    }
}

Caso de aplicación 4

  1. Escribir un servidor y un cliente.
  2. El servidor escucha en el puerto 8888
  3. El cliente se conecta al servidor y envía una imagen e:llqie.png
  4. El servidor recibe la imagen enviada por el cliente, la guarda en src, envía "imagen recibida" y luego sale
  5. El cliente recibe la "imagen recibida" enviada por el servidor y luego sale
  6. El programa requiere el uso de StreamUtils.java, y usamos directamente el método encapsulado en él.

package com.hspedu.upload;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;


/**
 * 文件上传的客户端
 */
public class TCPFileUploadClient {
    
    
    public static void main(String[] args) throws Exception {
    
    

        //客户端连接服务端 8888,得到Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        //创建读取磁盘文件的输入流
        //String filePath = "e:\\qie.png";
        String filePath = "e:\\abc.mp4";
        BufferedInputStream bis  = new BufferedInputStream(new FileInputStream(filePath));

        // 把文件读到字符数组中!!!!!
        // bytes 就是filePath对应的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //通过socket获取到输出流, 将bytes数据发送给服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes); //将文件对应的字节数组的内容,写入到数据通道
        bis.close();
        socket.shutdownOutput(); //设置写入数据的结束标记

        //=====接收从服务端回复的消息=====

        InputStream inputStream = socket.getInputStream();
        //使用StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);


        //关闭相关的流
        inputStream.close();
        bos.close();
        socket.close();

    }
}
package com.hspedu.upload;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 文件上传的服务端
 */
public class TCPFileUploadServer {
    
    
    public static void main(String[] args) throws Exception {
    
    

        //1. 服务端在本机监听8888端口
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端在8888端口监听....");
        //2. 等待连接
        Socket socket = serverSocket.accept();


        //3. 读取客户端发送的数据
        //   通过Socket得到输入流
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis); // 已然读到数组中了
        //4. 将得到 bytes 数组,写入到指定的路径,就得到一个文件了
        String destFilePath = "src\\abc.mp4";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
        bos.write(bytes);
        bos.close();

        // 向客户端回复 "收到图片"
        // 通过socket 获取到输出流(字符)
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("收到图片");
        writer.flush();//把内容刷新到数据通道
        socket.shutdownOutput();//设置写入结束标记

        //关闭其他资源
        writer.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}
package com.hspedu.upload;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
    
    
   /**
    * 功能:将输入流转换成byte[]
    * @param is
    * @return
    * @throws Exception
    */
   public static byte[] streamToByteArray(InputStream is) throws Exception{
    
    
      ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
      byte[] b = new byte[1024];
      int len;
      while((len=is.read(b))!=-1){
    
    
         bos.write(b, 0, len);// 读取道德数据写入bos
      }
      byte[] array = bos.toByteArray();
      bos.close();
      return array;
   }
   /**
    * 功能:将InputStream转换成String
    * @param is
    * @return
    * @throws Exception
    */
   
   public static String streamToString(InputStream is) throws Exception{
    
    
      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
      StringBuilder builder= new StringBuilder();
      String line;
      while((line=reader.readLine())!=null){
    
     //当读取到 null时,就表示结束
         builder.append(line+"\r\n");
      }
      return builder.toString();
      
   }

}

comando netstat

  1. netstat -anPuede ver las condiciones actuales de la red del host, incluida la supervisión del puerto del proyecto y las condiciones de conexión de la red.
  2. netstat -an | moreSe puede mostrar en páginas.
  3. netstat -anb(Ejecutar como administrador) para ver qué aplicaciones están escuchando en el puerto.
  4. La dirección externa es la IP y el número de puerto del cliente que se conecta a la dirección local y el número de puerto.

ilustrar:

(1) Escuchando significa que cierto puerto está escuchando Establecido significa que la conexión se ha establecido

(2) Si hay un programa externo (cliente) conectado al puerto, se mostrará un mensaje de conexión

Comunicación de red TCP

  1. Cuando el cliente se conecta al servidor, el cliente en realidad se comunica con el servidor a través de un puerto.Este puerto está asignado por TCP/IP, que es incierto y aleatorio. ( puerto del cliente )
  2. Verificación del programa + netstat

Programación de comunicación de red UDP

introducción básica

  1. La clase DatagramSockety DatagramPacket[paquete/datagrama] implementa
    un programa de red basado en el protocolo UDP.

  2. Los datagramas UDP se envían y reciben a través de sockets de datagramas.El DatagramSocketsistema no garantiza que los datagramas UDP se entreguen de forma segura a sus destinos, ni puede determinar cuándo llegarán.

  3. DatagramPacketEl objeto encapsula el datagrama UDP, y el datagrama contiene la dirección IP y el
    número de puerto del extremo emisor y la dirección IP y el número de puerto del extremo receptor.

  4. Cada datagrama en el protocolo UDP brinda información completa de la dirección, por lo que no es necesario establecer
    una conexión entre el remitente y el receptor.

proceso basico

  1. Las dos clases/objetos principales DatagramSocket y DatagramPacket
  2. Establecer el remitente y el receptor (sin concepto de servidor y cliente)
  3. Antes de enviar datos, cree un paquete de datos/objeto DatagramPacket de informe
  4. Llame a los métodos de envío y recepción de DatagramSocket
  5. Cerrar DatagramSocket

Aplicaciones

  1. Escriba un receptor A y un emisor B
  2. El receptor A espera recibir datos en el puerto 9999 (recibir)
  3. El remitente B envía datos al receptor A "hola, come una olla caliente mañana ~"
  4. El receptor A recibe los datos enviados por el emisor B, responde "OK, nos vemos mañana" y sale
  5. El remitente recibe los datos de respuesta y luego sale.
package com.hspedu.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * UDP接收端
 */
public class UDPReceiverA {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //1. 创建一个 DatagramSocket 对象,准备在9999接收数据
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9999端口时,就会接收到数据
        //   如果没有数据包发送到 本机的9999端口, 就会阻塞等待.
        System.out.println("接收端A 等待接收数据..");
        socket.receive(packet);

        //4. 可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        byte[] data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);


        //===回复信息给B端
        //将需要发送的数据,封装到 DatagramPacket对象
        data = "好的, 明天见".getBytes();
        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9998);

        socket.send(packet);//发送

        //5. 关闭资源
        socket.close();
        System.out.println("A端退出...");

    }
}
package com.hspedu.udp;

import java.io.IOException;
import java.net.*;

/**
 * 发送端B ====> 也可以接收数据
 */
@SuppressWarnings({
    
    "all"})
public class UDPSenderB {
    
    
    public static void main(String[] args) throws IOException {
    
    

        //1.创建 DatagramSocket 对象,准备在9998端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);

        //2. 将需要发送的数据,封装到 DatagramPacket对象
        byte[] data = "hello 明天吃火锅~".getBytes(); //

        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9999);

        socket.send(packet);

        //3.=== 接收从A端回复的信息
        //(1)   构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //(2)    调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9998端口时,就会接收到数据
        //   如果没有数据包发送到 本机的9998端口, 就会阻塞等待.
        socket.receive(packet);

        //(3)  可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //关闭资源
        socket.close();
        System.out.println("B端退出");
    }
}

Tarea para este capitulo

1. Preguntas de programación

(1) Escriba un programa de cliente y un programa de servidor usando flujos de caracteres,

(2) El cliente envía "nombre" y el servidor devuelve "Soy nova" después de recibirlo. Nova es tu propio nombre.

(3) El cliente envía "hobby" y el servidor devuelve "escribir programa Java" después de recibirlo

(4) No estas dos preguntas, responde "¿De qué estás hablando?"

Pregunta: Actualmente, solo podemos preguntar una vez y salir. ¿Cómo podemos preguntar varias veces? ->mientras ->chat

package com.hspedu.homework;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
 * 客户端,发送 "hello, server" 给服务端, 使用字符流
 */
@SuppressWarnings({
    
    "all"})
public class Homework01Client {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 连接服务端 (ip , 端口)
        //解读: 连接本机的 9999端口, 如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        //2. 连接上后,生成Socket, 通过socket.getOutputStream()
        //   得到 和 socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到 数据通道, 使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));

        //从键盘读取用户的问题
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的问题");
        String question = scanner.next();

        bufferedWriter.write(question);
        bufferedWriter.newLine();//插入一个换行符,表示写入的内容结束, 注意,要求对方使用readLine()!!!!
        bufferedWriter.flush();// 如果使用的字符流,需要手动刷新,否则数据不会写入数据通道


        //4. 获取和socket关联的输入流. 读取数据(字符),并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 关闭流对象和socket, 必须关闭
        bufferedReader.close();//关闭外层流
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出.....");
    }
}
package com.hspedu.homework;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端, 使用字符流方式读写
 */
@SuppressWarnings({
    
    "all"})
public class Homework01Server {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //思路
        //1. 在本机 的9999端口监听, 等待连接
        //   细节: 要求在本机没有其它服务在监听9999
        //   细节:这个 ServerSocket 可以通过 accept() 返回多个Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会 阻塞, 等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续

        Socket socket = serverSocket.accept();

        //
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据, 显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取, 使用字符流, 老师使用 InputStreamReader 将 inputStream 转成字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        String answer = "";
        if ("name".equals(s)) {
    
    
            answer = "我是韩顺平";
        } else if("hobby".equals(s)) {
    
    
            answer = "编写java程序";
        } else {
    
    
            answer = "你说的啥子";
        }


        //5. 获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        //    使用字符输出流的方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write(answer);
        bufferedWriter.newLine();// 插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//注意需要手动的flush


        //6.关闭流和socket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();//关闭

    }
}

2. Preguntas de programación

(1) Escriba un receptor A y un remitente B, usando el protocolo UDP para completar

(2) El extremo receptor está esperando recibir datos en el puerto 8888 (recibir)

(3) El extremo emisor envía datos al extremo receptor "Cuáles son los cuatro grandes clásicos"

(4) Después de que el extremo receptor recibe la pregunta enviada por el extremo emisor, devuelve "Las Cuatro Grandes Obras Maestras son <<Sueño de Mansiones Rojas>>...", de lo contrario, ¿devuelve qué?

(5) Salida de los programas receptor y emisor

package com.hspedu.homework;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
 * 发送端B ====> 也可以接收数据
 */
@SuppressWarnings({
    
    "all"})
public class Homework02SenderB {
    
    
    public static void main(String[] args) throws IOException {
    
    

        //1.创建 DatagramSocket 对象,准备在9998端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);

        //2. 将需要发送的数据,封装到 DatagramPacket对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你的问题: ");
        String question = scanner.next();
        byte[] data = question.getBytes(); //

        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 8888);

        socket.send(packet);

        //3.=== 接收从A端回复的信息
        //(1)   构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //(2)    调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        //老师提示: 当有数据包发送到 本机的9998端口时,就会接收到数据
        //   如果没有数据包发送到 本机的9998端口, 就会阻塞等待.
        socket.receive(packet);

        //(3)  可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //关闭资源
        socket.close();
        System.out.println("B端退出");
    }
}
package com.hspedu.homework;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * UDP接收端
 */
@SuppressWarnings({
    
    "all"})
public class Homework02ReceiverA {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //1. 创建一个 DatagramSocket 对象,准备在8888接收数据
        DatagramSocket socket = new DatagramSocket(8888);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        //   填充到 packet对象
        System.out.println("接收端 等待接收问题 ");
        socket.receive(packet);

        //4. 可以把packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        byte[] data = packet.getData();//接收到数据
        String s = new String(data, 0, length); // 将字节数组转为string!!!!
        //判断接收到的信息是什么
        String answer = "";
        if("四大名著是哪些".equals(s)) {
    
    
            answer = "四大名著 <<红楼梦>> <<三国演示>> <<西游记>> <<水浒传>>";
        } else {
    
    
            answer = "what?";
        }


        //===回复信息给B端
        //将需要发送的数据,封装到 DatagramPacket对象
        data = answer.getBytes();
        //说明: 封装的 DatagramPacket对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9998);

        socket.send(packet);//发送

        //5. 关闭资源
        socket.close();
        System.out.println("A端退出...");

    }
}

3. Preguntas de programación

(1) Escribir programa cliente y programa servidor

(2) El cliente puede ingresar un nombre de archivo de música, como Gaoshan Liushui. Después de recibir el nombre de la música, el servidor puede devolver el archivo de música al cliente. Si el servidor no tiene este archivo, simplemente devuelva una música predeterminada.

(3) Después de que el cliente reciba el archivo, guárdelo en el e:\\ local

(4) Consejo: este programa puede usar StreamUtils.java

package com.hspedu.homework;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 文件下载的客户端
 */
public class Homework03Client {
    
    
    public static void main(String[] args) throws Exception {
    
    


        //1. 接收用户输入,指定下载文件名
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入下载文件名");
        String downloadFileName = scanner.next();

        //2. 客户端连接服务端,准备发送
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        //3. 获取和Socket关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(downloadFileName.getBytes());
        //设置写入结束的标志
        socket.shutdownOutput();

        //4. 读取服务端返回的文件(字节数据)
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //5. 得到一个输出流,准备将 bytes 写入到磁盘文件
        //比如你下载的是 高山流水 => 下载的就是 高山流水.mp3
        //    你下载的是 无名 => 下载的就是 无名.mp3
        String filePath = "e:\\" + downloadFileName + ".mp3";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);

        //6. 关闭相关的资源
        bos.close();
        bis.close();
        outputStream.close();
        socket.close();

        System.out.println("客户端下载完毕,正确退出..");


    }
}
package com.hspedu.homework;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 先写文件下载的服务端
 */
public class Homework03Server {
    
    
    public static void main(String[] args) throws Exception {
    
    

        //1 监听 9999端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //2.等待客户端连接
        System.out.println("服务端,在9999端口监听,等待下载文件");
        Socket socket = serverSocket.accept();
        //3.读取 客户端发送要下载的文件名
        //  这里老师使用了while读取文件名,时考虑将来客户端发送的数据较大的情况
        InputStream inputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        int len = 0;
        String downLoadFileName = "";
        while ((len = inputStream.read(b)) != -1) {
    
    
            downLoadFileName += new String(b, 0 , len);
        }
        System.out.println("客户端希望下载文件名=" + downLoadFileName);

        //老师在服务器上有两个文件, 无名.mp3 高山流水.mp3
        //如果客户下载的是 高山流水 我们就返回该文件,否则一律返回 无名.mp3

        String resFileName = "";
        if("高山流水".equals(downLoadFileName)) {
    
    
            resFileName = "src\\高山流水.mp3";
        } else {
    
    
            resFileName = "src\\无名.mp3";
        }

        //4. 创建一个输入流,读取文件
        BufferedInputStream bis =
                new BufferedInputStream(new FileInputStream(resFileName));

        //5. 使用工具类StreamUtils ,读取文件到一个字节数组

        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //6. 得到Socket关联的输出流
        BufferedOutputStream bos =
                new BufferedOutputStream(socket.getOutputStream());
        //7. 写入到数据通道,返回给客户端
        bos.write(bytes);
        socket.shutdownOutput();//很关键.

        //8 关闭相关的资源
        bis.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("服务端退出...");

    }
}
package com.hspedu.homework;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
    
    
   /**
    * 功能:将输入流转换成byte[]
    * @param is
    * @return
    * @throws Exception
    */
   public static byte[] streamToByteArray(InputStream is) throws Exception{
    
    
      ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
      byte[] b = new byte[1024];
      int len;
      while((len=is.read(b))!=-1){
    
    
         bos.write(b, 0, len);  
      }
      byte[] array = bos.toByteArray();
      bos.close();
      return array;
   }
   /**
    * 功能:将InputStream转换成String
    * @param is
    * @return
    * @throws Exception
    */
   
   public static String streamToString(InputStream is) throws Exception{
    
    
      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
      StringBuilder builder= new StringBuilder();
      String line;
      while((line=reader.readLine())!=null){
    
    
         builder.append(line+"\r\n");
      }
      return builder.toString();
   }
}

Supongo que te gusta

Origin blog.csdn.net/m0_52316372/article/details/130573037
Recomendado
Clasificación