Detailed explanation of Java network programming

Articles and codes have been archived in [Github warehouse: https://github.com/timerring/java-tutorial] or the public account [AIShareLab] can also be obtained by replying to java .

Network related concepts

Telecommunication

  1. Concept: data transmission between two devices through the network
  2. Network Communication: Transferring data from one device to another over a network
  3. The java.net package provides a series of classes or interfaces for programmers to use to complete network communication

network

  1. Concept: Two or more devices are connected through certain physical devices to form a network
  2. According to the coverage of the network, the network is classified as follows:
  • LAN: The coverage is the smallest, covering only one classroom or one computer room
  • Metropolitan area network: it has a large coverage area and can cover a city
  • Wide area network: the largest coverage, can cover the whole country, even the whole world, the World Wide Web is the representative of the wide area network

ip address

  1. Concept: used to uniquely identify each computer/host in the network

  2. View ip address:ipconfig

  3. Representation of ip address: dotted decimal XX.XX.XX.XX

  4. The range of each decimal number: 0~255

  5. The composition of ip address = network address + host address, for example: 192.168.16.69

  6. IPv6 is a next-generation IP protocol designed by the Internet Engineering Task Force to replace IPv4. Its number of addresses claims to be able to encode an address for every grain of sand in the world.

  7. The biggest problem with IPv4 is that the network address resources are limited, which seriously restricts the application and development of the Internet. The use of IPv6 can not only solve the problem of the number of network address resources, but also solve the obstacle of connecting various access devices to the Internet.

ipv4 address classification

Special: 127.0.0.1 represents the local address

domain name

  1. www.baidu.com
  2. Benefits: In order to facilitate memory and solve ipthe difficulty of remembering
  3. Concept: ipMap the address into a domain name, how to map it here - HTTP protocol

The port number

  1. Concept: Used to identify a specific network program on a computer
  2. Representation: in integer form, port range 0~65535 [2 bytes represent port 0~2^16-1]
  3. 0~1024 already occupied, such as ssh 22, ftp 21, smtp 25 http 80
  4. Common network program port numbers
    • tomcat: 8080
    • mysql: 3306
    • oracle: 1521
    • sqlserver: 1433

network communication protocol

Protocol (tcp/ip)

The abbreviation of TCP/IP (Transmission Control Protocol/Internet Protocol), the Chinese translation is called Transmission Control Protocol/Internet Internet Protocol, also known as Network Communication Protocol, this protocol is the most basic protocol of Internet, the foundation of the Internet, simply , is composed of the IP protocol at the network layer and the TCP protocol at the transport layer.

TCP and UDP

TCP protocol: Transmission Control Protocol

  1. Before using the TCP protocol, a TCP connection must be established to form a transmission data channel
  2. Before transmission, the "three-way handshake" method is used, which is reliable
  3. Two application processes for TCP protocol communication: client and server
  4. A large amount of data can be transferred in the connection
  5. After the transmission is completed, the established connection needs to be released, which is inefficient

UDP protocol: User Data Protocol

  1. Encapsulate data, source, and destination into packets without establishing a connection
  2. The size of each datagram is limited to 64K, which is not suitable for transmitting large amounts of data
  3. Unreliable because no connection is required
  4. There is no need to release resources at the end of sending data (because it is not connection-oriented), and the speed is fast

InetAddress class

related methods

  1. Get the native InetAddress object getLocalHost
  2. Get the ip address object getByName according to the specified host name/domain name
  3. Get the host name of the InetAddress object getHostName
  4. Get the address of the InetAddress object getHostAddress

Applications

Write code to get the computer's hostname and IP address related API

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
    }
}

Socket

basic introduction

  1. Socket (Socket) development of network applications is widely adopted, so that it becomes the de facto standard.
  2. There must be Socket at both ends of the communication, which is the endpoint of communication between two machines.
  3. Network communication is actually communication between Sockets.
  4. Socket allows programs to treat network connections as a stream, and data is transmitted between two Sockets through IO.
  5. Generally, the application program that initiates the communication is the client, and the application that waits for the communication request is the server.

schematic diagram

TCP network communication programming

basic introduction

  1. Client-server based network communication
  2. The bottom layer uses the TCP/IP protocol
  3. Application scenario example: the client sends data, the server accepts and displays the console
  4. Socket-based TCP programming

Finally, you need to close the socket, otherwise there will be problems if there are too many connections.

Application case 1 (using byte stream)

  1. Write a server, and a client
  2. The server listens on port 9999
  3. The client connects to the server, sends "hello, server", and exits
  4. The server receives the information sent by the client, outputs, and exits

ServerSocket can return multiple Sockets through accept() [concurrency of multiple clients connecting to the server]

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();// 最后也需要关闭
    }
}

Application case 2 (using byte stream)

  1. Write a server and a client.
  2. The server listens on port 9999.
  3. The client connects to the server, sends "hello, server", and receives the "hello, client" sent back by the server, and then exits.
  4. The server receives the information sent by the client, outputs it, and sends "hello, client". Then exit.

NOTE: Sets the closing marker. Make sure the output ends.

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("客户端退出.....");
    }
}

Application case 3 (using character stream)

  1. Write a server, and a client
  2. The server listens on port 9999
  3. The client connects to the server, sends "hello, server", and receives the "hello, client" sent back by the server, and then exits
  4. The server receives the information sent by the client, outputs, and sends "hello, client", and then exits

The end tag can also be used here writer.newLine();, but this requires the other party to read and must use it 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();//关闭
    }
}

Application Case 4

  1. Write a server, and a client
  2. The server listens on port 8888
  3. The client connects to the server and sends a picture e:llqie.png
  4. The server receives the picture sent by the client, saves it under src, sends "received picture" and then exits
  5. The client receives the "picture received" sent by the server, and then exits
  6. The program requires the use of StreamUtils.java, and we directly use the method encapsulated in it.

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();
      
   }

}

netstat command

  1. netstat -anYou can view the current host network conditions, including project port monitoring and network connection conditions
  2. netstat -an | moreCan be displayed in pages
  3. netstat -anb(Run as administrator) to see which applications are listening on the port.
  4. The external address is the IP and port number of the client connecting to the local address and port number.

illustrate:

(1) Listening means that a certain port is listening to Established means that the connection has been established

(2) If there is an external program (client) connected to the port, a connection message will be displayed

TCP network communication

  1. When the client connects to the server, the client actually communicates with the server through a port. This port is allocated by TCP/IP, which is uncertain and random. ( client's port )
  2. Program verification + netstat

UDP network communication programming

basic introduction

  1. The class DatagramSocketand DatagramPacket[packet/datagram] implements
    a network program based on the UDP protocol.

  2. UDP datagrams are sent and received through datagram sockets DatagramSocket. The system does not guarantee that UDP datagrams will be delivered safely to their destinations, nor can they determine when they will arrive.

  3. DatagramPacketThe object encapsulates the UDP datagram, and the datagram contains the IP address and
    port number of the sending end and the IP address and port number of the receiving end.

  4. Each datagram in the UDP protocol gives complete address information, so there is no need to establish
    a connection between the sender and the receiver

basic process

  1. The two core classes/objects DatagramSocket and DatagramPacket
  2. Establish the sender and receiver (no server and client concept)
  3. Before sending data, create a data packet/report DatagramPacket object
  4. Call the sending and receiving methods of DatagramSocket
  5. Close DatagramSocket

Applications

  1. Write a receiver A, and a sender B
  2. Receiver A waits to receive data on port 9999 (receive)
  3. The sender B sends data to the receiver A "hello, eat hot pot tomorrow~"
  4. Receiver A receives the data sent by sender B, replies "OK, see you tomorrow" and exits
  5. The sender receives the reply data, and then exits
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端退出");
    }
}

Homework for this chapter

1. Programming questions

(1) Write a client program and a server program using character streams,

(2) The client sends "name" and the server returns "I am nova" after receiving it. Nova is your own name.

(3) The client sends "hobby", and the server returns "write java program" after receiving it

(4) Not these two questions, reply "What are you talking about?"

Question: At present, we can only ask once and quit. How can we ask multiple times? ->while ->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. Programming questions

(1) Write a receiver A and a sender B, using the UDP protocol to complete

(2) The receiving end is waiting to receive data on port 8888 (receive)

(3) The sending end sends data to the receiving end "Which are the four great classics"

(4) After the receiving end receives the question sent by the sending end, it returns "The Four Great Masterpieces are <<Dream of Red Mansions>>...", otherwise it returns what?

(5) Receiver and sender programs exit

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. Programming questions

(1) Write client program and server program

(2) The client can input a music file name, such as Gaoshan Liushui. After receiving the music name, the server can return the music file to the client. If the server does not have this file, just return a default music.

(3) After the client receives the file, save it to the local e:\\

(4) Tip: This program can use 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();
   }
}

Guess you like

Origin blog.csdn.net/m0_52316372/article/details/130573037