java网络通信

浏览器中输入:“www.woaijava.com”之后都发生了什么?

请详细阐述
由域名→IP地址 寻找IP地址的过程依次经过了浏览器缓存、系统缓存、hosts文件、路由器缓存、 递归搜索根域名服务器
建立TCP/IP连接(三次握手具体过程)
由浏览器发送一个HTTP请求,经过路由器的转发,通过服务器的防火墙,该HTTP请求到达了服务器
服务器处理该HTTP请求,返回一个HTML文件
浏览器解析该HTML文件,并且显示在浏览器端
这里需要注意:
HTTP协议是一种基于TCP/IP的应用层协议,进行HTTP数据请求必须先建立TCP/IP连接
可以这样理解:HTTP是轿车,提供了封装或者显示数据的具体形式Socket是发动机,提供了网络通信的能力。(四元组–对应ip 端口,目标ip 端口)
两个计算机之间的交流无非是两个端口之间的数据通信,具体的数据会以什么样的形式展现是以不同的应用层协议来定义的。

简单来说是:
1、用户在浏览器中输入 url 地址
2、浏览器解析域名得到服务器 ip 地址
3、TCP 三次握手建立客户端和服务器的连接
4、客户端发送 HTTP 请求获取服务器端的静态资源
5、服务器发送HTTP 响应报文给客户端,客户端获取到页面静态资源
6、TCP 四次挥手关闭客户端和服务器的连接
7、浏览器解析文档资源并渲染页面

lnetAddress

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对应的主机是否能连通

协议

在这里插入图片描述
传输层的协议:TCP、UDP
UDP(User Datagram Protocol): 用户数据报协议;TCP(Transmission ControlProtocol): 传输控制协议。
UDP协议

  • 特点: 无连接、不可靠通信。
  • 不事先建立连接,数据按照包发,一包数据包含:自己的IP、程序端口,目的地IP、程序端口和数据(限制在64KB内)等。
  • 发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的。

TCP协议

  • 特点:面向连接、可靠通信。
  • TCP的最终目的:要保证在不可靠的信道上实现可靠的传输
  • TCP主要有三个步骤实现可靠传输:三次握手建立连接,传输数据进行确认,四次挥手断开连接。
  • 如果只有两次握手,那么只能知道客户端的起始地址,不能知道服务端的起始地址。其实就是,三次握手中是将对方下次发送的起始序列号给互相告知了
    在这里插入图片描述

UDP客户端程序

/**
 * 目标:完成UDP通信快速入门:实现1发1收。
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建客户端对象(发韭菜出去的人)
        DatagramSocket socket = new DatagramSocket(7777);

        // 2、创建数据包对象封装要发出去的数据(创建一个韭菜盘子)
       /* public DatagramPacket(byte buf[], int length,
             InetAddress address, int port)
               参数一:封装要发出去的数据。
               参数二:发送出去的数据大小(字节个数)
               参数三:服务端的IP地址(找到服务端主机)
               参数四:服务端程序的端口。
             */
        byte[] bytes = "我是快乐的客户端,我爱你abc".getBytes();
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length
                , InetAddress.getLocalHost(),  6666);

        // 3、开始正式发送这个数据包的数据出去了
        socket.send(packet);

        System.out.println("客户端数据发送完毕~~~");
        socket.close(); // 释放资源!
    }
}

UDP服务端程序

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("----服务端启动----");
        // 1、创建一个服务端对象(创建一个接韭菜的人) 注册端口
        DatagramSocket socket = new DatagramSocket(6666);

        // 2、创建一个数据包对象,用于接收数据的(创建一个韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 64KB.
        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);

        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(packet.getPort());

        socket.close(); // 释放资源
    }
}

UDP通讯api
在这里插入图片描述

TCP的java实现

  1. 当创建Socket对象时,就会在客户端和服务端创建一个数据通信的管道,在客户端和服务端两边都会有一个Socket对象来访问这个通信管道。
  2. 现在假设客户端要发送一个“在一起”给服务端,客户端这边先需要通过Socket对象获取到一个字节输出流,通过字节输出流写数据到服务端
  3. 然后服务端这边通过Socket对象可以获取字节输入流,通过字节输入流就可以读取客户端写过来的数据,并对数据进行处理。
  4. 服务端处理完数据之后,假设需要把“没感觉”发给客户端端,那么服务端这边再通过Socket获取到一个字节输出流,将数据写给客户端
  5. 客户端这边再获取输入流,通过字节输入流来读取服务端写过来的数据。

总结:输入数据是获取字节输出流,获取数据是获取字节输入流

/**
 *  目标:完成TCP通信快速入门-客户端开发:实现客户端可以反复的发消息出去
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建Socket对象,并同时请求与服务端程序的连接。
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
        OutputStream os = socket.getOutputStream();

        // 3、把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();

            // 一旦用户输入了exit,就退出客户端程序
            if("exit".equals(msg)){
                System.out.println("欢迎您下次光临!退出成功!");
                dos.close();
                socket.close();
                break;
            }

            // 4、开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}
/**
 *  目标:完成TCP通信快速入门-服务端开发:实现服务端反复发消息
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();

        // 3、从socket通信管道中得到一个字节输入流。
        InputStream is = socket.getInputStream();

        // 4、把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        while (true) {
            try {
                // 5、使用数据输入流读取客户端发送过来的消息
                String rs = dis.readUTF();
                System.out.println(rs);
            } catch (Exception e) {
                System.out.println(socket.getRemoteSocketAddress() + "离线了!");
                dis.close();
                socket.close();
                break;
            }
        }
    }
}

TCP怎么实现服务端与多个客户端通讯

在这里插入图片描述
首先要写一个服务端读取数据的线程类(此处这个线程类继承了Tread,这是一种创建线程的方法)

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);

                } catch (Exception e) {
                    System.out.println("有人下线了:" + socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

不断接受新的连接,并各自的连接数据分别给不同的线程去处理

/**
 *  目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();

            System.out.println("有人上线了:" + socket.getRemoteSocketAddress());

            // 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
            new ServerReaderThread(socket).start();
        }
    }
}

实现聊天功能,实现客户端之间的互通

在这里插入图片描述

```java
public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                    // 把这个消息分发给全部客户端进行接收。
                    sendMsgToAll(msg);
                } catch (Exception e) {
                    System.out.println("有人下线了:" + socket.getRemoteSocketAddress());
                    Server.onLineSockets.remove(socket);
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendMsgToAll(String msg) throws IOException {
        // 发送给全部在线的socket管道接收。
        for (Socket onLineSocket : Server.onLineSockets) {
            OutputStream os = onLineSocket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}

BS架构实现页面TCP多连接通信

/**
 *  目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();

            System.out.println("有人上线了:" + socket.getRemoteSocketAddress());

            // 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
            new ServerReaderThread(socket).start();
        }
    }
}

使用线程池完成BS架构的网络通讯

使用ThreadPoolExecutor 创建线程池,每次接收到一个Socket就往线程池中提交任务就行

public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8080);

        // 创建出一个线程池,负责处理通信管道的任务。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(8) , Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        while (true) {
            // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();

            // 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
            pool.execute(new ServerReaderRunnable(socket));
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值