JavaSE进阶(day12,复习自用)

网络编程(通信)

  • 网络通信三要素
    • 三要素概述、要素一:IP地址
    • IP地址操作类-InetAddress
    • 要素二:端口号
    • 要素三:协议
  • UDP通信-快速入门
  • UDP通信-广播、组播
  • TCP通信-快速入门
    • 编写客户端代码
    • 编写服务端代码、原理分析
  • TCP通信-多发多收消息
  • TCP通信-同时接受多个客户端消息
  • TCP通信-使用线程池优化
  • TCP通信实战案例-即时通信
  • TCP通信实战案例-模拟BS系统

JavaSE进阶(day12,复习自用)_第1张图片
JavaSE进阶(day12,复习自用)_第2张图片

网络通信三要素

JavaSE进阶(day12,复习自用)_第3张图片

三要素概述、要素一:IP地址

IP地址:设备在网络中的地址,是唯一的标识。

端口:应用程序在设备中唯一的标识。

协议: 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。
JavaSE进阶(day12,复习自用)_第4张图片
JavaSE进阶(day12,复习自用)_第5张图片
JavaSE进阶(day12,复习自用)_第6张图片
JavaSE进阶(day12,复习自用)_第7张图片

IP地址操作类-InetAddress

JavaSE进阶(day12,复习自用)_第8张图片

要素二:端口号

JavaSE进阶(day12,复习自用)_第9张图片

要素三:协议

连接和通信数据的规则被称为网络通信协议
JavaSE进阶(day12,复习自用)_第10张图片
JavaSE进阶(day12,复习自用)_第11张图片
JavaSE进阶(day12,复习自用)_第12张图片
JavaSE进阶(day12,复习自用)_第13张图片
JavaSE进阶(day12,复习自用)_第14张图片

UDP通信-快速入门

UDP是一种无连接、不可靠传输的协议。
将数据源IP、目的地IP和端口以及数据封装成数据包,大小限制在64KB内,直接发送出去即可。
JavaSE进阶(day12,复习自用)_第15张图片
JavaSE进阶(day12,复习自用)_第16张图片
JavaSE进阶(day12,复习自用)_第17张图片
JavaSE进阶(day12,复习自用)_第18张图片

/*
    发送端 一发 一收
 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动==========");

        //1.创建发送端对象:发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6666);

        //2.创建一个数据包对象封装数据(韭菜盘子)
       /* public DatagramPacket(byte buf[], int length,
        InetAddress address, int port)
        参数一:封装要发送的数据(韭菜)
        参数二:发送数据的大小
        参数三:服务端的主机IP地址
        参数四:服务端的端口
        */
        byte[] buffer = "我是一颗快乐的韭菜,你愿意吃吗?".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getLocalHost(),8888);

        //3.发送数据出去
        socket.send(packet);

        socket.close();

    }
}
/*
    接收端
 */
public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动==========");

        //1.创建接收端对象:注册端口(人)
        DatagramSocket socket = new DatagramSocket(8888);

        //2.创建一个数据包对象接受数据(韭菜盘子)
        byte[] buffer = new byte[1024*64];
        DatagramPacket packet = new DatagramPacket(buffer,buffer.length);

        //3.等待接收数据即可
        socket.receive(packet);

        //4.取出数据即可
        //读取多少倒出多少
        int len = packet.getLength();
        String rs = new String(buffer,0,len);
        System.out.println("收到了:" + rs);

        //获取发送端的ip和端口
//        System.out.println(packet.getSocketAddress());//这样也对,比老师的更方便
        String ip = packet.getSocketAddress().toString();
        System.out.println("对方地址:"+ ip);
        int port = packet.getPort();
        System.out.println("对方端口:" + port);


        socket.close();


    }
}

JavaSE进阶(day12,复习自用)_第19张图片
JavaSE进阶(day12,复习自用)_第20张图片
JavaSE进阶(day12,复习自用)_第21张图片

/*
    发送端 多发多收
 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========客户端启动==========");

        //1.创建发送端对象:发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(7777);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            if("exit".equals(msg)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }
            //2.创建一个数据包对象封装数据(韭菜盘子)
            byte[] buffer = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer,buffer.length, InetAddress.getLocalHost(),8888);

            //3.发送数据出去
            socket.send(packet);
        }
    }
}

/*
    接收端
 */
public class ServerDemo2 {
    public static void main(String[] args) throws Exception {
        System.out.println("==========服务端启动==========");

        //1.创建接收端对象:注册端口(人)
        DatagramSocket socket = new DatagramSocket(8888);

        //2.创建一个数据包对象接受数据(韭菜盘子)
        byte[] buffer = new byte[1024*64];
        DatagramPacket packet = new DatagramPacket(buffer,buffer.length);

        while (true) {
            //3.等待接收数据即可
            socket.receive(packet);

            //4.取出数据即可
            //读取多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer,0,len);
            System.out.println("收到了来自:" + packet.getAddress()+",对方端口是"+packet.getPort()+"的消息:"+rs);
        }
    }
}

UDP通信-广播、组播

JavaSE进阶(day12,复习自用)_第22张图片
JavaSE进阶(day12,复习自用)_第23张图片
JavaSE进阶(day12,复习自用)_第24张图片

TCP通信-快速入门

TCP是一种面向连接,安全、可靠的传输数据的协议
传输前,采用“三次握手”方式,点对点通信,是可靠的
在连接中可进行大数据量的传输

JavaSE进阶(day12,复习自用)_第25张图片

编写客户端代码

JavaSE进阶(day12,复习自用)_第26张图片

/*
    目标:完成Socket网络编程入门案例的客户端开发,一发一收
 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.println("=========客户端启动=========");
            //1.创建Socket通信管道请求有服务器的连接
            //public Socket(String host,int port)
            //参数一:服务端的IP地址
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);

            //2.从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            //4.发送消息
            ps.println("我是TCP的客户端,我已经与你对接,并发出邀请:约吗?");
            ps.flush();

            //关闭资源
//            socket.close();




        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

编写服务端代码、原理分析

JavaSE进阶(day12,复习自用)_第27张图片
JavaSE进阶(day12,复习自用)_第28张图片

/*
    目标:开发Socket网络编程入门代码的服务端:实现接收消息
 */
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=========服务端启动成功!=========");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //2.必须调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
            Socket socket = serverSocket.accept();
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            if ((msg = br.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

TCP通信-多发多收消息

JavaSE进阶(day12,复习自用)_第29张图片本案例实现了多发多收,那么是否可以同时接收多个客户端的消息?
不可以的。
因为服务端现在只有一个线程,只能与一个客户端进行通信。
本次多发多收是如何实现的
客户端使用循环反复地发送消息。
服务端使用循环反复地接收消息。
现在服务端为什么不可以同时接收多个客户端的消息。
目前服务端是单线程的,每次只能处理一个客户端的消息。

/*
    目标:实现多发和多收
 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.println("=========客户端启动=========");
            //1.创建Socket通信管道请求有服务器的连接
            //public Socket(String host,int port)
            //参数一:服务端的IP地址
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);

            //2.从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请说:");
                String msg = sc.nextLine();
                //4.发送消息
                ps.println(msg);
                ps.flush();
            }

            //关闭资源
//            socket.close();




        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/*
    目标:开发Socket网络编程入门代码的服务端:实现接收消息
 */
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=========服务端启动成功!=========");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //2.必须调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
            Socket socket = serverSocket.accept();
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }



        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

TCP通信-同时接受多个客户端消息

如何才可以让服务端可以处理多个客户端的通信需求?
引入多线程。

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
        }
    }
}

/*
    目标:实现服务端可以同时处理多个客户端的消息
 */
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=========服务端启动成功!=========");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //a.定义一个死循环由主线程负责不断的接收客户端Socket管道连接
            while (true) {
                //2.每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了");
                //3.开始创建独立线程处理socket
                new ServerReaderThread(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

本次是如何实现服务端接收多个客户端的消息的。
主线程定义了循环负责接收客户端Socket管道连接
每接收到一个Socket通信管道后分配一个独立的线程负责处理它。

TCP通信-使用线程池优化

public class SereverReaderRunnable implements Runnable{
    private Socket socket;
    public SereverReaderRunnable(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
        }
    }
}

/*
    目标:实现服务端可以同时处理多个客户端的消息
 */
public class ServerDemo2 {

    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3,
            5,6, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        try {
            System.out.println("=========服务端启动成功!=========");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(6666);
            //a.定义一个死循环由主线程负责不断的接收客户端Socket管道连接
            while (true) {
                //2.每接收到一个客户端的Socket管道
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了");
                //任务对象负责读取消息
                Runnable target =  new SereverReaderRunnable(socket);
                pool.execute(target);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

TCP通信实战案例-即时通信

即时通信是什么含义,要实现怎么样的设计?
即时通信,是指一个客户端的消息发出去,其他客户端可以接收到。
之前我们的消息都是发给服务端的。
即时通信需要进行端口转发的设计思想。

/*
    目标:实现服务端可以同时处理多个客户端的消息

    1.客户端发送消息
    2.客户端随时可能需要收到消息



 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.println("=========客户端启动=========");
            //1.创建Socket通信管道请求有服务器的连接
            //public Socket(String host,int port)
            //参数一:服务端的IP地址
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);

            //创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发消息过来!)
            new ClientReaderThread(socket).start();

            //2.从socket通信管道中得到一个字节输出流 负责发送数据
            OutputStream os = socket.getOutputStream();

            //3.把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请说:");
                String msg = sc.nextLine();
                //4.发送消息
                ps.println(msg);
                ps.flush();
            }
            //关闭资源
//            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

public class ClientReaderThread extends Thread{
    private Socket socket;
    public ClientReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine())!=null){
                System.out.println("收到消息:" + msg);
            }
        } catch (Exception e) {
            System.out.println("服务端把你踢出去了~~~");
        }
    }
}

/*
    目标:实现服务端可以同时处理多个客户端的消息
 */
public class ServerDemo2 {
    //定义一个静态的List集合存储当前全部在线的socket管道
    public static List<Socket> allOnlineSocket = new ArrayList<>();
    public static void main(String[] args) {
        try {
            System.out.println("=========服务端启动成功!=========");
            //1.注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //a.定义一个死循环由主线程负责不断的接收客户端Socket管道连接
            while (true) {
                //2.每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了");
                allOnlineSocket.add(socket);//上线完成
                //3.开始创建独立线程处理socket
                new ServerReaderThread(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3.从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4.把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5.按照行读取消息
            String msg;
            while ((msg = br.readLine())!=null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
                //把这个消息进行端口转发给全部客户端socket管道
                sendMsgToAll(msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
            ServerDemo2.allOnlineSocket.remove(socket);
        }
    }

    private void sendMsgToAll(String msg) throws Exception {
        for (Socket socket : ServerDemo2.allOnlineSocket) {
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(msg);
            ps.flush();
        }
    }
}

TCP通信实战案例-模拟BS系统

1、之前的客户端都是什么样的
其实就是CS架构,客户端实需要我们自己开发实现的。
2、BS结构是什么样的,需要开发客户端吗?
浏览器访问服务端,不需要开发客户端。
JavaSE进阶(day12,复习自用)_第30张图片

public class ServerReaderRunnable implements Runnable{
    private Socket socket;
    public ServerReaderRunnable(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            // 浏览器 已经与本线程建立了Socket管道
            // 响应消息给浏览器显示
            PrintStream ps = new PrintStream(socket.getOutputStream());
            // 必须响应HTTP协议格式数据,否则浏览器不认识消息
            ps.println("HTTP/1.1 200 OK"); // 协议类型和版本 响应成功的消息!
            ps.println("Content-Type:text/html;charset=UTF-8"); // 响应的数据类型:文本/网页

            ps.println(); // 必须发送一个空行

            // 才可以响应数据回去给浏览器
            ps.println("《最牛的149期》 ");
            ps.close();
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");
        }
    }
}

/**
    了解:BS-浏览器-服务器基本了解。

    引入:
        之前客户端和服务端都需要自己开发。也就是CS架构。
        接下来模拟一下BS架构。

    客户端:浏览器。(无需开发)
    服务端:自己开发。
    需求:在浏览器中请求本程序,响应一个网页文字给浏览器显示


 */
public class BSserverDemo {
    // 使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3,
            5, 6, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2)
            , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        try {
            // 1.注册端口
            ServerSocket ss = new ServerSocket(8080);
            // 2.创建一个循环接收多个客户端的请求。
            while(true){
                Socket socket = ss.accept();
                // 3.交给一个独立的线程来处理!
                pool.execute(new ServerReaderRunnable(socket));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


你可能感兴趣的:(JavaSE进阶,网络,udp,网络协议)