Bootstrap

自制笔记 | Java基础——网络编程(持续更新...)


网络编程就是在网络通信协议下,不同计算机上运行的程序,进行的数据传输

Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序

常见的软件架构:

C/S:Client/Server(客户端 / 服务器):在用户本地需要下载并安装客户端程序,在远程有一个服务器端程序

B/S:Browser/Server(浏览器 / 服务器):只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器

在BS架构中,所有的图片、音频资源等都需要服务器传输到本地电脑上,而在CS架构中,这些资源包含在安装包内,已经在本地电脑上。因此BS架构中的图片、音频等资源一般没有CS架构中更精致

BS架构的优缺点:

① 不需要开发客户端,只需要页面 + 服务端
② 用户不需要下载,打开浏览器就能使用
③ 如果应用过大,用户体验受到影响

CS架构的优缺点:

① 画面可以做的非常精美,用户体验好
② 需要开发客户端,也需要开发服务端
③ 用户需要下载和更新的时候太麻烦

三要素:

IP:设备在网络中的地址,是唯一的标识
端口号:应用程序在设备中唯一的标识
协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp

IP

全称:Internet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签

常见的IP分类为:IPv4、IPv6

IPv4:

全称:Internet Protocol version 4,互联网通信协议第四版。采用32位地址长度,分为4组,每组的大小都是0-255(十进制),最多有2^32个IP,目前已经用完了

例如:

image-20240309114318564

IPv4的地址分类形式:

公网地址(万维网使用)和私有地址(局域网使用)。192.168.开头的就是私有地址,范围即为192.168.0.0-192.168.255.255,专门为组织机构内部使用,以此节省IP

例如:网吧中的每一台电脑共享同一个公网IP,再由路由器分享给每一台电脑不同的局域网IP

特殊IP地址:127.0.0.1,也可以是localhost:是回送地址,也称本地回环地址,也称本机IP,永远只会寻找当前所在本机

连接不同的网时,局域网可能不相同,而使用局域网地址传输数据,需要通过路由器。但若使用回送地址,则不通过路由器,因此建议练习时使用127.0.0.1地址

特殊IP地址1

特殊IP地址2

IPv6:

全称:Internet Protocol version 6,互联网通信协议第六版。由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4模式下IP的总数是有限的

采用128位地址长度,分为8组,每组2个字节大小,最多有2^128个IP,可以为地球上的每一粒沙子都设定IP

例如:

image-20240309114357472

常用的CMD命令:

ipconfig:查看本机IP地址

ping:检查网络是否连通,后面可以跟IP或网址

InetAddress类的使用:

public static void main(String[] args) throws UnknownHostException {
    /*
    * static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
    * String getHostName() 获取此IP地址的主机名
    * String getHostAddress() 返回文本显示中的IP地址字符串
    * */

    //获取InetAddress的对象
    //IP的对象 一台电脑的对象
    InetAddress address = InetAddress.getByName("小璐乱撞");
    System.out.println(address);

    String name = address.getHostName();
    System.out.println(name);

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

端口号

应用程序在设备中唯一的标识,可以理解为设备往外发送数据或者往内接收数据的接口

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

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

协议

计算机网络中,连接和通信的规则被称为网络通信协议

OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准

协议

UDP协议:

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

UDP是面向无连接通信协议(不管是否已经连接成功),速度快,有大小限制,一次最多发送64K,数据不安全,易丢失数据

应用场景:网络会议、语音通话、在线视频(允许丢失少部分数据)

TCP协议:

传输控制协议(Transmission Control Protocol)

TCP协议是面向连接通信协议,速度慢,没有大小限制,数据安全

应用场景:下载软件、文字聊天、发送邮件(一点数据都不允许丢失)

UDP通信程序:

发送数据:

① 创建发送端的DatagramSocket对象
② 数据打包(DatagramPacket)
③ 发送数据
④ 释放资源

示例:

public static void main(String[] args) throws IOException {
    //发送数据

    //1.创建DatagramSocket对象
    //细节:
    //绑定端口,以后我们就是通过这个端口往外发送数据
    //空参:所有可用的端口中随机一个进行使用
    //有参:指定端口号进行绑定
    DatagramSocket ds = new DatagramSocket();

    //2.打包数据
    String str = "小璐乱撞";
    byte[] bytes = str.getBytes();
    InetAddress address = InetAddress.getByName("127.0.0.1");
    int port = 10086;

    DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);

    //3.发送数据
    ds.send(dp);

    //4.释放资源
    ds.close();
}

接收数据:

① 创建接收端的DatagramSocket对象
② 接收打包好的数据
③ 解析数据包
④ 释放资源

示例:

public static void main(String[] args) throws IOException {
    //接收数据

    //1.创建DatagramSocket对象
    //细节:
    //在接收的时候,一定要绑定端口
    //而且绑定的端口一定要跟发送的端口保持一致
    DatagramSocket ds = new DatagramSocket(10086);

    //2.接收数据包
    byte[] bytes = new byte[1024];
    DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

    //该方法是阻塞的
    //程序执行到这一步的时候,会在这里死等
    //等发送端发送消息
    ds.receive(dp);

    //3.解析数据包
    byte[] data = dp.getData(); //这个数组和bytes是一个数组
    int length = dp.getLength();
    InetAddress address = dp.getAddress();
    int port = dp.getPort();

    System.out.println("接收到数据" + new String(data, 0, length));
    System.out.println("该数据是从" + address + "这台电脑中的" + port + "这个端口发出的");

    //4.释放资源
    ds.close();
}

UDP的三种通信方式:

① 单播

发送端只给一个设备发送数据

代码实现:之前练习的代码都是单播

② 组播

发送端给一组设备发送数据

代码实现:

组播地址:224.0.0.0 ~ 239.255.255.255,其中224.0.0.0 ~ 224.0.0.255为预留的组播地址(自己能用的)

发送端:

public static void main(String[] args) throws IOException {
    //组播发送端代码

    //创建MulticastSocket对象
    MulticastSocket ms = new MulticastSocket();

    //创建DatagramPacket对象
    String str = "小璐乱撞";
    byte[] bytes = str.getBytes();
    InetAddress address = InetAddress.getByName("224.0.0.2");
    int port = 10000;

    DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);

    //发送数据
    ms.send(dp);

    //释放资源
    ms.close();
}

接收端:

public static void main(String[] args) throws IOException {
    //创建MulticastSocket对象
    MulticastSocket ms = new MulticastSocket(10000);

    //将当前本机,添加到224.0.0.2这一组当中
    InetAddress address = InetAddress.getByName("224.0.0.2");
    ms.joinGroup(address);

    //创建DatagramPacket对象
    byte bytes[] = new byte[1024];
    DatagramPacket dp = new DatagramPacket(bytes, bytes.length);

    //接收数据
    ms.receive(dp);

    //解析数据
    byte[] data = dp.getData();
    String ip = dp.getAddress().getHostAddress();
    String name = dp.getAddress().getHostName();
    int len = dp.getLength();

    System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));

    //释放资源
    ms.close();
}

③ 广播

发送端给局域网中所有的设备发送数据

广播地址:255.255.255.255

将之前的发送端发送的IP地址改成255.255.255.255即可

InetAddress address = InetAddress.getByName("255.255.255.255");

TCP通信程序:

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通信之前要保证连接已经确立,通过Socket产生IO流来进行网络通信

image-20240309114413627

客户端:

① 创建客户端的Socket对象(Socket)与指定服务端连接

Socket(String host, int post)

② 获取输出流,写数据

OutputStream getOutputStream()

③ 释放资源

void close()

服务器:

① 创建服务器端的Socket对象(ServerSocket)

ServerSocket(int port)

② 监听客户端连接,返回一个Socket对象

 Socket accept()

③ 获取输入流,读数据,并把数据显示在控制台

InputStream getInputStream()

④ 释放资源

void close()

示例:

客户端:

public class Client {
    public static void main(String[] args) throws IOException {
        //TCP协议,发送数据

        //1.创建Socket对象
        //细节:在创建对象的同时会连接服务端
        //如果连接不上,代码会报错

        Socket socket = new Socket("127.0.0.1", 10001);

        //2.可以从连接通道中获取输出流
        OutputStream os = socket.getOutputStream();

        //写出数据
        os.write("小璐乱撞".getBytes());

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

服务端:

public class Server {
    public static void main(String[] args) throws IOException {
        //TCP协议,接收数据

        //1.创建对象ServerSocket
        ServerSocket ss = new ServerSocket(10001);

        //2.监听客户端的连接(若未有客户端来连接,会一直死等)
        Socket socket = ss.accept();

        //3.从连接通道中获取输入流读取数据
        /*
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        */
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int b;
        while((b = br.read()) != -1) {
            System.out.print((char)b);
        }

        //4.释放资源
        br.close();
        socket.close();
        ss.close();
    }
}

三次握手:确保连接建立

[外链图片转存中…(img-1HWRhA1g-1709956049563)]三次握手

**四次挥手:**确保连接断开,且数据处理完毕

四次挥手

练习

TCP练习

public class Client {
    public static void main(String[] args) throws IOException {
        //1.创建Socket对象并连接客户端
        Socket socket = new Socket("127.0.0.1", 10002);

        //2.写出数据
        OutputStream os = socket.getOutputStream();
        String str = "小璐乱撞";
        os.write(str.getBytes());

        //写出一个结束标记
        socket.shutdownOutput();

        //3.接收客户端回写的数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int b;
        while((b = isr.read()) != -1) {
            System.out.print((char)b);
        }

        //4.释放资源
        socket.close();
    }
}
port java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        //1.创建对象并绑定端口
        ServerSocket ss = new ServerSocket(10002);

        //2.等待客户端连接
        Socket socket = ss.accept();

        //3.socket中获取输入流读取数据
        InputStreamReader isr = new InputStreamReader(socket.getInputStream());
        int b;
        //细节:
        //read方法会从连接通道中读取数据
        //但是,需要有一个结束标记,此处的循环才会停止
        //否则,程序就会一直停在read方法这里,等待读取下面的数据
        while((b = isr.read()) != -1) {
            System.out.print((char)b);
        }

        //4.回写数据
        String str = "好好好";
        OutputStream os = socket.getOutputStream();
        os.write(str.getBytes());

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

TCP练习2

public class Client {
    public static void main(String[] args) throws IOException {
        //1.创建socket对象,并连接服务器
        Socket socket = new Socket("127.0.0.1", 10002);

        //2.读取本地文件的数据,并写到服务器当中
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day31-code\\src\\test9\\a.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] bytes = new byte[1024];
        int len;
        while((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bis.close();
        //写出结束标记
        socket.shutdownOutput();

        //3.接收服务器的回写数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = br.readLine();
        System.out.println(line);

        //4.释放资源
        socket.close();
    }
}
public class Server {
    public static void main(String[] args) throws IOException {
        //1.创建对象并绑定端口
        ServerSocket ss = new ServerSocket(10002);

        //2.等待客户端连接
        Socket socket = ss.accept();

        //3.读取数据并保存到本地文件中
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        //获取随机的名字(UUID)
        String name = UUID.randomUUID().toString().replace("-", "");
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day31-code\\src\\test9\\serverdir\\" + name + ".jpg"));
        byte[] bytes = new byte[1024];
        int len;
        while((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.close();

        //4.回写数据
        String str = "接收完毕";
        OutputStream os = socket.getOutputStream();
        os.write(str.getBytes());

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

image-20240309114430795

这道题修改服务器端即可

public class Server {
    public static void main(String[] args) throws IOException {
        //1.创建对象并绑定端口
        ServerSocket ss = new ServerSocket(10002);

        while(true) {
            //2.等待客户端连接
            Socket socket = ss.accept();

            //开启一条线程
            //一个用户就对应服务端的一条线程
            new Thread(new MyRunnable(socket)).start();
        }
    }
}
public class MyRunnable implements Runnable{
    Socket socket;

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

    @Override
    public void run() {
        try {
            //3.读取数据并保存到本地文件中
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day31-code\\src\\test10\\serverdir\\" + name + ".jpg"));
            byte[] bytes = new byte[1024];
            int len;
            while((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
            bos.close();

            //4.回写数据
            String str = "接收完毕";
            OutputStream os = socket.getOutputStream();
            os.write(str.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(socket != null) {
                try {
                    //5.释放资源
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
;