zoukankan      html  css  js  c++  java
  • 网络编程入门笔记

    网络编程入门笔记

    狂神网络编程

    基础的科普

    概述

    举例

    打电话——TCP

    发短信——UDP

    网络编程的目的

    传播交流信息、数据交换、通信

    网络通信的要素

    • 通信双方的地址,包括IP地址、端口号port
    • 网络通信的协议

    tcp/ip参考模型

    OSI七层网络模型是理想化的参考模型,并没有实际应用,实际是TCP/IP参考模型。

    tpc/ip参考模型.png

    IP地址

    IP地址:InetAddress

    • IP用于唯一定位一台网络上的计算机
    • 本机:127.0.0.1 或者 localhost
    • IP地址的分类
      • IPv4 : 32位,4个字节组成,每个字节范围为0——255的无符号整数,总量有42亿,即2的32次方。分布不均,30亿在北美,亚洲4亿,2011年就用尽了。
      • IPv6 :128位,8个无符号整数,每个整数16位。
        • 示例:2001:DB8:0:23:8:800:200C:417A
      • 公网(互联网)/私网IP(局域网)
        • ABCD类地址
        • 192.168.X.X 这类地址是专门给组织内部使用的,内网地址
    • 域名:用于记忆IP地址、集群时的多个IP地址与域名的映射

    扩展

    IPv6表示法

    IPv6的地址长度为128位,是IPv4地址长度的4倍。于是IPv4点分十进制格式不再适用,采用十六进制表示。IPv6有3种表示方法。

    一、冒分十六进制表示法
      格式为X:X:X:X:X:X:X:X,其中每个X表示地址中的16b,以十六进制表示,例如:
      ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
      这种表示法中,每个X的前导0是可以省略的,例如:
      2001:0DB8:0000:0023:0008:0800:200C:417A→ 2001:DB8:0:23:8:800:200C:417A

    二、0位压缩表示法
      在某些情况下,一个IPv6地址中间可能包含很长的一段0,可以把连续的一段0压缩为“::”。但为保证地址解析的唯一性,地址中”::”只能出现一次,例如:
      FF01:0:0:0:0:0:0:1101 → FF01::1101
      0:0:0:0:0:0:0:1 → ::1
      0:0:0:0:0:0:0:0 → ::

    三、内嵌IPv4地址表示法
      为了实现IPv4-IPv6互通,IPv4地址会嵌入IPv6地址中,此时地址常表示为:X:X:X:X:X:X:d.d.d.d,前96b采用冒分十六进制表示,而最后32b地址则使用IPv4的点分十进制表示,例如::192.168.0.1与::FFFF:192.168.0.1就是两个典型的例子,注意在前96b中,压缩0位的方法依旧适用

    IP地址中A类、B类、C类地址的区别

    IP地址表示方法不同:

    一个A类IP地址是指, 在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码。如果用二进制表示IP地址的话,A类IP地址就由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”。A类IP地址中网络的标识长度为8位,主机标识的长度为24位。

    一个B类IP地址是指,在IP地址的四段号码中,前两段号码为网络号码。如果用二进制表示IP地址的话,B类IP地址就由2字节的网络地址和2字节主机地址组成,网络地址的最高位必须是“10”。B类IP地址中网络的标识长度为16位,主机标识的长度为16位。

    一个C类IP地址是指,在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码。如果用二进制表示IP地址的话,C类IP地址就由3字节的网络地址和1字节主机地址组成,网络地址的最高位必须是“110”。C类IP地址中网络的标识长度为24位,主机标识的长度为8位。

    2、IP地址范围不同:

    A类IP地址 地址范围从1.0.0.1到127.255.255.254 (二进制表示为:00000001 00000000 00000000 00000001 - 01111111 11111111 11111111 11111110)。最后一个是广播地址。

    B类IP地址地址范围从128.0.0.1-191.255.255.254 (二进制表示为:10000000 00000000 00000000 00000001-10111111 11111111 11111111 11111110)。 最后一个是广播地址。

    C类IP地址范围从192.0.0.1-223.255.255.254 (二进制表示为: 11000000 00000000 00000000 00000001 - 11011111 11111111 11111111 11111110)。最后一个是广播地址。

    3、子网掩码不同:

    A类IP地址的子网掩码为255.0.0.0

    B类IP地址的子网掩码为255.255.0.0

    C类IP地址的子网掩码为255.255.255.0

    4、适用范围不同:

    A类适用的类型为大型网络,A类网络地址数量较少,有126个网络,每个网络支持的最大主机数为256的3次方-2=16777214台;

    B类适用的类型为中型网络,B类网络地址数量适中,有16384个网络,每个网络支持的最大主机数为256的2次方-2=65534台;

    C类适用的类型为小型网络,C类网络地址数量较多,有209万余个网络,适用于小规模的局域网络,每个网络支持的最大主机数为256的1次方-2=254台。

    ABCD类地址记忆

    A:0-127 中间128位

    B:128-191 中间64位

    C:192-223 中间32位

    D:224-239 中间16位

    E:240-255 中间16位

    记的话就从0开始一直加128,再加它的二分之一,一直这样下去,即可算出。

    端口Port

    我们如果把IP地址比喻成一栋楼,那端口Port就是每套房子的名字,我们的主机上的程序相当于一套房子,而我们的每个程序运行时都要分配一个端口号。

    • 不同的进程有不同的端口号,用来区分软件的。
    • 规定范围 0~65535
    • 不同的协议TCPUDP都有对应0~65535的端口号范围,因此总的可以使用的端口号有65535 * 2 个,不同协议的端口号可以相同,而相同协议下比如TCP只能有一个80端口被一个进程使用,不能有冲突。
    • 端口分类
      • 公有端口0~1023
        • HTTP: 80 (默认端口)
        • HTTPS: 443
        • FTP: 21
        • SSH: 22
        • Telent :23
      • 程序注册端口范围:1024~49151 ,分配给用户或者程序的端口
        • Tomcat:8080
        • MySQL: 3306
        • Oracle:1521
      • 私有、动态端口范围:49152~65535

    简单命令

    #查看所有端口列表
    netstat -ano
    #查看指定端口或字符串对应的端口列表。 |表示管道,过滤的意思,会先执行过滤再查找
    netstat -ano|findstr "8080" 
    #查看指定端口或者程序的进程
    tasklist|findstr "chrome"
    tasklist|findstr "1736"
    

    代码示例

    public class INetAddressTest {
        public static void main(String[] args) throws UnknownHostException {
            //查询本机地址的3种方式
            ///127.0.0.1
            System.out.println(InetAddress.getByName("127.0.0.1"));
            //DESKTOP-G590BHK/172.16.57.150 电脑计算机名加主机
            System.out.println(InetAddress.getLocalHost());
    
            InetAddress localhost = InetAddress.getByName("localhost");
    //        System.out.println(localhost.getAddress());//返回2进制数组地址, byte[]
            //localhost/127.0.0.1
            System.out.println(localhost);
            //activate.navicat.com 返回典范,标准的主机名,因为在本机电脑hosts配置了 127.0.0.1       activate.navicat.com
    //        System.out.println(localhost.getCanonicalHostName());
            //localhost
            System.out.println(localhost.getHostName());
            System.out.println(localhost.getHostAddress());
            System.out.println("-----------------------------------");
            InetAddress qq = InetAddress.getByName("www.qq.com");
            System.out.println(qq);
            System.out.println(qq.getCanonicalHostName());
            System.out.println(qq.getHostName());
            System.out.println(qq.getHostAddress());
            System.out.println("----------------port-------------------");
    
            //IP端口对象
            InetSocketAddress socketAddress = new InetSocketAddress("localhost", 8080);
            System.out.println(socketAddress.getAddress());
            System.out.println(socketAddress.getHostName());
            System.out.println(socketAddress.getPort());
        }
        /**
         * 这两个类作用不大,只是了解
         * /127.0.0.1
         * DESKTOP-G590BHK/172.16.57.150
         * localhost/127.0.0.1
         * localhost
         * 127.0.0.1
         * -----------------------------------
         * www.qq.com/121.14.77.201
         * www.qq.com
         * www.qq.com
         * 121.14.77.201
         * ----------------port-------------------
         * localhost/127.0.0.1
         * localhost
         * 8080
         */
    }
    

    通信协议

    协议:就是约定,就像我们约定沟通用普通话。

    因为通信协议的复杂,我们就大事化小,进行分层处理。

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

    TCP:传输控制协议,Transmission Control Protocol

    UDP:用户数据报协议,User Datagram Protocol

    比较常用出名的便是TCP/IP协议。

    tcp/ip.png

    TCP与UDP的对比

    TCP

    • 打电话
    • 建立连接,稳定
    • 三次握手、四次挥手
    • 有客户端、服务端的概念
    • 传输完成,释放连接,效率低

    关于三次握手和四次挥手,面试官想听到怎样的回答

    UDP

    • 发短信
    • 不建立连接,不稳定
    • 没有客户端、服务端的明确界限
    • 不管有没有准备好都可以发送信息
    • DDOS饱和暴力攻击就是UDP协议形式

    TCP通信步骤

    客户端

    • 连接服务器Socket
    • 发送消息

    服务端

    • 建立服务端口ServerSocket
    • 等待用户连接 serverSocket.accept()
    • 接受用户消息

    代码示例

    TCP协议下的通讯
    public class TCPClient {
        public static void main(String[] args) throws IOException {
            //1、客户端知道服务器的地址和端口号,建立连接。Socket是客户端套接字
            try (Socket socket = new Socket("localhost", 9999)) {
                try (OutputStream outputStream = socket.getOutputStream()) {
                    /* Scanner scanner = new Scanner(System.in);
                    System.out.println("!");
                    //服务端无法读取到所以数据,只能读取最后一部分,只要scanner不断开,也就是客户端不结束,服务端的读取流就一直阻塞着
                   while (scanner.hasNext()) {
                        if ("exit".equalsIgnoreCase(scanner.next())) {
                            scanner.close();
                            System.out.println("客户端退出聊天室!");
                            break;
                        }
                        //发送消息IO流
                        outputStream.write(scanner.next().getBytes());*/
                    outputStream.write("客户端可以发送信息给智能小白了".getBytes());
    //                }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public class TCPServer {
        public static void main(String[] args) throws IOException {
            //服务端通过ip地址和端口号创建一个服务端套接字 ServerSocket
            try (ServerSocket serverSocket = new ServerSocket(9999)) {
                //等待客户端连接
                try (Socket socket = serverSocket.accept()) {
                    //获取客户端的读字节流,读取客户端的消息
                    try (InputStream is = socket.getInputStream()) {
                        //管道流
                        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                            int len = 0;
                            byte[] buffer = new byte[1024];
                            while ((len = is.read(buffer)) > 0) {
                                outputStream.write(buffer, 0, len);
                            }
                            System.out.println(outputStream.toString());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 客户端可以发送信息给智能小白了
         */
    }
    
    TCP协议下上传文件
    public class TCPUploadClient {
        public static void main(String[] args) throws Exception {
            //1创建Socket连接
            Socket socket = new Socket("127.0.0.1", 8090);
            //2、创建输出流
            OutputStream os = socket.getOutputStream();
    
            //没有写file的路径名时默认是相对路径,即项目根目录下的位置,springboot-demo下
            //读取文件
            FileInputStream is = new FileInputStream(new File("asfasf.jpg"));
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
    
            //通知服务器我结束发送消息了,结束输出流,这样服务器那边的就不会阻塞等待了
            socket.shutdownOutput();
    
            InputStream inputStream = socket.getInputStream();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            while ((len = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
            System.out.println(outputStream.toString());
    
            //先开后关
            inputStream.close();
            outputStream.close();
            is.close();
            os.close();
            socket.close();
        }
        //文件传输完成了!再见!
    }
    
    public class TCPUploadServer {
        public static void main(String[] args) throws Exception {
            //创建服务ServerSocket
            ServerSocket serverSocket = new ServerSocket(8090);
            //监听客户端
            Socket socket = serverSocket.accept();
            //获取输入流
            InputStream is = socket.getInputStream();
            //创建输出文件名及输出流
            FileOutputStream os = new FileOutputStream(new File("hello.jpg"));
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
    
            //通知客户端文件传输完成,即向客户端写消息
            //先拿到输出流
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("文件传输完成了!再见!".getBytes());
    
            //关闭资源
            outputStream.close();
            os.close();
            is.close();
            socket.close();
            serverSocket.close();
        }
    }
    

    UDP

    UDP的客户端Client可以直接发生消息给服务端或者其他人,不需要建立连接,因此就不需要要求服务端或其他人是在线的,也能发生成功;而TCP发生消息需要先建立连接,这时候如果连接的服务器不可用(比如没有启动起来),TCP的客户端启动时就会报错。如下:

    Exception in thread "main" java.net.ConnectException: Connection refused: connect
    

    但是,如果UDP接收方,比如服务器不可用的话,是接收不到数据的,所以理论上虽然不会报错,但是UDP服务器也是要先启动起来等待接受数据的。

    代码示例

    UDP协议下通讯聊天——发包进行聊天

    首选创建发送消息和接受消息两个UDP工具类,然后创建两个用户对象,分别创建两条线程监听执行。

    接受API类

    public class UDPChatReceiver implements Runnable {
    
        private DatagramSocket datagramSocket;
        private int fromPort;
        private String userName;
    
        public UDPChatReceiver(int fromPort, String userName) {
            this.fromPort = fromPort;
            this.userName = userName;
            try {
                //1创建一个数据包套接字DatagramSocket,开放接收端口
                datagramSocket = new DatagramSocket(fromPort);
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            try {
                while (true) {
                    //准备容器接收数据
                    byte[] buffer = new byte[1024];
                    //2创建接收数据包,传入缓存容器
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                    //3阻塞接收数据
                    datagramSocket.receive(packet);
                    System.out.println(packet.getAddress());
                    //4读取数据后将字节流转字符串即可
                    String data = new String(packet.getData());
                    System.out.println(userName + ":" + data);
                    if ("exit".equalsIgnoreCase(data)) {
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //5关闭流
                datagramSocket.close();
            }
        }
    }
    
    

    发送API类

    public class UDPChatSender implements Runnable {
    
        //目标方的IP
        private String toIP;
        //目标方的端口
        private int toPort;
        //自己的端口
        private int fromPort;
    
        private DatagramSocket datagramSocket;
    
        private BufferedReader reader;
    
        public UDPChatSender(String toIP, int toPort, int fromPort) {
            this.toIP = toIP;
            this.toPort = toPort;
            this.fromPort = fromPort;
            try {
                //1创建一个数据包套接字DatagramSocket
                datagramSocket = new DatagramSocket(fromPort);
                reader = new BufferedReader(new InputStreamReader(System.in));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            try {
                while (true) {
                    //读取控制台数据
                    String str = reader.readLine();
                    //2创建一个数据包用于发送 ,包含数据及发送的目标IP和端口
                    DatagramPacket packet = new DatagramPacket(str.getBytes(), 0, str.getBytes().length, InetAddress.getByName(toIP), toPort);
                    //3发送数据包
                    datagramSocket.send(packet);
                    if ("exit".equalsIgnoreCase(str)) {
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //4关闭流
                datagramSocket.close();
            }
        }
    }
    

    用户对象

    
    public class Customer {
        public static void main(String[] args) {
            new Thread(new UDPChatReceiver(9800,"销售")).start();
            new Thread(new UDPChatSender("localhost",9500,9601)).start();
        }
    }
    
    public class Sale {
        public static void main(String[] args) {
            //接收线程
            new Thread(new UDPChatReceiver(9500,"客户")).start();
            //发送线程
            new Thread(new UDPChatSender("localhost",9800,9600)).start();
        }
    }
    

    java执行class要注意带包名时要退回到包名根路径下再执行java 包名.文件名 才能执行文件

    java执行class.png

    Tomcat

    执行文件.png

    Tomcat日志乱码是因为Windows默认编码是GBK,更改conf目录下的logging.properties文件即可。

    tomcat.png

    URL

    https://www.kugou.com/song/8wj752.html?share=1#hash=A46E805441A932ED0F5EF78DD229F688&album_id=1598950

    统一资源定位符:定位互联网上的某一个资源,定位资源用的。

    DNS域名解析指把域名解析成IP地址,如 www.kugou.com ——》 117.27.241.66

    URL格式

    协议://IP地址:端口号/项目名/资源
    

    代码示例——url资源下载

    网络爬虫的本质就是爬取各种资源文件的URL地址,然后创建连接,打开下载流下载到地址来,或者是爬取到数据来进行分析。

    public class URLTest {
        public static void main(String[] args) throws Exception {
            URL url1 = new URL("https://www.bilibili.com/video/BV1LJ411z7vY?p=12");
            //需要注意的是host如果是域名则获取的主机还是域名,没有端口的话默认是-1
            System.out.println(url1.getProtocol());//协议
            System.out.println(url1.getHost());//主机
            System.out.println(url1.getPort());//端口
            System.out.println(url1.getPath());//文件
            System.out.println(url1.getFile());//全路径
            System.out.println(url1.getQuery());//参数
            /**
             * https
             * www.bilibili.com
             * -1
             * /video/BV1LJ411z7vY
             * /video/BV1LJ411z7vY?p=12
             * p=12
             * null
             */
    
            //创建一个url对象,通过这个url对象可以进行访问、资源下载、爬虫抓取数据等操作
            URL url = new URL("https://webfs.yun.kugou.com/202102241417/c9463283bf6cecf8eead45be1614a275/part/0/960125/KGTX/CLTX001/a46e805441a932ed0f5ef78dd229f688.mp3");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            InputStream is = connection.getInputStream();
            FileOutputStream os = new FileOutputStream(new File("hope.mp3"));
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer);
            }
            os.close();
            is.close();
            connection.disconnect();
        }
    }
    
  • 相关阅读:
    模拟光照中的凹凸纹理原理和应用
    Visual Studio 2010 SP1正式开放下载
    同桌的你网工版
    [转载]同桌的你程序员版
    学习计划:SSIS
    基于Java的HTML解析器
    初次使用NHibernate遇到的问题
    .NET下开源CMS系统汇总
    MyEclipse、Tomcat启动项目报错
    VBA 分文件夹 分excel
  • 原文地址:https://www.cnblogs.com/castamere/p/14441426.html
Copyright © 2011-2022 走看看