Java 进阶day12 网络编程、TCP、UDP、模拟B\S服务器、BIO和NIO

知识点1、网络编程

网络编程概述:

实现不同计算机上进行数据传输的程序。

网络编程三要素:(IP地址、端口号、协议)

IP地址找到电脑、端口号找到程序、协议传输数据

IP地址

IP地址: 指互联网协议地址(Internet Protocol Address),俗称IP。
IP地址用来给一个网络中的计算机设备做唯一的编号(相当于手机号码)。

IPV4

是一个32位的二进制数,通常被分为4个字节,表示成 a.b.c.d 的形式,例如 192.168.65.100。其中 a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。

IPV6

由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制 数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789

IP地址介绍

查看本机IP地址
在DOS命令行输入: ipconfig

检查网络是否连通
在DOS命令行输入: ping IP地址

特殊IP地址
127.0.0.1:是回送地址也称本地回环地址,可以代表本机的IP地址,一般用来测试使用

端口介绍

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

端口号: 用两个字节表示的整数,它的取值范围是0~65535。
其中0~1023之间的端口号用于一些知名的网络服务或者应用。
使用1024以上的端口号就可以了。

注意:
一个端口号只能被一个应用程序使用。

协议介绍

传输层协议:UDP、TCP

UDP协议

用户数据报协议(User Datagram Protocol)

1、不需要连接
2、速度快
3、有大小限制,一个包最多发送64K (如果大于64K,会自动拆成多个包发送)
4、易丢失数据

适用场景:
直播、语音通话、视频会话

TCP协议(重点)

传输控制协议(Transmission Control Protocol)

1、需要连接
2、速度慢
3、没有大小限制(以流的形式传输数据)
4、不易丢失数据

适用场景:
对信息安全要求较高的场景,下载、金融等数据通信

InetAddress类的使用
在这里插入图片描述
静态方法,用类名调用

		// 获取本机IP地址对象
        InetAddress host = InetAddress.getLocalHost();
        // 获取主机名
        String hostName = host.getHostName();
        // 获取IP地址字符串
        String hostAddress = host.getHostAddress();

知识点2、UDP通信

发送端
发送的是二进制数据
接收端
1、创建发送端
2、创建一个数据包
3、发送数据包
1、创建接受端
2、创建空的数据包
3、接受数据

发送端不需要端口号,接收端需要端口号
发送端 DatagramSocket()
接收端 DatagramSocket(int post)

创建发送的数据包
DatagramPacket​(byte[] buf, int offset, int length, InetAddress address, int port)
创建接收的数据包
DatagramPacket​(byte[] buf, int length)

UDP发送端

步骤:
1、创建发送端
2、创建数据包
3、发送数据
4、关流

public class UDPSender {
    public static void main(String[] args) throws IOException {
        // 1.创建发送端
        DatagramSocket socket = new DatagramSocket();

        // 2.创建数据包
        byte[] bytes = "你好UDP!".getBytes();
        DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, InetAddress.getLocalHost(), 10011);

        // 3.发送数据
        socket.send(packet);

        socket.close();
    }
}

UDP接收端

步骤:
1、创建接收端
2、创建空的数据包
3、接收数据
4、关流

public class UDPReceiver {
    public static void main(String[] args) throws IOException {
        // 1.创建接收端
        DatagramSocket socket = new DatagramSocket(10011);

        // 2.创建空的数据包
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        // 3.接收数据
        socket.receive(packet); // 没有数据会一直等待,阻塞式方法
        int len = packet.getLength(); // 接收到数据的长度
        System.out.println("接收到数据: " + new String(buf, 0, len));

        socket.close();
    }
}

注意:
1、先有接收端,然后再运行发送端
2、接收端:没有数据会一直等待,阻塞式方法


知识点3、TCP通信

TCP协议通信需要连接,建立连接后以流的形式传输

在这里插入图片描述客户端

步骤:
1、创建客户端
2、写数据
3、读数据
4、关流

public class TCPClient {
    public static void main(String[] args) throws IOException {
        //  1、创建客户端
        Socket client = new Socket(InetAddress.getLocalHost(), 10011);
        
        //   2、写数据
        OutputStream out = client.getOutputStream();
        out.write("约吗?".getBytes());
        
        //    3、读数据
        InputStream in = client.getInputStream();
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));
        
        //   4、关流
        in.close();
        out.close();
        client.close();

    }
}

服务端

步骤:
1、创建服务端
2、接收请求
3、读数据
4、写数据
5、关流

public class TCPServer {
    public static void main(String[] args) throws IOException {
        System.out.println("服务端启动了");
        //  创建服务端
        ServerSocket server = new ServerSocket(10011);

        //   接收请求
        Socket socket = server.accept();  // 没有客户端连接的时候会一直停在这里

        //   读数据
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));

        //    写数据
        OutputStream out = socket.getOutputStream();
        out.write("不约?滚".getBytes());

        //关流
        out.close();
        in.close();
        socket.close();
        server.close();
    }
}

注意:
1、socket的流能做循环的时候无法停下来,需要在客户端调用 shutdownOutput()
2、服务端返回的socket 和客户端的socket 不同,是新建一个socket。
3、先运行服务端,再运行客户端。
4、socket.accept() 服务端没有客户端连接会一直等待,阻塞式方法。


案例1:传输文件

客户端

public class UploadClient {
    public static void main(String[] args) throws IOException {
        System.out.println("文件上传客户端启动啦!");
        // 1.创建客户端
        Socket socket = new Socket("127.0.0.1", 33445);
        // 2.创建文件输入流
        FileInputStream fis = new FileInputStream("D:\\MyFileTest\\xyz.png");

        // 3.得到Socket的输出流
        OutputStream out = socket.getOutputStream();

        // 4.循环读写数据
        byte[] buf = new byte[1024]; // 保存读取的数据
        int len; // 保存读取的数量
        while ((len = fis.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
        socket.shutdownOutput(); // 告诉socket这个流没有数据啦
        System.out.println("客户端发送完成!");

        // 5.得到Socket输入流读取数据
        InputStream in = socket.getInputStream();
        len = in.read(buf); // 读取多个字节,读取到的数据保存buf中,读取的数量赋值给len
        System.out.println("客户端收到: " + new String(buf, 0, len));

        // 6.关闭资源
        in.close();
        out.close();
        fis.close();
        socket.close();
    }
}

服务端

public class UploadServer {
    public static void main(String[] args) throws IOException {
        System.out.println("文件上传服务端启动啦!");
        // 1.创建服务端
        ServerSocket ss = new ServerSocket(33445);
        // 2.同意客户端的连接
        Socket socket = ss.accept();
        // 3.得到Socket输入流
        InputStream in = socket.getInputStream();

        // 4.创建文件输出流
        // UUID生成一个随机的字符串
        String fileName = UUID.randomUUID().toString();
        FileOutputStream fos = new FileOutputStream("study_day12\\upload\\" + fileName + ".png");
        // 5.循环读写数据
        byte[] buf = new byte[1024]; // 保存读取到的数据
        int len; // 保存读取的数量
        while ((len = in.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        System.out.println("接收完毕!");

        // 6.得到Socket的输出流写数据
        OutputStream out = socket.getOutputStream();
        out.write("上传完成!".getBytes());

        // 7.关闭
        out.close();
        fos.close();
        in.close();
        socket.close();
        ss.close();
    }
}

在这里插入图片描述在这里插入图片描述
注意:

1、客户端的循环读写结束了,但是服务端的循环读写没有结束 ,需要在客户端中调用 shutdownOutput()

2、原因:
客户端在读写的时候,fis在读数据,fis是文件输入流,当读取不到数据会返回-1,可以结束循环
服务端在读写数据的时候,in在读数据,in是socket的输入流,当读取不到数据,会一直等待

3、怎么解决?
客户端切断流 shutdownOutput() // 告诉客户端这个流没有数据

4、解决文件重名的问题
String fileName = UUID.randomUUID().toString()

知识点4、模拟B\S服务器

HTTP 超文本传输协议
HTTP协议对TCP协议进行封装,需要按照HTTP规则收发数据

网站服务器的核心原理:
网站服务器是TCP服务端,发送数据给浏览器,浏览器显示

public class WebServer {
    public static void main(String[] args) throws IOException {
        // 网站服务器就是TCP服务端
        ServerSocket ss = new ServerSocket(6688);
        while (true) {
            Socket socket = ss.accept();
            System.out.println("有人连接啦!: " + socket);

            // 给浏览器回数据
            // HTTP协议对TCP协议进行了封装,我们需要按照HTTP的规则收发数据
            OutputStream out = socket.getOutputStream();
            out.write("HTTP/1.1 200 OK\r\n".getBytes());
            out.write("Content-Type:text/html\r\n".getBytes());
            out.write("\r\n".getBytes());

            // 再把服务器上的web\index.html发送给浏览器
            FileInputStream fis = new FileInputStream("F:\\Demo\\index.html");
            byte[] buf = new byte[1024];
            int len;
            while ((len = fis.read(buf)) != -1) {
                out.write(buf, 0, len);
            }

            fis.close();
            out.close();
            socket.close();
        }
    }
}

在浏览器中输入: http://127.0.0.1:6688
http:// 是超文本传输协议,可以传输文字图片,视频等等资源
127.0.0.1: 服务器的IP地址
6688: 服务器的端口号

知识点5、BIO和NIO

JDK1.4以前:InputStream/OutputStream称为BIO(Blocking IO) 阻塞式IO
JDK1.4推出了一套新的IO体系称为NIO (New IO/ Not Blocking IO) 非阻塞式IO

阻塞: 如果没有数据就一直等待
非阻塞: 如果没有数据,不会一直等待,可以做其他事情
非阻塞的好处,不需要一直等待,当有数据来才需要处理,没有数据可以做其他操作

BIO 两个单向的流

在这里插入图片描述

NIO 双向传输数据

在这里插入图片描述
NIO 3个角色:

1、Channel(通道)可以双向传输数据

2、 ByteBuffer 相当于之前BIO的byte[],可以保存要发送和接收的数据
ByteBuffer 效率比byte[]要高,功能更强大

3、Selector 选择器,可以管理多个连接
使用了多路复用,只需要一个线程就可以处理
多个通道,降低内存占用率,减少CPU切换时间,
在高并发、高频段业务环境下有非常重要的优势

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

halulu.me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值