吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2255|回复: 25
收起左侧

[学习记录] 【自学笔记】 Java基础 - 网络基础

  [复制链接]
LongJL 发表于 2021-7-22 19:04
本帖最后由 LongJL 于 2021-7-22 19:24 编辑

网络编程

概述

  • 在网络通信协议下,不同计算机上运行的程序,可以进行数据传输。

三要素

IP地址

  • 设备在网络中的地址,是唯一的标识
  • 全称"互联网协议地址",也称IP地址。是分配给上网设备的数字标签。常见的IP分类为:ipv4和ipv6

    端口

  • 应用程序在设备在唯一的标识
端口号

用俩个字节表示的整数,它的取值范围是0~65535,其他0~1023之间的端口号用于一些知名的网络服务或者应用,一遍使用1024以上的端口就行。 一个端口号只能被一个应用程序使用。

协议

  • 数据在网络中传输的规则,常见的协议又UDP协议和TCP协议
UDP协议
  • 用户数据报协议(User Datagram Protocal)
  • UDP是面向无连接通信协议,速度快,有大小限制一次最多发送64K,数据不安全,易丢失
TCP协议
  • 传输控制协议(Transmission Control Protocal)
  • TCP协议是面向连接的通信协议。速度慢,没有大小限制,数据安全。

InetAddress类

方法

  • public static InetAddress getByName(String host):确定主机名称的IP地址。
  • public String getHostName():获取此IP地址的主机名。
  • public String getHostAddress():返回文本显示中的IP地址字符串
public class InetAddressDemo1 {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress address = InetAddress.getByName("LAPTOP-FHMDM194");

        // 主机名
        String hostName = address.getHostName();
        System.out.println(hostName);

        // ip
        String ip = address.getHostAddress();
        System.out.println(ip);
    }
}

UDP通信程序

UDP的三种通信方式

  • 单播
  • 组播
  • 广播

单播

发送步骤
  1. 创建发送端的DatagramSocket对象
    DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
  2. 创建数据,并把数据打包(DatagramPacket)
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
    参数介绍:
    buf:要发送的数据
    length:你要把数组中多少个数据发送过去
    address:接收端
    port:接收端的端口号
  3. 调用DatagramSocket对象的方法发送数据
  4. 释放数据
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();

        byte[] bytes = "发送的信息".getBytes();
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 10000;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

        ds.send(dp);

        ds.close();
    }
}
接收步骤
  1. 创建接收端的DatagramSocket对象
    DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口。
  2. 创建个变量,接收数据
    DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket用于接收长度的数据包 length 。
  3. 调用DatagramSocket的方法接收数据并把数据放入箱子中
  4. 解析数据包
  5. 释放资源
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 指定一个端口号,接收发送端发送的数据
        DatagramSocket ds = new DatagramSocket(10000);

        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);

        ds.receive(dp);

        byte[] data = dp.getData();
        int length = dp.getLength();

        System.out.println(new String(data,0,length));

        ds.close();
    }
}
注意事项
  1. 在运行的过程中,需要先运行接收端,然后再去运行发送端
  2. 接收端启动后,如果发送端没有发送数据,就会处于等待状态
  3. 在接收数据的时候,可以调用getLength的方法,可以获取接收数据的长度

组播

组播地址:224.0.0.0 ~ 239.255.255.255,其中224.0.0.0 ~ 224.0.0.255为预留的组播地址

发送步骤
  1. 创建发送端的DatagramSocket对象
    DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
  2. 创建数据,并把数据打包(DatagramPacket)
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
    参数介绍:
    buf:要发送的数据
    length:你要把数组中多少个数据发送过去
    address:接收端
    port:接收端的端口号
  3. 调用DatagramSocket对象的方法发送数据,发送给组播地址
  4. 释放数据

    public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
    
        byte[] bytes = "组播发送".getBytes();
        InetAddress address = InetAddress.getByName("224.0.1.0");
        int post = 8888;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,post);
    
        ds.send(dp);
    
        ds.close();
    }
    }
接收步骤
  1. 创建接收端的MulticastSocket对象
    MulticastSocket(int port)创建组播套接字并将其绑定到特定端口。
  2. 创建个变量,接收数据
    DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket用于接收长度的数据包 length 。
  3. 调用DatagramSocket的方法接收数据并把数据放入箱子中
  4. 解析数据包
  5. 释放资源
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        MulticastSocket ms = new MulticastSocket(8888);

        DatagramPacket dp = new DatagramPacket(new byte[1024],1024);

        // 把当前计算机绑定一个组播地址,表示添加到这一组中
        ms.joinGroup(InetAddress.getByName("224.0.1.0"));

        ms.receive(dp);

        byte[] data = dp.getData();
        int length = dp.getLength();

        System.out.println(new String(data,0,length));

        ms.close();
    }
}

广播

广播地址:255.255.255.255

发送步骤
  1. 创建发送端的DatagramSocket对象
    DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
  2. 创建数据,并把数据打包(DatagramPacket)
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
    参数介绍:
    buf:要发送的数据
    length:你要把数组中多少个数据发送过去
    address:接收端
    port:接收端的端口号
  3. 调用DatagramSocket对象的方法发送数据,发送给广播地址
  4. 释放数据

    
    public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 指定一个端口号,接收发送端发送的数据
        DatagramSocket ds = new DatagramSocket(8888);
    
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
    
        ds.receive(dp);
    
        byte[] data = dp.getData();
        int length = dp.getLength();
    
        System.out.println(new String(data,0,length));
    
        ds.close();
    }
    }

#### 接收步骤
1. 创建接收端的DatagramSocket对象
        `DatagramSocket(int port)`构造数据报套接字并将其绑定到本地主机上的指定端口。
2. 创建个变量,接收数据
        `DatagramPacket(byte[] buf, int length)`构造一个 DatagramPacket用于接收长度的数据包 length 。 
3. 调用DatagramSocket的方法接收数据并把数据放入箱子中
4. 解析数据包
5. 释放资源

```Java
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();

        byte[] bytes = "广播发送".getBytes();
        InetAddress address = InetAddress.getByName("255.255.255.255");
        int post = 8888;
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,post);

        ds.send(dp);

        ds.close();
    }
}

TCP通信程序

TCP通信协议是一个可靠的网络协议,它在通信的俩端各简历一个Socket对象
客户端用的类为Socket,服务端用的类为ServerSocket

发送数据步骤

  1. 创建客户端的Socket对象与指定服务器连接
    Socket(String host, int port):创建流套接字并将其连接到指定主机上的指定端口号。
  2. 获取输出流,写数据
    public OutputStream getOutputStream():返回此套接字的输出流。
  3. 释放资源
    void close()
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);

        OutputStream outputStream = socket.getOutputStream();

        outputStream.write("hello".getBytes());

        // 释放资源
        outputStream.close();
        socket.close();
    }
}

接收数据步骤

  1. 创建服务器端的Socket对象(ServerSocket)
    ServerSocket(int port)创建绑定到指定端口的服务器套接字。
  2. 监听客户端连接,返回一个Socket对象
    Socket accept()
    注:执行到这一步的时候,如果没有客户端来连接就会发送阻塞。
  3. 获取输入流,读数据,并把数据显示在控制台
    InputStream getInputStream()

    
    public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);
    
        Socket accept = ss.accept();
    
        InputStream inputStream = accept.getInputStream();
    
        int b;
        while ((b= inputStream.read()) != -1){
            System.out.println((char)b);
        }
    
        inputStream.close();
        ss.close();
    }
    }

#### 注意事项
1. accept方法是阻塞的,它的作用就等待客户端连接。
2. 客户端创建对象并连接服务器,此时是通过三次握手协议保证跟服务器之间的连接。
3. 对于客户端而言,是往外写的,所以是输出流,对于服务器而言,是往里读的,所以是输入流
4. read方法也是阻塞的
5. 在关闭客户端输出流的时候,会自动往服务器写一个结束标记的动作。
6. 通过四次挥手保证连接终止

#### 三次握手
1. 客户端向服务器发送链接请求(等待服务器确认)
2. 服务器向客户端返回一个响应(告诉客户端收到了请求)
3. 客户端向服务器再次发送确认信息(建立连接)

#### 四次挥手
1. 客户端向服务器发出取消连接请求
2. 服务器向客户端返回一个响应(表示收到客户端取消请求)
3. 第二次发送完得时候会去处理数据,处理完了再次向客户端发送确认取消信息
4. 客户端再次发送确认消息(连接取消)

#### TCP小练习

```Java
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);

        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello".getBytes());
        socket.shutdownOutput();// 仅仅关闭输出流,并写一个结束标记,对socket没有任何影响

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 字节转字符
        String line;
        while ((line = br.readLine())!=null){
            System.out.println(line);
        }
        br.close();
        outputStream.close();
        socket.close();
    }
}

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);

        Socket accept = ss.accept();

        InputStream inputStream = accept.getInputStream();

        int b;

        while ((b= inputStream.read())!=-1){
            System.out.println((char)b);
        }

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream())); // 字节转字符
        bw.write("你谁啊");
        bw.newLine();
        bw.flush();

        bw.close();
        inputStream.close();
        accept.close();
        ss.close();
    }
}

文件上传

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);

        // 本地流,读取本地文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\FileTest\\1.mp4"));

        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);

        int b;
        while ((b=bis.read())!= -1){
            bos.write(b); // 通过网络写到服务器
        }

        // 给服务器结束标记
        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        bis.close();
        socket.close();

    }
}
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);

        Socket accept = ss.accept();

        // 网络中的流
        BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\FileTest\\copy\\1.mp4"));

        int b;

        while ((b = bis.read()) != -1){
            bos.write(b);
        }

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("上传成功");
        bw.newLine();
        bw.flush();

        accept.close();
        ss.close();
        bos.close();
    }
}

服务端优化

  • 使用死循环让服务器保持一直运行
  • 使用UUID来确保文件的唯一性
  • 使用多线程可以处理多个客户端请求
  • 在使用线程池优化多线程的资源消耗过大的问题

UUID

一个表示不可变的通用唯一标识符(UUID)的类。 UUID表示128位值。

方法

  • public static UUID randomUUID() 静态工厂检索一个类型4(伪随机生成)的UUID。 UUID是使用加密强伪随机数生成器生成的。
  • String toString() 返回代表这个 UUID的 String对象
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,// 核心线程数量
                10,// 线程池的总数量
                60,// 临时线程的空闲时间
                TimeUnit.SECONDS,// 临时线程的空闲时间单位
                new ArrayBlockingQueue<>(5),//阻塞队列
                Executors.defaultThreadFactory(),//创建线程的方式
                new ThreadPoolExecutor.AbortPolicy()// 任务拒绝策略
        );
        while (true) {
            Socket accept = ss.accept();
            ThreadSocket ts = new ThreadSocket(accept);
//            new Thread(ts).start();
            pool.submit(ts);
        }
//        ss.close();
    }
}
public class ThreadSocket implements Runnable {
    private Socket acceptSocket;
    public ThreadSocket(Socket accept) {
        this.acceptSocket = accept;
    }

    @Override
    public void run() {
        BufferedOutputStream bos = null;
        try {
            // 网络中的流
            BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream("D:\\FileTest\\copy\\"+ UUID.randomUUID().toString().replace("-","") +".mp4"));
            int b;

            while ((b = bis.read()) != -1){
                bos.write(b);
            }
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (acceptSocket != null){
                try {
                    acceptSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);

        // 本地流,读取本地文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\FileTest\\1.mp4"));

        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(outputStream);

        int b;
        while ((b=bis.read())!= -1){
            bos.write(b); // 通过网络写到服务器
        }

        // 给服务器结束标记
        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        bis.close();
        socket.close();

    }
}

免费评分

参与人数 5吾爱币 +5 热心值 +4 收起 理由
柑桔 + 1 + 1 谢谢@Thanks!
liuli123 + 1 鼓励转贴优秀软件安全工具和文档!
hwq + 1 + 1 我很赞同!
abc126 + 1 + 1 谢谢@Thanks!
好萌一只大辉宝 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

好萌一只大辉宝 发表于 2021-7-22 19:10
有用,刚好在学
qiokio 发表于 2021-7-22 19:25
头像被屏蔽
偶尔平凡 发表于 2021-7-22 19:26
letoto 发表于 2021-7-22 20:04
web前端想转java
daytripper 发表于 2021-7-22 20:15
刚好需要学习下java,感谢楼主
gaifan 发表于 2021-7-22 21:06
谢谢分享
MCQI 发表于 2021-7-22 21:08
想看看,想看看
KevINBy 发表于 2021-7-22 21:24
受教了,感谢分享
SuBaiQiao 发表于 2021-7-22 21:24
谢谢分享,很与价值!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-26 00:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表