26-网络通信

网络通信

什么是网络编程?
可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)。
java.net.包下提供了网络编程的解决方案!
基本的通信架构有2种形式:CS架构( Client客户端/Server服务端 ) 、 BS架构(Browser浏览器/Server服务端)。

26-网络通信_第1张图片

26-网络通信_第2张图片

我们java的重点是开发BS架构
无论是CS架构,还是BS架构的软件都必须依赖网络编程

网络通信的三要素

  1. IP地址 设备在网络中的地址,是唯一的标识。
  2. 端口 应用程序在设备中唯一的标识
  3. 协议 连接和数据在网络中传输的规则。

IP地址

IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标志。
IP地址有两种形式:IPv4、IPv6

IPV4

26-网络通信_第3张图片

IPV6

32为的IP地址根本不够为我们如此多的IP的地址进行编号,所以演变出了IPV6地址
IPv6:共128位,号称可以为地球每一粒沙子编号。
IPv6分成8段表示,每段每四位编码成一个十六进制位表示, 数之间用冒号(:)分开。
26-网络通信_第4张图片

IP域名

域名就是最后也要转化为IP的
26-网络通信_第5张图片

特殊IP

公网IP,内网IP
公网IP:是可以连接互联网的IP地址;内网IP:也叫局域网IP,只能组织机构内部使用。
192.168. 开头的就是常见的局域网地址,范围即为192.168.0.0–192.168.255.255,专门为组织机构内部使用。
特殊IP地址:非常重要
127.0.0.1、localhost:代表本机IP,只会寻找当前所在的主机。
IP常用命令:
ipconfig:查看本机IP地址。
ping IP地址:检查网络是否连通。

InerAddress命令
名称 说明
public static InetAddress getLocalHost() 获取本机IP,会以一个inetAddress的对象返回
public static InetAddress getByName(String host) 根据ip地址或者域名,返回一个inetAdress对象
public String getHostName() 获取该ip地址对象对应的主机名。
public String getHostAddress() 获取该ip地址对象中的ip地址信息。
public boolean isReachable(int timeout) 在指定毫秒内,判断主机与该ip对应的主机是否能连通
举例
    public static void main(String[] args) {
        try {
            InetAddress ia = InetAddress.getLocalHost();  //获取本机IP
            InetAddress bd = InetAddress.getByName("www.baidu.com");  //获取这个网址的ip
            System.out.println(ia);  //输出这个本机ip的主机
            System.out.println(ia.getHostName());  //输出这个本机ip的名字
            System.out.println(ia.getHostAddress()); //输出这个本机ip的地址
            System.out.println(bd.isReachable(1000)); //判断baidu的主机和本机是否能够在1000ms内进行连接成功
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出结果
DESKTOP-ROKA7MJ/111.111.111.1 (这个本机ip我已经修改了,防止自己的ip泄露,这里随便编了一个,为了能够更好的展示结果)
DESKTOP-ROKA7MJ
111.111.111.1
www.baidu.com/180.101.50.188
true

端口号

端口
标记正在计算机设备上运行的应用程序的,被规定为一个 16 位的二进制,范围是 0~65535。
分类
周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)
注册端口:1024~49151,分配给用户进程或某些应用程序。
动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出错。

协议

网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式网络互联标准:OSI网络参考模型
OSI网络参考模型:全球网络互联标准。
TCP/IP 网络模型:事实上的国际标准。(大四的课程, 进行网络通信)

OSI网络参考模型 TCP/IP网络模型 各层对应 面向操作
应用层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
表示层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
会话层 应用层 HTTP、FTP、SMTP… 应用程序需要关注的:浏览器,邮箱。程序员一般在这一层开发
传输层 传输层 UDP、TCP… 选择使用的TCP , UDP协议
网络层 网络层 IP… 封装源和目标IP
数据链路层 数据链路层+ 物理 比特流… 物理设备中传输
物理层 数据链路层+ 物理 比特流… 比特流…

UDP(User Datagram Protocol):用户数据报协议; TCP(Transmission Control Protocol) :传输控制协议。

UDP协议

特点:无连接、不可靠通信。
不事先建立连接,数据按照包发,一包数据包含:自己的IP、程序端口,目的地IP、程序端口和数据(限制在64KB内)等。
发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的 。
语音童话,还有视频直播我们可以用这个UDP通信,因为数据的丢失对这个影响不大

TCP协议

特点:面向连接、可靠通信。
TCP的最终目的:要保证在不可靠的信道上实现可靠的传输。
TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。

26-网络通信_第6张图片

26-网络通信_第7张图片

26-网络通信_第8张图片

UDP通信的快速入门

常用方法

UDP通信
特点:无连接、不可靠通信。
不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。
Java提供了一个java.net.DatagramSocket类来实现UDP通信。
DatagramSocket: 用于创建客户端、服务端

构造器 说明
public DatagramSocket() 创建客户端的Socket对象, 系统会随机分配一个端口号。
public DatagramSocket(int port) 创建服务端的Socket对象, 并指定端口号
方法 说明
public void send(DatagramPacketdp) 发送数据包
public void receive(DatagramPacket p) 使用数据包接收数据

DatagramPacket:创建数据包

构造器 说明
public DatagramPacket(byte[] buf, int length, InetAddress address, int port) 创建发出去的数据包对象
public DatagramPacket(byte[] buf, int length) 创建用来接收数据的数据包
方法 说明
public int getLength() 获取数据包,实际接收到的字节个数

一发一收

创建一个客户端对象

    public static void main(String[] args) throws Exception {
        //1. 创建客户端对象,发数据的人
        DatagramSocket ds = new DatagramSocket();

        //2 创建数据包对象封装要发出去的数据(创建一个韭菜盒子)  
        //参数一:封装要发出去的数据
        //参数二,发出去的数据大小,字节个数
        //参数三:服务端的IP地址
        // 参数四: 服务端程序的端口
        byte[] bytes = "我爱你,你爱我,蜜雪冰城甜蜜蜜".getBytes();
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);
        ds.send(dp);
        System.out.println("客户端数据发送完毕");
        ds.close(); //释放资源
    }

创建一个服务端对象,注册端口

    public static void main(String[] args) throws Exception {
        //创建一个服务端对象,注册端口
        System.out.println("------------");
        DatagramSocket ds = new DatagramSocket(6666);
        //创建一个数据包对象,用于接受数据
        byte [] bytes = new byte[1024*64]; //一个数据包最大不能超过64kb,所以我们接收的时候最好用最大的,防止接收不完
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        ds.receive(dp);
        //读取多少就倒出多少
        String s = new String(bytes,0,dp.getLength());
        System.out.println(s);

    }

多发多收

客户端.可以多次运行

        Scanner input  = new Scanner(System.in);
        while (true) {
            System.out.println("请说");
            String msg = input.nextLine();
            //退出这个循环
            if(msg.equals("end")){
                System.out.println("退出成功,欢迎下次使用");
                ds.close(); //释放资源
                break;
            }
            byte[] bytes = msg.getBytes();
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);
            ds.send(dp);
            System.out.println("客户端数据发送完毕");
        }

服务端没有必要关闭

        DatagramSocket ds = new DatagramSocket(6666);
        byte [] bytes = new byte[1024*64]; //一个数据包最大不能超过64kb,所以我们接收的时候最好用最大的,防止接收不完
        while (true) {
            System.out.println("------------");
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
            ds.receive(dp);
            //读取多少就倒出多少
            String s = new String(bytes,0,dp.getLength());
            System.out.println(s);
        }

TCP通信

一定要注意前后服务端和客户端要一一对应,否则就容易出错

特点:面向连接、可靠通信。
通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端。
Java提供了一个java.net.Socket类来实现TCP通信。

26-网络通信_第9张图片

TCP通信之-客户端开发

客户端程序就是通过java.net包下的Socket类来实现的。

常用方法

构造器 说明
public Socket(String host , int port) 根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
方法 说明
public OutputStream getOutputStream() 获得字节输出流对象
public InputStream getInputStream() 获得字节输入流对象

TCP通信之-服务端开发

服务端是通过java.net包下的ServerSocket类来实现的。

构造器 说明
public ServerSocket(int port) 为服务端程序注册端口
方法 说明
public Socket accept() 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象。

举例

单发单收
服务端, 从外读input

 //服务端的开发
        ServerSocket serverSocket = new ServerSocket(8888);
        //使用servesocket对象,调用accept[t方法,等待客户端的连接请求
        Socket accept = serverSocket.accept();
        //从socket通信管道中获取一个字节输入流
        InputStream is = accept.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        //读取数据
        System.out.println(dis.readUTF());
        dis.close();
        serverSocket.close();

客户端,往外写 output

//创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);

        //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        dos.writeUTF("我喜欢你");
        dos.close();
        socket.close();

多发多收
服务端, 从外读 input

//服务端的开发
        ServerSocket serverSocket = new ServerSocket(8888);
        Socket accept = serverSocket.accept();
        //使用servesocket对象,调用accept[t方法,等待客户端的连接请求
        //从socket通信管道中的大奥一个字节输入流
        InputStream is = accept.getInputStream();
        DataInputStream dis = new DataInputStream(is);
        while (true) {
            System.out.println("------------");
            //读取数据
            System.out.println(dis.readUTF());
        }

客户端, 往外写output

        //创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        Scanner input = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        while (true) {
            //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
            String msg = input.nextLine();
            if(msg.equals("end")){
                System.out.println("退出客户端");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(msg);
            dos.flush();
            System.out.println("写入成功");
        }

如果我们这个客户端挂了,那么服务端也会挂

TCP通信,支持与多个客户端同时通信

目前我们开发的服务端程序,是否可以支持与多个客户端同时通信 ?
不可以的。
因为服务端现在只有一个主线程,只能处理一个客户端的消息。
UDP不需要进行连接,只需要进行发送数据包就好了
26-网络通信_第10张图片
所以我们要又多线程来实现多个客户端进行通信
服务端,创建多线程

        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器启动");
        while (true) {
            Socket accept = serverSocket.accept();
            System.out.println("有人上线了,地址是"+accept.getRemoteSocketAddress() );
            new TCPThread(accept).start();
        }

线程对象

public class TCPThread extends Thread{
    private Socket socket;
    public TCPThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run(){
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true) {
                //读取数据,防止服务端关闭这里崩溃
                try {
                    System.out.println(dis.readUTF());
                    System.out.println(socket.getRemoteSocketAddress()+"输入了数据:");
                } catch (Exception e) {
                    System.out.println(socket.getRemoteSocketAddress()+"关闭");
                    socket.close();
                    dis.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端

        //创建socker对象,并同时请求与服务器程序的连接
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        Scanner input = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();
        //BufferedOutputStream bos = new BufferedOutputStream(os);
        //把低级的字节输出流,包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        while (true) {
            //从cocket通信管道中得到一个字节输出流,用来发数据给服务端程序
            String msg = input.nextLine();
            if(msg.equals("end")){
                System.out.println("退出客户端");
                dos.close();
                socket.close();
                break;
            }
            dos.writeUTF(msg);
            dos.flush();
            System.out.println("写入成功");
        }

你可能感兴趣的:(#,JavaSE学习笔记,网络,学习,笔记,java)