Day12、网络通信三要素-TCP实战

Day11、网络通信三要素-TCP实战

网络编程:

  • 网络编程可以让程序与网络上的其他设备中的程序进行数据交互。

网络通信基本模式:

  • 常见的通信模式有如下2中形式:Client-Server(CS),Browser/server(BS)

网络编程需要学会什么:

网络通信三要素

实现网络编程关键的三要素

  • IP 地址: 设备在网络中的地址,是唯一的标识。

  • 端囗: 应用程序在设备中唯一的标识。

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

IP地址:

  • IP(lnternet Protocol) : 全称” 互联网协议地址” ,是分配给上网设备的唯一标志。

  • 常见的甲分类为:IPv4 和IPv6

IPV4:

IPV6:128位(16个字节),分为8个整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开。

IP地址基本寻路:

IP地址形式:

  • 公网地址、和私有地址( 局域网使用) 。

  • 192 .168 .开头的就是常见的局域网地址,范围即为192.168.0.0一192 .168.255.255,专门为组织机构内部使用。

IP常用命令:

  • ipconfig : 查看本机IP地址

  • ping IP地址: 检查网络是否连通

特殊IP地址:

  • 本机IP :127.0.0.1 或者localhost : 称为回送地址也可称本地回环地址, 只会寻找当前所在本机。

总结:

InetAddress 的使用

  • 此类表示Internet协议(IP) 地址。

InetAddress API如下

名称 说明
public static InetAddress getLocalHost() 返回本主机的地址对象
public static InetAddress getByName(String host) 得到指定主机的IP地址对象, 参数是域名或者IP地址
public String getHostName() 获取此IP地址的主机名
public String getHostAddress() 返回IP地址字符串
public boolean isReachable(int timeout) 在指定毫秒内连通该IP地址对应的主机, 连通返回true
public static void main(String[] args) throws Exception {
    //1.获取本机的地址对象
    InetAddress ip1 = InetAddress.getLocalHost();
    System.out.println(ip1);//cafune 172.31.247.149
    System.out.println(ip1.getHostName());//cafune
    System.out.println(ip1.getHostAddress());//172.31.247.149

    //2.获取域名ip对象
    InetAddress ip2 = InetAddress.getByName("www.baidu.com");
    System.out.println(ip2.getHostName());
    System.out.println(ip2.getHostAddress());

    //3.获取公网ip对象
    InetAddress ip3 = InetAddress.getByName("110.242.68.4");
    System.out.println(ip3.getHostName());
    System.out.println(ip3.getHostAddress());

    //4.判断能否接通:ping 5s内接通返回true
    System.out.println(ip3.isReachable(5000));
}

总结:

端囗号

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

端囗类型

  1. 周知端口: 0-1023,被预先定义的知名应用占用( 如: HTTP占用80 , FTP 占用21 )

  2. 注册端囗: 1024-49151, 分配给用户进程或某些应用程序。( 如: Tomcat 占用8080 ,MySQL 占用3306 )

  3. 动态端口: 49152到65535,之所以称为动态端口,是因为它一般不固定分配某种进程,而是动态分配。

注意: 我们自己开发的程序选择注册端囗且一个设备中不能出现两个程序的端囗号一样否则出错。

通信协议:

  • 连接和通信数据的规则被称为网络通信协议

网络通信协议有两套参考模型

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

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

传输层的2个常见协议

  1. TCP(Transmission Contr01 protocol) :传输控制协议

  2. UDP(User Datagram Protocol) : 用户数据报协议

TCP 协议特点:

  1. 使用TCP 协议, 须双方先建立连接, 它是一种面向连接的可靠通信协议。

  2. 传输前, 采用" 三次握手“ 方式建立连接, 所以是可靠的。

  3. 在连接中可进行大数据量的传输。

  4. 连接、发送数据都需要确认, 且传输完毕后, 还需释放已建立的连接, 通信效率较低。

TCP 协议通信场景

  • 对信息安全要求较高的场景, 例如: 文件下载、金融等数据通信。

TCP三次握手确立连接:

TCP四次挥手断开连接

UDP 协议:

  1. UDP 是一种无连接、不可靠传输的协议。

  2. 将数据源IP、目的地IP 和端口封装成数据包, 不需要建立连接

  3. 每个数据包的大小限制在64KB内

  4. 发送不管对方是否准备好, 接收方收到也不确认, 故是不可靠的

  5. 可以广播发送, 发送数据结束时无需释放资源, 开销小, 速度快。

UDP 协议通信场景:

  • 语音通话, 视频会话等

总结:

UDP通信-快速入门

UDP协议的特点:

  1. UDP 是一种无连接、不可靠传输的协议。

  2. 将数据源IP、目的地IP 和端口封装成数据包, 不需要建立连接

  3. 每个数据包的大小限制在64KB内,直接发送出去即可

DatagramPacket:数据包对象( 韭菜盘子)

构造器 说明
public DatagramPacket(byte[] buf,int length, InetAddress address,int port) 创建发送端数据包对象
buf: 要发送的内容, 字节数组
length: 要发送内容的字节长度
address: 接收端的IP 地址对象
port : 接收端的端口号
public DatagramPacket(byte[] buf,int length) 创建接收端的数据包对象
buf: 用来存储接收的内容
length: 能够接收内容的长度

DatagramPacaket常用方法:

方法 说明
public int getLength() 获得实际接收到的字节个数

DatagramSocket : 发送端和接收端对象( 人)

构造器 说明
public DatagramSocket() 创建发送端的socket 对象, 系统会随机分配一个端口号。
public DatagramSocket(int port ) 创建接收端的socket 对象并指定端口号

DatagramSocket 类成员方法

方法 说明
public void send(DatagramPacket dp) 发送数据包
public void receive(DatagramPacket p) 接收数据包

总结:

案例:使用udp通信实现:多发多收消息

步骤:发送端可以反复发送数据

步骤:接收端可以反复接收数据

总结:

UDP通信-广播、组播

UDP 的三种通信方式

  • 单播: 单台主机与单台主机之间的通信。

  • 广播: 当前主机与所在网络中的所有主机通信。

  • 组播: 当前主机与选定的一组主机的通信。

UDP 如何实现广播

使用广播地址: 255.255.255.255

具体操作:

  1. 发送端发送的数据包的目的地写的是广播地址、且指定端口。( 255.255.255.255,9999)
  2. 本机所在网段的其他主机的程序只要匹配端口成功即就可以收到消息了。( 9999 )

UDP 如何实现组播

使用组播地址:224.0.0.0 ~ 239.255.255.255

具体操作:

  1. 发送端的数据包的目的地是组播IP( 例如:224.0.1.1,端口: 9999 )
  2. 接收端必须绑定该组播IP ( 224.0.1.1 ), 端口还要对应发送端的目的端口9999 , 这样即可接收该组播消息。
  3. DatagramSocket 的子类MulticastSocket 可以在接收端绑定组播IP。
public static void main(String[] args) throws Exception {
        System.out.println("---启动服务端---");
        //1.创建一个接收端对象并指定端口号
        MulticastSocket socket = new MulticastSocket(9999);

        //把当前接收端加入到一个组播组中去,绑定对应组播消息的组播ip
        socket.joinGroup(InetAddress.getByName("224.0.1.1"));
        /*
        socket.joinGroup(new InetSocketAddress(InetAddress.getByName("244.0.1.1"),
                9999,NetworkInterface.getByInetAddress(InetAddress.getLocalHost())));
*/

        //2.创建一个数据包接收韭菜数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //3.等待接收数据
            socket.receive(packet);

            //4.收多少数据倒多少数据
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到了来自" + packet.getSocketAddress()
                    + "的数据," + "对方端口是:" + packet.getPort() +
                    "的消息:" + rs);
        }
    }

总结:

TCP通信-快速入门

TCP协议回顾:

  1. 使用TCP 协议, 须双方先建立连接, 它是一种面向连接的可靠通信协议。

  2. 传输前, 采用" 三次握手“ 方式建立连接, 所以是可靠的。

  3. 在连接中可进行大数据量的传输。

  4. 连接、发送数据都需要确认, 且传输完毕后, 还需释放已建立的连接, 通信效率较低。

TCP通信模式演示:socket->端

注意:在java中只要是使用java.net.Socket类实现通信,底层即是使用了TCP协议

Socket

构造器 说明
public Socket(String host,int port) 创建发送端的Socket对象与服务端连接,参数为服务端程序的ip和端口

客户端发送消息:

public class ClientDemo01 {
    public static void main(String[] args) {
        //public Socket(String host,int port)
        /*
        参数一:服务端的ip地址
        参数二:服务端的端口
         */
        try {
            //1.创建socket通信管道请求与服务器连接
            Socket socket = new Socket("172.31.247.149",7777);

            //2.从socket通信管道中得到一个输出流,负责数据输出
            OutputStream os = socket.getOutputStream();

            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            //4.发送消息
            ps.print("我是TCP的客户端,现在请求和你对接,约吗?");
            ps.flush();

            //5.关闭资源
            ps.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

总结:

ServerSocket( 服务端)

构造器 说明
public ServerSocket(int port) 注册服务端端囗

ServerSocket 类成员方法

方法 说明
public Socket accept() 等待接收客户端的socket 通信连接
连接成功返回socket 对象与客户端建立端到端通信

服务器实现消息接收

public static void main(String[] args) {
    try {
        System.out.println("------服务端启动------");
        //1.注册端口
        ServerSocket serverSocket = new ServerSocket(7777);

        //2.调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
        Socket socket = serverSocket.accept();

        //3.从socket通信管道中得到一个字节输入流
        InputStream is = socket.getInputStream();//读数据

        //4.把字节输入流包装成缓冲字符输入流进行消息的接收
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //5.按行接收消息
        String msg;
        if ((msg = br.readLine()) != null){
            System.out.println(socket.getRemoteSocketAddress() +
                    "说了:" + msg);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
        //public Socket(String host,int port)
        /*
        参数一:服务端的ip地址
        参数二:服务端的端口
         */
        System.out.println("------客户端启动------");
        try {
            //1.创建socket通信管道请求与服务器连接
            Socket socket = new Socket("172.31.247.149",7777);

            //2.从socket通信管道中得到一个输出流,负责数据输出
            OutputStream os = socket.getOutputStream();//写数据

            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            //4.发送消息
            ps.print("我是TCP的客户端,现在请求和你对接,约吗?\n");
            ps.flush();

            //5.关闭资源
            //ps.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

总结:

TCP通信-多发多收消息

案例:使用TCP通信实现:多发多收消息

总结:

TCP通信-同时接收多个客户端信息

public class ServerDemo01 {
    public static void main(String[] args) {
        try {
            System.out.println("------服务端启动------");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);

            while (true) {
                //2.每接收到一个客户端的socket管道,交给一个独立的子线程处理管道
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() +
                        "上线了!");
                //3.开始创建独立的线程处理socket
                new ServerReaderThread(socket).start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class ServerReaderThread extends Thread {
    private Socket socket;

    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();//读数据

            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            //5.按行接收消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() +
                        "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!");
        }
    }
}

总结:

TCP通信-使用线程池优化

总结:

TCP通信实战案例-即时通信

即时通信是什么含义,要实现怎么样的设计?

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

  • 之前我们的消息都是发给服务端的。

  • 即时通信需要进行端囗转发的设计思想。

  • 服务端需要把在线的Socket管道存储起来

  • 一旦收到一个消息要推送给其他管道

TCP通信实战案例-模拟BS系统

转载请注明出处:http://www.smbzepe.com/article/20230317/753641.html