20、网络编程实战

一、概述

  • 地球村:你在西安,你一个美国的朋友!
  • 信件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SZWKTtD3-1614584904637)(E:\硕士研究\Java学习历程\20、网络编程实战(信件原理)].png)

  • 计算机网络:

    ​ 计算机网络是指将**地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来**,在网络操作系统网络管理软件及**网络通信协议**的管理和协调下,实现资源共享和信息传递的计算机系统。

  • 网络编程的目的:

    无线电台 —> 传播交流信息、数据交换、通信

  • 想要达到这个效果需要什么:

    • 如何准确地定位网络上的一台主机 192.168.16.124: 端口,定位到这个计算机上的某个资源
    • 找到了这个主机,如何传输数据呢?
  • 网络编程和网页编程

    • 网络编程 TCP/IP C/S
    • 网页编程 JavaWeb B/S

二、网络通信的要素

  • 如何实现网络的通信?

  • 通信双方的地址:

    IP、端口号

  • 规则:网络通信的协议:http、ftp、smtp、tcp、udp…

    TCP/IP参考模型:

    在这里插入图片描述

三、IP

  • IP地址:InetAddress类

  • 唯一定位一台网络上的计算机

  • 本机 localhost:127.0.0.1

  • IP地址的分类:

    • ipv4 / ipv6

      • ipv4:127.0.0.1,4个字节组成,0~255,42亿:北美30亿,亚洲4亿,2011年已用尽;

      • ipv6:fe80::35bb:3e82:d451:cb96%19,128位,8个无符号整数;

        2001:0bb2:aaaa:0015:0000:0000:1aaa:1312
        
    • 公网(互联网)/ 私网(局域网)

      • ABCD类地址(查资料)

        IP地址分为五类,A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同。

        其中A类、B类、和C类这三类地址用于TCP/IP节点,其它两类D类和E类被用于特殊用途。
        A、B、C三类IP地址的特征:当将IP地址写成二进制形式时,A类地址的第一位总是O,B类地址的前两位总是10,C类地址的前三位总是110。

        1. A类IP地址

        一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”, 地址范围从1.0.0.0 到126.0.0.0。可用的A类网络有126个,每个网络能容纳1亿多个主机。

        ⑴ A类地址第1字节为网络地址,其它3个字节为主机地址。
        ⑵ A类地址范围:1.0.0.1—126.155.255.254
        ⑶ A类地址中的私有地址和保留地址:
        ① 10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
        ② 127.X.X.X是保留地址,用做循环测试用的。

        2. B类IP地址

        一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是“10”,地址范围从128.0.0.0到191.255.255.255。可用的B类网络有16382个,每个网络能容纳6万多个主机 。

        ⑴ B类地址第1字节和第2字节为网络地址,其它2个字节为主机地址。
        ⑵ B类地址范围:128.0.0.1—191.255.255.254。
        ⑶ B类地址的私有地址和保留地址
        ① 172.16.0.0—172.31.255.255是私有地址
        ② 169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。

        3. C类IP地址

        一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是“110”。范围从192.0.0.0到223.255.255.255。C类网络可达209万余个,每个网络能容纳254个主机。

        ⑴ C类地址第1字节、第2字节和第3个字节为网络地址,第4个个字节为主机地址。另外第1个字节的前三位固定为110。
        ⑵ C类地址范围:192.0.0.1—223.255.255.254。
        ⑶ C类地址中的私有地址:
        192.168.X.X是私有地址。

        4. D类地址用于多点广播(Multicast)。

        D类IP地址第一个字节以“1110”开始,它是一个专门保留的地址。它并不指向特定的网络,目前这一类地址被用在多点广播(Multicast)中。多点广播地址用来一次寻址一组计算机,它标识共享同一协议的一组计算机。

        ⑴ D类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1110。
        ⑵ D类地址范围:224.0.0.1—239.255.255.254

        5. E类IP地址

        以“11110”开始,为将来使用保留。

        全零(“0.0.0.0”)地址对应于当前主机。全“1”的IP地址(“255.255.255.255”)是当前子网的广播地址。

        ⑴ E类地址也不分网络地址和主机地址,它的第1个字节的前五位固定为11110。
        ⑵ E类地址范围:240.0.0.1—255.255.255.254

        6. 在IP地址3种主要类型里,各保留了3个区域作为私有地址,其地址范围如下:

        A类地址:10.0.0.0~10.255.255.255

        B类地址:172.16.0.0~172.31.255.255

        C类地址:192.168.0.0~192.168.255.255

        7. 子网掩码

        **子网掩码(subnet mask)**又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。

        **子网掩码不能单独存在,它必须结合IP地址一起使用。**子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。子网掩码是一个32位地址,用于屏蔽IP地址的一部分以区别网络标识和主机标识,并说明该IP地址是在局域网上,还是在远程网上。

        子网掩码——屏蔽一个IP地址的网络部分的“全1”比特模式。
        对于A类地址来说,默认的子网掩码是255.0.0.0;
        对于B类地址来说默认的子网掩码是255.255.0.0;
        对于C类地址来说默认的子网掩码是255.255.255.0。

      • 192.168.xx.xx:专门给组织内部使用的

  • 域名:记忆IP问题!

    • IP:www.vip.com
package com.cwlin.lesson01;

import java.net.InetAddress;
import java.net.UnknownHostException;

//测试IP
public class TestInetAddress {
    public static void main(String[] args) {
        try {
            //查询本机地址
            InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
            System.out.println(inetAddress1);
            InetAddress inetAddress3 = InetAddress.getByName("localhost");
            System.out.println(inetAddress3);
            InetAddress inetAddress4 = InetAddress.getLocalHost();
            System.out.println(inetAddress4);

            //查询网站ip地址
            InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
            System.out.println(inetAddress2);

            //常用方法
            //System.out.println(inetAddress2.getAddress()); //地址
            System.out.println(inetAddress2.getCanonicalHostName()); //规范的名字
            System.out.println(inetAddress2.getHostAddress()); //ip
            System.out.println(inetAddress2.getHostName()); //域名,或者自己电脑的名字
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}

四、端口

  • 端口表示计算机上的一个程序的进程。

  • 不同的进程有不同的端口号,用来区分软件!

  • 被规定为0~65535

  • TCP/UDP:65535*2,TCP:80和UDP:80不冲突;在单个协议下,端口号不能冲突

  • 端口分类:

    • 公有端口 0~1023
      • HTTP: 80;
      • HTTPS: 443;
      • FTP: 21;
      • Telent: 23
    • 程序注册端口 1024~49151,分配给用户或者程序
      • Tomcat: 8080
      • MySQL: 3306
      • Oracle: 1521
    • 动态、私有:49152~65535
    netstat -ano #查看所有端口
    netstat -ano|findstr "49664" #查看指定端口
    tasklist|findstr "21796" #查看指定端口的进程
    
package com.cwlin.lesson01;

import java.net.InetAddress;
import java.net.InetSocketAddress;

//测试ip+port
public class TestInetSocketAddress {
    public static void main(String[] args) {
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);
        InetSocketAddress socketAddress2 = new InetSocketAddress("localhost",8080);
        System.out.println(socketAddress);
        System.out.println(socketAddress2);
        System.out.println(socketAddress.getAddress()); //ip
        System.out.println(socketAddress.getPort()); //端口
        System.out.println(socketAddress.getHostName()); //地址(hosts文件可修改)
    }
}

五、通信协议

  • 协议:约定,

  • 网络通信协议:速率、传输码率、代码结构、传输控制…

  • 问题:非常复杂?

  • 解决:大事化小!分层!

  • TCP/IP协议簇:实际上是一组协议

  • 重要协议:

    • TCP:用户传输协议
    • UDP:用户数据报协议
  • 出名的协议:

    • TCP:传输控制协议
    • IP:网络互联协议

在这里插入图片描述

  • TCP和UDP的对比

    • TCP:打电话

      • 连接,稳定

      • 三次握手四次挥手

      • 客户端、服务端

      • 传输完成,释放连接,效率低

    • UDP:发短信

      • 不连接,不稳定
      • 客户端、服务端:没有明确的界限
      • 不管有没有准备好,都可以发给你
      • 导弹
      • DDOS:洪水攻击!(饱和攻击)
    • TCP的三次握手、四次挥手

      • 概述:

        最少需要三次,保证连接稳定!
        A: 你愁啥?
        B: 瞅你咋地?
        A: 干一场!
        
        最少需要四次,保证彻底断开!
        A: 我要走了!
        B: 我真的要走了吗?
        B: 你真的真的要走了吗?
        A: 我真的要走了!
        
      • 详解:

      在这里插入图片描述
      在这里插入图片描述

      • 通俗理解:

      在这里插入图片描述
      在这里插入图片描述

六、TCP

6.1、发送消息

  • 客户端
    1. 连接服务Socket
    2. 发送消息
package com.cwlin.lesson02;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;

//客户端
public class TcpClientDemo01 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1.要知道服务器的地址、端口号
            InetAddress serverIp = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            //2.创建一个socket连接
            socket = new Socket(serverIp,port);
            //3.发送消息 IO流
            os = socket.getOutputStream();
            os.write("你好,欢迎学习网络编程".getBytes());

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 服务器

    1. 建立服务的端口 ServerSocket

    2. 等待用户的连接 accept

    3. 接收用户的消息

package com.cwlin.lesson02;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

//服务端
public class TcpServerDemo01 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            //1.我得有一个地址
            serverSocket = new ServerSocket(9999); //插槽
            while (true){
                //2.等待客户端连接过来
                socket = serverSocket.accept();
                //3.读取客户端的消息
                is = socket.getInputStream();

                //管道流
                baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);
                }
                System.out.println(baos.toString());
            }


            /* 比较的方法,若中文在中间断掉,会乱码
                byte[] buffer = new byte[1024];
                int len;
                while ((len=is.read(buffer))!=-1){
                    String msg = new String(buffer, 0, len);
                    System.out.println(msg);
                }
             */
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if (baos != null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }



        }
    }
}

6.2、文件上传

  • 客户端
package com.cwlin.lesson02;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class TcpClientDemo02 {
    public static void main(String[] args) throws Exception {
        //1.创建一个Socket连接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
        //2.创建一个输出流
        OutputStream os = socket.getOutputStream();
        //3.读取文件
        FileInputStream fis = new FileInputStream(new File("send.png"));
        //4.写入文件
        byte[] buffer = new byte[1024];
        int len;
        while ((len=fis.read(buffer)) != -1){
            os.write(buffer,0,len);
        }

        //通知服务器已经传输结束
        socket.shutdownOutput();
        //确定服务器接收完毕,才能断开连接
        InputStream inputStream = socket.getInputStream();
        //String byte[]
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer2 = new byte[1024];
        int len2;
        while ((len2=inputStream.read(buffer2)) != -1){
            byteArrayOutputStream.write(buffer2,0,len2);
        }
        System.out.println(byteArrayOutputStream.toString());

        //5.关闭资源
        byteArrayOutputStream.close();
        inputStream.close();
        fis.close();
        os.close();
        socket.close();
    }
}
  • 服务器
package com.cwlin.lesson02;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServerDemo02 {
    public static void main(String[] args) throws Exception {
        //1.创建服务
        ServerSocket serverSocket = new ServerSocket(9000);
        //2.监听客户端的连接
        Socket socket = serverSocket.accept();
        //3.获取输入流
        InputStream is = socket.getInputStream();
        //4.文件输出
        FileOutputStream fos = new FileOutputStream(new File("receive.png"));
        byte[] buffer = new byte[1024];
        int len;
        while ((len=is.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

        //通知客户端已经接收完毕
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("已经接收完毕,可以断开".getBytes());

        //5.关闭资源
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

6.3、Tomcat

  • 服务端

    • 自定义 S
    • Tomcat服务器 S:Java后台开发!
  • 客户端

    • 自定义 C
    • 浏览器 B

七、UDP

7.1、发送消息:不用连接,只需要知道对方的地址!

  • 发送端
package com.cwlin.lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//不需要连接服务器
public class UdpClientDemo01 {
    public static void main(String[] args) throws Exception {
        //1.建立一个Socket
        DatagramSocket socket = new DatagramSocket();
        //2.建个包
        String msg = "你好啊,服务器!";
        InetAddress localhost = InetAddress.getByName("localhost");
        int port = 9090;
        //数据,数据的起止,要发送给谁
        DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);
        //3.发送包
        socket.send(packet);
        //4.关闭流
        socket.close();
    }
}
  • 接收端
package com.cwlin.lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

//还是要等待客户端的连接!
public class UdpServerDemo01 {
    public static void main(String[] args) throws Exception {
        //开放端口
        DatagramSocket socket = new DatagramSocket(9090);
        //接收数据包
        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(packet); //阻塞接收
        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(new String(packet.getData(),0,packet.getLength()));
        //关闭连接
        socket.close();
    }
}

7.2、咨询:循环发送消息和接收消息!

  • 发送端:循环发送消息
package com.cwlin.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class UdpSenderDemo01 {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8888);
        //准备数据:控制台读取System.in
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true){
            String data = reader.readLine();
            byte[] sendData = data.getBytes();
            DatagramPacket packet = new DatagramPacket(sendData,0,sendData.length,new InetSocketAddress("localhost",6666));

            socket.send(packet);
            if (data.equals("bye")){
                break;
            }
        }
        socket.close();
    }
}
  • 接收端:循环接收消息
package com.cwlin.chat;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UdpReceiveDemo01 {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(6666);
        while (true){
            //准备接收包裹
            byte[] container = new byte[1024];
            DatagramPacket packet = new DatagramPacket(container,0,container.length);
            socket.receive(packet); //阻塞式接收包裹
            //断开连接 bye
            byte[] data = packet.getData();
            String receiveData = new String(data, 0, data.length);

            System.out.println(receiveData);
            if (receiveData.equals("bye")){
                break;
            }
        }
    }
}

7.3、在线咨询:两个人都可以是发送方和接收方!

  • 发送线程
package com.cwlin.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class TalkSend implements Runnable {
    DatagramSocket socket = null;
    BufferedReader reader = null;

    private int fromPort;
    private String toIP;
    private int toPort;

    public TalkSend(int fromPort, String toIP, int toPort) {
        this.fromPort = fromPort;
        this.toIP = toIP;
        this.toPort = toPort;

        try {
            socket = new DatagramSocket(fromPort);
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true){
            String data = null;
            try {
                data = reader.readLine();
                byte[] sendData = data.getBytes();
                DatagramPacket packet = new DatagramPacket(sendData,0,sendData.length,new InetSocketAddress(this.toIP,this.toPort));

                socket.send(packet);
                if (data.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        socket.close();
    }
}
  • 接收线程
package com.cwlin.chat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class TalkReceive implements Runnable {
    DatagramSocket socket = null;
    private int port;
    private String msgFrom;

    public TalkReceive(int port, String msgFrom) {
        this.port = port;
        this.msgFrom = msgFrom;
        try {
            socket = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true){
            try {
                //准备接收包裹
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container,0,container.length);
                socket.receive(packet); //阻塞式接收包裹
                //断开连接 bye
                byte[] data = packet.getData();
                String receiveData = new String(data, 0, data.length);

                System.out.println(msgFrom + ":" + receiveData);
                if (receiveData.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 老师端
package com.cwlin.chat;

public class TalkTeacher {
    public static void main(String[] args) {
        //开启两个线程
        new Thread(new TalkSend(5555,"localhost",8888)).start();
        new Thread(new TalkReceive(9999,"学生")).start();
    }
}
  • 学生端
package com.cwlin.chat;

public class TalkStudent {
    public static void main(String[] args) {
        //开启两个线程
        new Thread(new TalkSend(7777,"localhost",9999)).start();
        new Thread(new TalkReceive(8888,"老师")).start();
    }
}

八、URL

8.1、概述

  • 统一资源定位符:定位资源、定位互联网上的某一个资源

  • DNS域名解析 www.baidu.com xxx.x.x.x

  • 格式:协议://IP地址:端口/项目名/资源

8.2、URL基本内容

package com.cwlin.lesson05;

import java.net.MalformedURLException;
import java.net.URL;

public class URLDemo01 {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("http://localhsot:8080/helloworld/index.jsp?username=cwlin&password=123456");
        System.out.println(url.getProtocol()); //协议:http
        System.out.println(url.getHost()); //主机IP:localhost
        System.out.println(url.getPort()); //端口:8080
        System.out.println(url.getPath()); //文件:/helloworld/index.jsp
        System.out.println(url.getQuery()); //参数:username=cwlin&password=123456
        System.out.println(url.getFile()); //全路径:/helloworld/index.jsp?username=cwlin&password=123456
    }
}

8.3、URL下载网络资源

package com.cwlin.lesson05;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class URLDownload {
    public static void main(String[] args) throws Exception {
        //1.下载地址
        //网页图片: https://p2.music.126.net/4WuOpPZeK7hH8bqn28G-Dg==/109951165315490238.jpg?param=130y130
        //网页音乐: https://ws.stream.qqmusic.qq.com/C4000046fqfQ3mSaUo.m4a?guid=446211115&vkey=C8A1B9D42E3F101F2A7D0F98AEECA5CE2F5AB629A9533212BA47BB36B8680B85796E7C91E2D71DF5295FD18BAE714E50A6F89C5B04E3786B&uin=1208793450&fromtag=66
        URL url = new URL("http://localhost:8080/cwlin/SecurityFile.txt");
        //2.连接到这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream inputStream = urlConnection.getInputStream();
        FileOutputStream fos = new FileOutputStream("漫长的告白.m4a");
        byte[] buffer = new byte[1024];
        int len;
        while ((len=inputStream.read(buffer))!=-1){
            fos.write(buffer,0,len); //写出这个数据
        }
        fos.close();
        inputStream.close();
        urlConnection.disconnect(); //断开连接
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值