zoukankan      html  css  js  c++  java
  • 网络编程;InetAddress类;UDP协议和TCP协议;Socket编程;UDP编程;TCP编程 (Java Day26)

    一,网络编程概念

    • 网络:就是不同地域,不同型号、不同ip等多台计算机相互连接沟通形成的通信系统
    • ​ 元素:
    1. ​ 看得见的元素:网线、交换机、计算机、内存条等一系列的硬件设备
    2. ​ 看不见的元素:传输协议、io流、运行的程序等
    • 网络编程:基于计算机网络来进行数据的接收,发送,处理等操作的过程会使用不同的语言来实现。比如 java c++ 等
    • 网络编程三要素:ip地址、端口号、传输协议

    • IP地址

    • 概述:计算机在网络中IP协议分配给每一台计算机的唯一标识。【他代表了计算机在网络中唯一地址。通过ip可以找到想要找的计算机】
    • 作用:能够在网络准确找到计算机
    • 分类:IPv4:是由四个字节组成的一段序列,来表示计算机的标识,字节和字节之间使用.隔开。一个字节8位,4个字节是32位,一共有2^32个ip。大概42亿个ip,也就是说他可以给42亿台计算机分配地址。
    • ​ 比如:192.168.1.148
    • ​ 一般前三个字节代表的是子网段的,最后一个字节代表计算机的段号。每一个字节都是0到255之间的数
    • IPv6:8组16进制的数组成的一段序列,来表示ip地址。组与组之间使用 :隔开。每组数有16种变化,一共128位,2^128个ip,号称全世界每一粒沙子都有一个ip。
    • ​ 比如:fe80::741f:ab6d:2237:20af%13,
    • 如果是0可以省略,一般是连续为0.
    • 端口号【重点】

    • 概述:就是一个数字,是计算机中正在运行的进程的编号。端口号不可以重复。他是由2个字节大小的数字来表示,0到65535的范围。
    • 作用:能够通过他准确的找到计算机中正在运行的进程
    • 端口号的分配:
    1. 程序在启动的时候计算机随机自动分配端口号
    2. 程序中人为的指定端口号 比如 : 第二阶段 安装 mysql 时会有一个端口号设置 3306 【默认的】一般情况下默认不改
    • 常用的端口号:
    1. ​ 系统程序:0到1024
    2. ​ MySQL:3306
    3. ​ Oracle:1521
    4. ​ Tomcat:8080
    5. ​ QQ:4000
    • 通信协议

    • 概述:数据在传输过程中接收、发送,处理等操作是有规则。不同的场景有不同的协议,往往不同的协议协同合作维护网络编程的环境。
    • 网络分层:分工作业
    1. ​ 应用层:对数据的发送和接收进行处理工作 HTTP协议、HTTPS协议、FTP协议。
    2. ​ 传输层:把数据从一端传输到另一端 TCP协议 UDP协议【今天要讲的协议】
    3. ​ 网络层:规划线路连接 IP协议
    4. ​ 物理层:相关的硬件设施

    二,InetAddress类

    • 概述:此类表示互联网协议 (IP) 地址。【对ip的相关特征和行为的描述,一般包括主机和IP地址】
    • 获取对象的方式:【静态方法
    1. ​ getAllByName(String host) :  通过主机名称获取对应的所有IP地址对象的数组
    2. ​ getByAddress(byte[] addr) :通过IP地址的字节数组获取IP地址的对象
    3. ​ getByAddress(String host, byte[] addr) :通过主机名称和IP地址的字节数组获取IP地址的对象
    4. getByName(String host) :通过主机名称获取对应的IP地址对象
    5. ​ getLocalHost() :获取本地主机的IP对象

    代码示例:

    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    public class Demo_InetAddress {
        public static void main(String[] args) throws UnknownHostException {
            InetAddress[] allByName = InetAddress.getAllByName("APPLE-NO-MBP"); // 主机名
            System.out.println(Arrays.toString(allByName)); // [APPLE-NO-MBP/192.168.43.61],获取主机名称和IP地址
    
            // 127.0.1 本机的IP地址 对应的字节数组 127 0 0 1
            byte[] bs = { 127, 0, 0, 1 };
            InetAddress address = InetAddress.getByAddress(bs);
            System.out.println(address); // 127.0.0.1,将数组变为IP地址,数组与IP地址之间的转化
    
            InetAddress address2 = InetAddress.getByAddress("APPLE-NO-MBP", bs);
            System.out.println(address2); // APPLE-NO-MBP/127.0.0.1,显示哪台机器下面的IP,包括主机名称和IP地址
    
            InetAddress address3 = InetAddress.getByName("APPLE-NO-MBP");
            System.out.println(address3); // APPLE-NO-MBP/192.168.43.61 获取的是主机和IPV4地址
    
            InetAddress host = InetAddress.getLocalHost();
            System.out.println(host); // apple-no-MBP/192.168.43.61, 获取自己电脑的IP地址
    • 获取对象的属性常用方法:
    1. ​ getAddress() :返回对象的原始IP地址
    2. ​ getHostName(): 返回对象的主机名称
    3. ​ toString() :将ip地址转换为字符串

    代码示例

    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    public class Demo_InetAddress {
        public static void main(String[] args) throws UnknownHostException {
            InetAddress host = InetAddress.getLocalHost();
            System.out.println(host); // apple-no-MBP/192.168.43.61, 获取自己电脑的IP地址
    
            // 常用方法
            byte[] bs2 = host.getAddress(); // IP 的字节数组
            System.out.println(Arrays.toString(bs2)); // [-64, -88, 43, 61], 因为192超出了字节的范围,溢出了
            InetAddress address5 = InetAddress.getByAddress(bs2);
            System.out.println(address5); // /192.168.43.61 转回为数组
            
            String name = host.getHostName();
            System.out.println(name);  //apple-no-MBP 返回对象的主机名称
            System.out.println(host.toString());  //apple-no-MBP/192.168.43.61, 将ip地址转换为字符串
        }
    }

    三,UDP协议和TCP协议

    • 概述:是传输层的协议,是数据端到端的协议
    • UDP:  是面向无连接的协议。不用端和端之间联系就进行数据的传输。比如:QQ发消息、短信、微博留言、邮件等方式。所以不用管对方在不在线,直接操作数据,但是数据发出去之后有可能收不到,安全性低,效率高。不区分客户端和服务端,只有发送端和接收端。
    • 特点:
    1. 数据不安全
    2. 效率高
    • TCP:面向连接的传输协议。要求对方必须在线并且连接成功。区分客户和服务,把发送数据段叫做客户端,接收数据端就做服务端。
    • ​ 如何进行连接的?
    • ​ 三次握手:瞬间就可以完成的。
    1. ​ 第一次:发送端发出信号给接收端
    2. ​ 第二次:接收端接到信号给出回应
    3. ​ 第三次:发送端收到回应确定连接成功
    • 特点:
    1. 数据安全性有保证
    2. 效率低

    四,Socket编程【套接字编程】

    • Socket :  套接字
    • ​ 套接字:传输层编程是端到端的编程,套接字就是端和端进行交流的中间服务
    • ​ 举例: 网购 客户 网上买了东西 商家 把东西邮寄给你
    • ​ 客户:发送端
    • ​ 商家: 服务端
    • ​ 快递:把货在商家和客户之间进行传输 就是套接字
    • Socket编程在不同的协议下使用的套接字不一样。
    • UDP协议:DatagramSocket
    • TCP协议:
    1. ​ 客户端:Socket
    2. ​ 服务端:ServerSocket

    五,UDP编程

    • DatagramSocket:他是UDP编程的套接字 ,此类表示用来发送和接收数据报包的套接字
    • 数据报包【DatagramPacket】:指包装了发送的数据和接收数据数据的一个容器。【发送和接收的内容、发送的ip地址、端口号等内容】
    • 构造方法
    1. DatagramSocket():获取套接字对象【一般用于发送端】
    2. DatagramSocket(int port):获取套接字对象【一般用于接收端】
    • 常用方法:
    1. ​ send(DatagramPacket dp):发送数据报包出去
    2. ​ receive(DatagramPacket dp):接收数据报包
    3. DatagramPacket :数据报包
    • 通过构造方法来封装相关数据的构造方法:
    1. ​ DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) :用于发送端
    2. ​ DatagramPacket(byte[] buf, int offset, int length) :用于接收端
    • ​ 说明:
    1. buf:存放发送或接收数据内容的字节数组
    2. offset:buf 数组从哪个角标开始发送或接收,代表开始的角标值
    3. length:代表发送内容的长度,或者接受数组长度
    4. address:发送端发送目标ip地址
    5. port:发送的目标端口号
    • 数据报包的常用方法【获取数据报包内部的数据的方法】
    1. getData():获取数据报包中的内容数组
    2. ​ getLength():获取数据报包中有效内容的长度

    代码示例1,UDP发送端

    • 发送端编写步骤:
    1. 获取套接字对象
    2. 准备发送的相关数据
    3. 获取数据报包同时封装发送的数据
    4. 发送数据报包
    5. 准备接收数据的容器【字节数组相关数据】
    6. 准备一个接收数据的数据报包
    7. 接收数据
    8. 解析数据

    import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;
    // 发送端 public class UDP_Send { public static void main(String[] args) throws Exception { // 创建发送端的套接字对象 DatagramSocket socket = new DatagramSocket(); byte[] buf = "美女你好".getBytes(); DatagramPacket packet = new DatagramPacket(buf, 0, buf.length, InetAddress.getLocalHost(), 9999); socket.send(packet); // 接收发送端的回复 byte[] buf1 = new byte[1024]; DatagramPacket packet1 = new DatagramPacket(buf, 0, buf.length); socket.receive(packet1); // 如何获取接收到的数据呢? byte[] bs = packet1.getData();// 获取到数据报包中的读取内容的数组 int len = packet1.getLength();// 获取到有效内容的字节个数 System.out.println(new String(bs , 0 , len)); } }

    代码示例2:UDP接收端

    • 接收端编写步骤:
    1. 获取套接字
    2. 准备接收容器【字节数组的相关数据】
    3. 接收数据到数据报包
    4. 解析接收到的数据【数据报包方法】
    5. 准备回应的内容【字节数组】
    6. 将内容添加到接收使用的数据报包中
    7. 将该数据报包发送回发送端

    import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;
    // 接收端 public class UDP_Receive { public static void main(String[] args) throws Exception { // 创建套接字对象 DatagramSocket socket = new DatagramSocket(9999); byte[] buf = new byte[1024]; DatagramPacket packet = new DatagramPacket(buf, 0, buf.length); socket.receive(packet); // 如何获取接收到的数据呢? byte[] bs = packet.getData();// 获取到数据报包中的读取内容的数组 int len = packet.getLength();// 获取到有效内容的字节个数 System.out.println(new String(bs , 0 , len)); // 接收端要给个回应 byte[] bs2 = "帅哥你好".getBytes(); packet.setData(bs2); socket.send(packet);
    } }

     六,TCP编程

    • 客户端
    1. Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点
    • ​ 构造方法
    1. ​ Socket(InetAddress address, int port) :创建套接字对象,包含了目标的ip和端口号
    2. ​ 发送和接收数据采用的是io流技术,套接字发送和接收数据,先获取对用的流对象。
    • ​ 常用功能
    1. ​ getOutputStream() :获取字节输出流【专门使用在客户端和服务端流的目标就是客户端和服务端】
    2. ​ getInputStream() :获取字节输入流
    • 服务端
    • ServerSocket:此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果
    • 某些操作:ServerSocket套接字侦听客户端套接字是否入侵服务端,侦听到客户端的套接字,要和该套接字交流,找一个和客户端同一类型的套接字对象。
    • ​ 构造方法:
    1. ​ ServerSocket(int port):创建服务端的套接字对象【内含端口号】
    • ​ 常用方法
    1.  accept() :获取一个和客户端类型一致的套接字对象

    代码示例1:TCP客户端

    • 步骤:
    1. 创建Socket套接字对象
    2. 获取字节输出流
    3. 使用输出流写出内容
    4. 获取字节输入流
    5. 创建读取内容的字节数组
    6. 读取内容
    7. 解析内容
    8. 关闭流资源

    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.util.Scanner;
    public class TCP_Send { public static void main(String[] args) throws Exception, IOException { // 创建键盘录入对象 Scanner scanner = new Scanner(System.in); while(true) { // 创建客户端的套接字对象【链接服务器 需要传入服务器的ip和端口号】 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); // 发送数据和接收数据需要相应的流对象 InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); System.out.println("请输入您要说的话:"); String next = scanner.next(); byte[] bs = next.getBytes(); // 把数据发送出去 os.write(bs); // 接收服务端的回复信息 byte[] bs1 = new byte[1024]; int i = is.read(bs1); System.out.println(new String(bs1,0,i)); os.close(); //关流 is.close(); //关流 } } }

    代码示例2:TCP服务端

    • 步骤:
    1. 创建ServerSocket套接字对象
    2. 提供Socket套接字对象【好和客户端的套接字交流】
    3. 获取字节输入流
    4. 创建读取内容的字节数组
    5. 读取内容
    6. 解析内容
    7. 获取字节输出流
    8. 使用输出流写出内容
    9. 关闭流资源

    import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner;
    public class TCP_Receice { public static void main(String[] args) throws Exception { // 创建服务端的套接字对象 ServerSocket serverSocket = new ServerSocket(9999); // 创建键盘录入对象 Scanner scanner = new Scanner(System.in); while(true) { // 根据客户端的套接字对象生成对应的对象来进行正常的交流 Socket socket = serverSocket.accept(); // 得到输入流对象可以读取【接收发送过来的数据】 InputStream is = socket.getInputStream(); byte[] bs = new byte[1024]; int i = is.read(bs); System.out.println(new String(bs,0,i)); // 给客户端一个回复 OutputStream os = socket.getOutputStream(); System.out.println("请输入您要回复的话:"); String next = scanner.next(); byte[] bs2 = next.getBytes(); os.write(bs2); os.close(); //关流 is.close(); //关流 } } }
    • 加强:一个服务端 ,多个客户端的时候,单线程的时候,客户的需求服务端一个一个的处理,处理第一个客户需求的时候,其他的客户就得等着,处理完了才会处理下一个。同时接受多个客户的需求并进行处理

    服务端代码:

    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    public class TCP_Receice {
        public static void main(String[] args) throws Exception {
            // 创建服务端的套接字对象
            ServerSocket serverSocket = new ServerSocket(9999);
            // 创建键盘录入对象
            Scanner scanner = new Scanner(System.in);
            while(true) {
                // 根据客户端的套接字对象生成对应的对象来进行正常的交流
                // 服务端监测到一个客户端对象来 就给你分配一条线程【安排一个窗口不用等】
                Socket socket = serverSocket.accept();
                // 分配新的线程
                new Thread() {// 一个新的窗口
                    public void run() {
                        // 得到输入流对象可以读取【接收发送过来的数据】
                        InputStream is = null;
                        OutputStream os = null;
                        try {
                            is = socket.getInputStream();
                            byte[] bs = new byte[1024];
                            int i = is.read(bs);
                            System.out.println(new String(bs,0,i));
                            
                            // 给客户端一个回复
                             os = socket.getOutputStream();
                            System.out.println("请输入您要回复的话:");
                            String next = scanner.next();
                            byte[] bs2 = next.getBytes();
                            os.write(bs2);  
                        } catch (IOException e) {
                            e.printStackTrace();
                        }finally {
                            try {
                                if (os != null) {
                                    os.close();
                                }
                                if (is != null) {
                                    is.close();
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            } 
                        }
                    }
                }.start();
            }
        }
    }

    客户端代码:


    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.util.Scanner;
    public class TCP_Send { public static void main(String[] args) throws Exception, IOException { // 创建键盘录入对象 Scanner scanner = new Scanner(System.in); while(true) { // 创建客户端的套接字对象【链接服务器 需要传入服务器的ip和端口号】 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); // 发送数据和接收数据需要相应的流对象 InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); System.out.println("请输入您要说的话:"); String next = scanner.next(); byte[] bs = next.getBytes(); // 把数据发送出去 os.write(bs); // 接收服务端的回复信息 byte[] bs1 = new byte[1024]; int i = is.read(bs1); System.out.println(new String(bs1,0,i)); os.close(); //关流 is.close(); //关流 } }
  • 相关阅读:
    BZOJ4346 : [POI2016]Nadajniki
    BZOJ4345 : [POI2016]Korale
    BZOJ4134 : ljw和lzr的hack比赛
    BZOJ4342 : CF348 Pilgrims
    BZOJ2310 : ParkII
    BZOJ3322 : [Scoi2013]摩托车交易
    BZOJ1444 : [Jsoi2009]有趣的游戏
    Xcode8中处理打印日志的配置
    iOS开发之记录用户登录状态
    热修复
  • 原文地址:https://www.cnblogs.com/nastu/p/12604309.html
Copyright © 2011-2022 走看看