网络编程;InetAddress类;UDP协议和TCP协议;Socket编程;UDP编程;TCP编程 (Java Day26)
一,网络编程概念
- 网络:就是不同地域,不同型号、不同ip等多台计算机相互连接沟通形成的通信系统
-  元素:
-  看得见的元素:网线、交换机、计算机、内存条等一系列的硬件设备
-  看不见的元素:传输协议、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的范围。
- 作用:能够通过他准确的找到计算机中正在运行的进程
- 端口号的分配:
- 程序在启动的时候计算机随机自动分配端口号
- 程序中人为的指定端口号 比如 : 第二阶段 安装 mysql 时会有一个端口号设置 3306 【默认的】一般情况下默认不改
- 常用的端口号:
-  系统程序:0到1024
-  MySQL:3306
-  Oracle:1521
-  Tomcat:8080
-  QQ:4000
- 
通信协议
- 概述:数据在传输过程中接收、发送,处理等操作是有规则。不同的场景有不同的协议,往往不同的协议协同合作维护网络编程的环境。
- 网络分层:分工作业
-  应用层:对数据的发送和接收进行处理工作 HTTP协议、HTTPS协议、FTP协议。
-  传输层:把数据从一端传输到另一端 TCP协议 UDP协议【今天要讲的协议】
-  网络层:规划线路连接 IP协议
-  物理层:相关的硬件设施
二,InetAddress类
- 概述:此类表示互联网协议 (IP) 地址。【对ip的相关特征和行为的描述,一般包括主机和IP地址】
- 获取对象的方式:【静态方法】
-  getAllByName(String host): 通过主机名称获取对应的所有IP地址对象的数组
-  getByAddress(byte[] addr):通过IP地址的字节数组获取IP地址的对象
-  getByAddress(String host, byte[] addr):通过主机名称和IP地址的字节数组获取IP地址的对象
-  getByName(String host):通过主机名称获取对应的IP地址对象
-  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地址
- 获取对象的属性常用方法:
-  getAddress():返回对象的原始IP地址
-  getHostName(): 返回对象的主机名称
-  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发消息、短信、微博留言、邮件等方式。所以不用管对方在不在线,直接操作数据,但是数据发出去之后有可能收不到,安全性低,效率高。不区分客户端和服务端,只有发送端和接收端。
- 特点:
- 数据不安全
- 效率高
- TCP:面向连接的传输协议。要求对方必须在线并且连接成功。区分客户和服务,把发送数据段叫做客户端,接收数据端就做服务端。
-  如何进行连接的?
-  三次握手:瞬间就可以完成的。
-  第一次:发送端发出信号给接收端
-  第二次:接收端接到信号给出回应
-  第三次:发送端收到回应确定连接成功
- 特点:
- 数据安全性有保证
- 效率低
四,Socket编程【套接字编程】
- Socket : 套接字
-  套接字:传输层编程是端到端的编程,套接字就是端和端进行交流的中间服务
-  举例: 网购 客户 网上买了东西 商家 把东西邮寄给你
-  客户:发送端
-  商家: 服务端
-  快递:把货在商家和客户之间进行传输 就是套接字
- Socket编程在不同的协议下使用的套接字不一样。
- UDP协议:DatagramSocket
- TCP协议:
-  客户端:Socket
-  服务端:ServerSocket
五,UDP编程
- DatagramSocket:他是UDP编程的套接字 ,此类表示用来发送和接收数据报包的套接字
- 数据报包【DatagramPacket】:指包装了发送的数据和接收数据数据的一个容器。【发送和接收的内容、发送的ip地址、端口号等内容】
- 构造方法
-  DatagramSocket():获取套接字对象【一般用于发送端】
-  DatagramSocket(int port):获取套接字对象【一般用于接收端】
- 常用方法:
-  send(DatagramPacket dp):发送数据报包出去
-  receive(DatagramPacket dp):接收数据报包
- DatagramPacket :数据报包
-  通过构造方法来封装相关数据的构造方法:
-  DatagramPacket(byte[] buf, int offset, int length, InetAddressaddress, int port):用于发送端
-  DatagramPacket(byte[] buf, int offset, int length):用于接收端
-  说明:
-  buf:存放发送或接收数据内容的字节数组
-  offset:buf 数组从哪个角标开始发送或接收,代表开始的角标值
-  length:代表发送内容的长度,或者接受数组长度
-  address:发送端发送目标ip地址
-  port:发送的目标端口号
-  数据报包的常用方法【获取数据报包内部的数据的方法】
-  getData():获取数据报包中的内容数组
-  getLength():获取数据报包中有效内容的长度
代码示例1,UDP发送端
- 发送端编写步骤:
- 获取套接字对象
- 准备发送的相关数据
- 获取数据报包同时封装发送的数据
- 发送数据报包
- 准备接收数据的容器【字节数组相关数据】
- 准备一个接收数据的数据报包
- 接收数据
- 解析数据
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接收端
- 接收端编写步骤:
- 获取套接字
- 准备接收容器【字节数组的相关数据】
- 接收数据到数据报包
- 解析接收到的数据【数据报包方法】
- 准备回应的内容【字节数组】
- 将内容添加到接收使用的数据报包中
- 将该数据报包发送回发送端
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编程
- 客户端:
-  Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点
-  构造方法
-  Socket(InetAddress address, int port):创建套接字对象,包含了目标的ip和端口号
-  发送和接收数据采用的是io流技术,套接字发送和接收数据,先获取对用的流对象。
-  常用功能:
-  getOutputStream():获取字节输出流【专门使用在客户端和服务端流的目标就是客户端和服务端】
-  getInputStream():获取字节输入流
- 服务端:
-  ServerSocket:此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果
- 某些操作:ServerSocket套接字侦听客户端套接字是否入侵服务端,侦听到客户端的套接字,要和该套接字交流,找一个和客户端同一类型的套接字对象。
-  构造方法:
-  ServerSocket(int port):创建服务端的套接字对象【内含端口号】
-  常用方法
-  accept():获取一个和客户端类型一致的套接字对象
代码示例1:TCP客户端
- 步骤:
- 创建Socket套接字对象
- 获取字节输出流
- 使用输出流写出内容
- 获取字节输入流
- 创建读取内容的字节数组
- 读取内容
- 解析内容
- 关闭流资源
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服务端
- 步骤:
- 创建ServerSocket套接字对象
- 提供Socket套接字对象【好和客户端的套接字交流】
- 获取字节输入流
- 创建读取内容的字节数组
- 读取内容
- 解析内容
- 获取字节输出流
- 使用输出流写出内容
- 关闭流资源
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();  //关流
        }
    } 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号