java小白从入门到精通(javase基础十八)

1. 计算机网络基础

1.1 什么是协议?

​ 两个计算机之间进行通信的规则

1.2 常用的协议有哪些?

  • tcp
  • ip
  • udp
  • smtp
  • http
  • https
  • wx

1.3 ip地址

在网络中逻辑上唯一标识一台机器

ip是由32bit二进制组成,每8位标示ip地址的一个字段

1.4 mac地址

物理地址(网卡地址): 物理上唯一标识一台机器
在这里插入图片描述

1.5 子网掩码

与ip地址共同组合得到子网地址

1.6 子网

同处的网络

1.7 常用的ip地址有哪些分类?

  • A类ip地址

    255.0.0.0
    10.0.0.0
    
  • B类IP地址

    255.255.0.0
    172.254.x.x
    
  • C类IP地址

    255,255,255,0
    192.168.1.x
    

1.8 端口

端口: 使用端口号可以标识唯一的一个端口(进程)

我们在实际的生产环境中如果自定义端口,尽量不要使用1024以前的端口号;

1.9 windows中查看ip地址

cmd—>ipconfig

ipconfig /all: 查看完整的网卡信息

1.10 dns

域名解析服务: http://www.baidu.com

把域名解析成ip

1.11 公网地址与内网地址

2. Java中的网络编程

  • 可以使用Java编程语言开发网络的引用程序
  • java中提供的一些列的api来供我们进行网络编程

3. 网络编程的目的

  • 网络就是希望通过 编程+网络协议 的这种方式来实现远程计算机之间的通信

4. 网络协议

在网络通信中有 OSI七层网络模型,过于理想化,在实际的应用中可能不会完全遵守这个osi七层网络模型

我们在实际的网络中,现在有一个大家事实上的标准,TCP/IP网络网络模型

5. OSI七层网络模型

在这里插入图片描述

6. TCP/IP网络模型(事实标准)

在这里插入图片描述
在这里插入图片描述

7. TCP和UDP协议

传输层协议中有两个非常重要的协议

  • 传输控制协议TCP(Transmission Control Protocol)

  • 用户数据报协议UDP(User Datagram Protocol)

7.1 TCP(传输控制协议)

在这里插入图片描述

  • 首先基于tcp协议的通信是要在通信之前建立连接,通信之后关闭连接

  • 数据传输的可靠性增大了

  • 资源消耗较大

7.2 UDP(用户数据报协议)

在这里插入图片描述

  • udp协议是不可靠的协议
  • udp协议的通信效率高

7.3 我们如何选择?

对数据的传输可靠性有要求则使用tcp协议,对数据的传输可靠性没有要求,则使用udp协议

8. Tcp建立连接的过程

https://www.zhihu.com/question/24853633/answer/254224088
在这里插入图片描述

上面的过程就是tcp建立连接过程中的三次握手机制

9. TCP协议的四次挥手

在这里插入图片描述
在这里插入图片描述

10. ping命令

两个机器可以Ping通,证明可以通信;

11. InetAddress类

java.net.InetAddress

InetAddress是封装了域名(主机名称)+ip地址

//InetAddress传递域名,内部会解析其ip地址
InetAddress inetAddress = InetAddress.getByName("baidu.com");
//InetAddress.getLocalHost();返回的InetAddress封装的是本地的主机名称+ip地址
InetAddress inetAddress1 = InetAddress.getLocalHost();
//获取主机名称
System.out.println(inetAddress1.getHostName());
//获取主机地址(ip地址)
System.out.println(inetAddress1.getHostAddress());

12. Java中的远程进程通信

套接字:Socket

Socket就是用来进行远程进程之间的通信的;

13. 基于Tcp的java网络编程

tcp协议:我们如果需要使用tcp协议进行远程进程通信,必须先建立连接,然后才能进行通信,最后释放资源;

13.1 Tcp的服务(Server)端

package com.uplooking.tcp;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {
    private static BufferedInputStream bis;
    private static ServerSocket serverSocket;
    private static Socket socket;

    public static void main(String[] args) {
        try {
            //1. 建立连接(三次握手)
            //1.1 内部绑定端口
            //1.2 内部监听端口
            serverSocket = new ServerSocket(8899);

            //2. 如果有客户端连接到我(服务器),我接收连接
            socket = serverSocket.accept();//接收一个新的客户端的"连接"
            InetAddress inetAddress = socket.getInetAddress();
            System.out.println("有新的客户端连接到我了: " + inetAddress.getHostAddress());

            //3. 开始读取客户端给我发送的数据
            //获取从客户端发送到我(服务器)的数据
            InputStream inputStream = socket.getInputStream();
            //把基础的字节流对象进行包装(缓冲流)
            bis = new BufferedInputStream(inputStream);
            byte[] buf = new byte[1024];
            int len = 0;
            //read()也会阻塞,当连接断开时返回-1
            while ((len = bis.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("word".getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                socket.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

总结:

​ 1)accept()阻塞方法,等待客户端的连接,如果有客户端进来才会解阻塞

​ 2)read()阻塞方法,等待客户端发过来的数据,只有当有数据发送过来的时候,解除阻塞,当连接断开时,read()返回值-1

13.2 Tcp的客户(Client)端

package com.uplooking.tcp;

import sun.reflect.generics.scope.Scope;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * 基于Tcp的客户端
 */
public class TcpClient {
    private static Socket socket;
    private static OutputStream outputStream;

    public static void main(String[] args) {
        try {
            //1. 创建Socket的客户端的对象
            socket = new Socket();

            //2. 给客户端指定一个端口
            socket.bind(new InetSocketAddress(9999));

            //3. 我(客户端)连接到tcp的服务端
            socket.connect(new InetSocketAddress("172.16.6.6", 8899));

            //4. 获取网络字节输出流
            outputStream = socket.getOutputStream();

            //5. 使用输出流对象写数据到网络中
            outputStream.write("hello up".getBytes());
        } catch (IOException e) {
            System.out.println(e);
        } finally {
            try {
                outputStream.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

总结:

​ tcp客户端没有任何的阻塞

14. 基于UDP的java网络编程(了解)

14.1 Udp的发送端的实现

package com.uplooking.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UdpClinet {
    private static DatagramSocket datagramSocket;

    public static void main(String[] args) {
        try {
            //1. 创建DatagramSocket,并且绑定端口
            datagramSocket = new DatagramSocket(9999);
            //2. 连接到udp的主机
            datagramSocket.connect(new InetSocketAddress("172.16.6.6", 8899));

            //3. 创建数据报文
            byte[] buf = "hello".getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(buf, 0, 3);

            //4. 发送数据报文
            datagramSocket.send(datagramPacket);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            datagramSocket.close();
        }
    }

}

14.2 Udp的接收端的实现

package com.uplooking.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * udp的接收端的实现
 */
public class UdpRec {
    private static DatagramSocket datagramSocket;

    public static void main(String[] args) {
        try {
            //1. 创建DatagramerSocket对象,并且绑定端口
            datagramSocket = new DatagramSocket(9999);

            //2. 创建数据报对象,用来接收数据
            byte[] buf = new byte[10];
            int len = buf.length;
            DatagramPacket datagramPacket = new DatagramPacket(buf, 0, len);
            //3. 接收数据(阻塞方法)
            datagramSocket.receive(datagramPacket);
            System.out.println(new String(buf, 0, datagramPacket.getLength()));
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            datagramSocket.close();
        }
    }
}

15. tcp的网络编程优化

上面13中写的tcp的网络编程存在问题吗?

  • 我写的服务器同时只能处理一个客户端的请求

如何解决?

​ 主线程专门用于接收客户端的请求,工作线程用于处理具体的请求

package com.uplooking.tcp1;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class HandlerTaskRunnable implements Runnable {
    private Socket socket;
    private BufferedInputStream bis;

    public HandlerTaskRunnable() {
    }

    public HandlerTaskRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InetAddress inetAddress = socket.getInetAddress();
            System.out.println("有新的客户端连接到我了: " + inetAddress.getHostAddress());
            //3. 开始读取客户端给我(服务器)发送的数据
            //获取从客户端发送到我(服务器)的数据
            InputStream inputStream = socket.getInputStream();
            //把基础的字节流对象进行包装(缓冲流)
            bis = new BufferedInputStream(inputStream);
            byte[] buf = new byte[1024];
            int len = 0;
            //read()也会阻塞,当连接断开时返回-1
            while ((len = bis.read(buf)) != -1) {
                System.out.println(socket.getInetAddress().getHostAddress() + "====>" + new String(buf, 0, len));
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("word".getBytes());
            }
            System.out.println(socket.getInetAddress().getHostAddress() + "::断开了");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}

package com.uplooking.tcp1;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class HandlerTaskRunnable implements Runnable {
    private Socket socket;
    private BufferedInputStream bis;

    public HandlerTaskRunnable() {
    }

    public HandlerTaskRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InetAddress inetAddress = socket.getInetAddress();
            System.out.println("有新的客户端连接到我了: " + inetAddress.getHostAddress());
            //3. 开始读取客户端给我(服务器)发送的数据
            //获取从客户端发送到我(服务器)的数据
            InputStream inputStream = socket.getInputStream();
            //把基础的字节流对象进行包装(缓冲流)
            bis = new BufferedInputStream(inputStream);
            byte[] buf = new byte[1024];
            int len = 0;
            //read()也会阻塞,当连接断开时返回-1
            while ((len = bis.read(buf)) != -1) {
                System.out.println(socket.getInetAddress().getHostAddress() + "====>" + new String(buf, 0, len));
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("word".getBytes());
            }
            System.out.println(socket.getInetAddress().getHostAddress() + "::断开了");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}

16. 通过上面的改良还有啥问题?

  • 传统的socket存在两个地方的阻塞(accept read),这样我们如果处理的客户端的请求特别多的时候(并发量大),cpu轮训执行的线程太多了,cpu压力大;

  • 传统的Socket把其成为BIO(block input output);同步(阻塞)IO

  • **后面讲(nio aio netty)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值