Skip to content

第八章 网络编程 v1.0 ​

第一部分 网络通信 ​

一、网络通信基本模式 ​

1.Client-Server(CS) ​

image.png

2.Brower-Server(BS) ​

image.png

二、网络通信三要素 ​

1.IP地址 ​

设备在网络中的地址,是唯一的标识

IPv4:32位(4字节):分为4个整数,使用点分十进制表示

IPv6:128位(16字节):分为8个整数,每个用4个十六进制数表示,用冒号隔开

IP地址操作类(InetAddress) ​

2.端口号 ​

应用程序在设备中唯一的标识

标识正在计算机设备上运行的进程(程序),被规定为一个16位的二进制,范围是0~65535

常用端口号:HTTP:80;HTTPS:443;FTP:21

3.协议 ​

数据在网络中传输的规则,常见的协议有UDP协议和TCP协议

OSI参考模型:世界互联协议标准,全球通信规范,由于此模型过于理想化,未能在因特网上进行广泛推广。

TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

image.png

第二部分 UDP通信 ​

一、UDP相关API ​

1.数据包对象(DatagramPacket) ​

构造函数:

  1. DatagramPacket(byte[] b, int length, InetAddress ip, int port):创建发送端数据包对象
  2. DatagramPacket(byte[] b, int length):创建接收端数据包对象

常用方法:

getLength():获得实际接收到的字节个数

2.套接字对象(DatagramSocket) ​

构造函数:

  1. DatagramSocket():常用于创建发送端Socket对象,系统随机分配一个端口号
  2. DatagramSocket(int port):常用于创建接收端Socket对象,指定分配端口号

常用方法:

  1. send(DatagramPacket p):发送数据包
  2. receive(DatagramPacket p):接收数据包

二、发送端与服务端 ​

1.发送端 ​

java
public class Server {
    public static void main(String[] args) throws Exception {
        //创建发送端对象
        DatagramSocket socket = new DatagramSocket();
        Scanner sc = new Scanner(System.in);
        String input;
        while (!Objects.equals(input = sc.nextLine(), "exit")) {
            byte[] buffer = input.getBytes();
            //创建数据包(指定长度,发送IP地址与端口)
            DatagramPacket packet = new DatagramPacket(buffer, 
                                                       buffer.length, 
                                                       InetAddress.getLocalHost(), 
                                                       8888);
            //发送数据包
            socket.send(packet);
        }
        socket.close();
    }
}

2.服务端 ​

java
public class Client {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8888);
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        while (true) {
            socket.receive(packet);
            System.out.println(new String(buffer, 0, packet.getLength()));
        }
    }
}

三、UDP三种通信方式 ​

1.单播 ​

单台主机与单台主机之间的通信

2.广播 ​

当前主机与所在网络中的所有主机通信,广播地址:255.255.255.255

发送端:发送的数据包的目的地写的是广播地址(255.255.255.255)、且指定端口。

接收端:所在网段的其他主机的程序只要匹配端口成功即就可以收到消息了。

3.组播 ​

当前主机与选定的一组主机的通信,组播地址:224.0.0.0~239.255.255.255

发送端:数据包的目的地是组播IP(224.0.0.1~239.255.255.255)

接收端:必须绑定该组播IP,端口对应发送端的目的端口,即可接收该组播消息

java
//接收端
MulticastSocket socket = new MulticastSocket(8888);  //DatagramSocket的子类
socket.joinGroup(InetAddress.getByName("224.0.0.1"));  //绑定组播IP

第三部分 TCP通信 ​

一、套接字对象 ​

1.发送端(客户端) ​

构造方法:

Socket(String host, int port):创建一个发送消息的TCP对象,指定连接端口

常用方法:

getOutputStream():从通信管道中得到一个字节输出流(对应发送端)

getInputStream():从通信管道中得到一个字节输入流(对应接收端)

2.接收端(服务端) ​

构造方法:

ServerSocket(int port):构建一个用于构建接收的TCP连接的对象的对象

常用方法:

accept():由该对象生成Socket对象

3.基本概念 ​

  • 客户端怎么发,服务端就应该怎么收,客户端如果没有消息,服务端会进入阻塞等待。
  • Socket一方关闭或者出现异常、对方Socket也会失效或者出错。

二、构建TCP连接 ​

1.示例(点对点) ​

java
public class Client {
    public static void main(String[] args) throws Exception {
        try (
                Socket socket = new Socket("127.0.0.1", 5000);
        ) {
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);
            String s;
            Scanner sc=new Scanner(System.in);
            while(true){
                s=sc.nextLine();
                ps.println(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
java
public class Server {
    public static void main(String[] args) throws Exception {
        try (
                ServerSocket serverSocket=new ServerSocket(5000);
        ) {
            Socket socket = serverSocket.accept();
            InputStream is = socket.getInputStream();
            BufferedReader bs = new BufferedReader(new InputStreamReader(is));
            String msg;
            while((msg=bs.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress()+":"+msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.服务端处理多个客户端消息 ​

单线程每次只能处理一个客户端的Socket通信,需要引入多线程(线程池)优化

java
public class Server {
    static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());
    public static void main(String[] args) throws Exception {
        try (
                ServerSocket serverSocket = new ServerSocket(5000);
        ) {
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + ":上线了");
                Runnable target = new ServerReaderRunnable(socket);
                pool.execute(target);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ServerReaderRunnable implements Runnable {
    Socket socket;
    
    ServerReaderRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            BufferedReader bs = new BufferedReader(new InputStreamReader(is));
            String msg;
            while ((msg = bs.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() + ":" + msg);
            }
        } catch (java.net.SocketException ignored) {
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.即时通信 ​

即时通信,即指一个客户端的消息发出去,其他客户端可以接收到

即时通信需要进行端口转发的设计思想,服务端需要把在线的Socket管道存储起来,一旦收到一个消息要推送给其他管道