# 1、概述


  • 计算机之间通过传输介质、通信设施和网络通信协议互联,实现资源共享和数据传输。而我们的网络编程就是 ** 使用程序使互联网的两个(或多个)计算机之间进行数据传输。** 当然 java 语言,为了实现两个计算机之间的数据传输,提供了一系列的接口,使得开发人员可以方便的实现。

# 2、OSI 与 TCP/IP 模型


# 模型对比

image-20200623105550900.png

  • TCP/IP 支持跨层封装 ;但 OSI 不支持
  • TCP/IP 仅仅支持 IP 网络协议 ;OSI 支持多种网络层协议
  • TCP 是面向连接的可靠的传输协议
  • UDP 是非面向连接的不可靠的传输协议

# TCP/IP 模型中的协议剖析

image-20200623110038567.png

  • 该模型中几个主要的协议术语及其作用

    • TCP(传输控制协议):通过使用一个校验码检验数据是否发生错误,在接收和转发中都使用计算校验和,并同时对数据进行加密

    • UDP(用户数据报协议):UDP 使用底层的互联网协议来传送报文,同 IP 一样提供不可靠的无连接数据包传输服务。它不提供报文到达确认、排序、及流量控制等功能

    • FTP(文件传输协议):让用户连接上一个远程计算机(这些计算机上运行着 FTP 服务器程序)察看远程计算机有哪些文件,然后把文件从远程计算机上拷到本地计算机,或把本地计算机的文件送到远程计算机去。

    • SMTP(邮件消息传输协议):SMTP 是一种提供可靠且有效电子邮件传输的协议。它是建立在 FTP 文件传输服务上的一种邮件服务,主要用于传输系统之间的邮件信息并提供来信有关的通知。

    SMTP 重要的特性之一是它能跨越网络传输邮件,也即 “SMTP 邮件中继”。使用 SMTP,可实现相同网络上处理机之间的邮件传输,也可以通过中继器或网关实现某处理机与其它网络之间的邮件传输。具有域名服务系统 (DNS) 功能的邮件交换服务器还可以用来识别出传输邮件的下一跳 IP 地址。

# 3、IP


  • IP(网际协议) :提高网络可扩展性,为主机提供一种无连接的数据传输服务
  • 唯一定位一台网络上的计算机
  • 127.0.0.1 为本机地址 localhost

# 4、端口(port)


  • 端口表示计算机的一个程序的进程

    • 不同的进程有不同的端口号,并且端口号不能重复(单个协议下)

    • 端口号范围限制为 0 ~ 65535

    • 端口分类

      • 公有端口 0 ~ 1023

        • HTTP :80
        • HTTPS :443
        • FTP : 21
        • Telnet :23
      • 程序注册端口: 1024 ~ 49151 分配用户或程序

        • Tomcat :8080
        • MySQL :3306
        • Oracle :1521
      • 动态私有 49152 ~ 65535

        netstat -ano #查看所有端口
        netstat -ano|findstr "8080" # 查看指定端口
        tasklist|findstr "8696" # 查看指定端口的进程
        ctrl + shift +ESC # 调用任务管理器

# 5、TCP 实现聊天


  • 客户端(Client)

    1. 获取服务端的地址与端口号

    2. 连接服务器端口,建立 socket 连接

    3. 发送信息(IO 流)

    4. 关闭资源

      Socket socket = null;
      OutputStream os = null;
              try {
                  // 首先要知道服务端的地址和端口号
                  InetAddress serverIp = InetAddress.getByName("127.0.0.1");
                  int port = 9999;
                  // 建立 socket 连接
                  socket = new Socket(serverIp,9999);
                  // 发送信息
                  os = socket.getOutputStream();
                  os.write("我们已经成为好友,可以开始聊天".getBytes());
              } catch (Exception e) {
                  e.printStackTrace();
              }finally {
                  if (os != null){
                      try {
                          os.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (socket != null){
                      try {
                          socket.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
  • 服务端(Server)

    1. 建立 socket 服务器端口

    2. 调用端口的 accept 方法,等待用户端连接

    3. 读取用户信息(IO 流)的 inputStream

    4. 建立管道流,把数据从字节流转换为字符流

    5. 关闭资源

      ServerSocket serverSocket = null;
           Socket socket = null;
            InputStream is = null;
              ByteArrayOutputStream baos = null;
              try {
                  // 给一个服务端的地址
                   serverSocket = new ServerSocket(9999);
                  // 等待客户端接入
                   socket = serverSocket.accept();
                  // 读取客户端信息
                   is = socket.getInputStream();
                  // 管道流
                   baos = new ByteArrayOutputStream();
                  byte[] buffer = new byte[1024];
                  int len;
                  while ((len=is.read(buffer))!= -1){
                      baos.write(buffer,0,len);
                  }
                  System.out.println(baos.toString());
              } catch (IOException e) {
                  e.printStackTrace();
              }finally {
                  // 关闭资源
                  if(baos !=null){
                      try {
                          baos.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (is !=null){
                      try {
                          is.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (socket != null){
                      try {
                          socket.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (serverSocket != null){
                      try {
                          serverSocket.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }

# 6、TCP 实现文件上传


  • 服务端(Server)

    public static void main(String[] args) throws Exception {
            // 创建服务
            ServerSocket serverSocket = new ServerSocket(9000);
            // 监听客户端连接
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream is = socket.getInputStream();
        	// 此处写文件路径最好使用绝对路径,否则会报错
            File file = new File("G://IDEA_Project/FIST/src/receive.jpg");
            // 文件输出
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer))!=-1){
                fos.write(buffer,0,len);
            }
            // 通知客户端接收完毕
            OutputStream os = socket.getOutputStream();
            os.write("服务端接收完毕,你可以断开连接".getBytes());
            // 关闭资源 (后创建先关闭原则)
            fos.close();
            is.close();
            socket.close();
            serverSocket.close();
        }
    • 客户端(client)

      public static void main(String[] args) throws Exception {
              // 创建一个 socket 连接
              Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
              // 建立一个输出流
              OutputStream os = socket.getOutputStream();
      		// 此处写文件路径最好使用绝对路径,否则会报错
              File file = new File("G://IDEA_Project/FIST/src/lld.jpg");
              // 读取文件
              FileInputStream fis = new FileInputStream(file);
              // 写入文件
              byte[] buffer = new byte[1024];
              int len;
              while ((len= fis.read(buffer)) !=-1){
                  os.write(buffer,0,len);
              }
              // 通知服务器,我已经结束啦
              socket.shutdownOutput();
              // 确认服务端接收完毕,才断开连接
              InputStream is = socket.getInputStream();
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              byte[] buffer2 =new byte[1024];
              int len2;
              while ((len2 = is.read(buffer2)) != -1){
                  baos.write(buffer2,0,len2);
              }
              System.out.println(baos.toString());
              // 关闭资源 (后创建先关闭原则)
              baos.close();
              is.close();
              fis.close();
              os.close();
              socket.close();
          }

# 7、UDP 实现消息的发送


  • 客户端

    public static void main(String[] args) throws Exception {
            // 建立一个 socket
            DatagramSocket socket = new DatagramSocket();
            // 建立数据包
            String msg = "Hello,Server!";
            // 发送目的地
            InetAddress localhost = InetAddress.getByName("localhost");
            int port =9090;
            // 数据,数据长度的起始,目的地信息
            DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
            // 发送包
            socket.send(packet);
            // 关闭流
            socket.close();
        }
  • 服务端

    public static void main(String[] args) throws Exception {
            // 开放端口
            DatagramSocket socket = new DatagramSocket(9090);
            // 接收数据包
            byte[] buffer = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
            // 接收包
            socket.receive(packet);
    		// 打印输出目的端地址及数据内容
            System.out.println(packet.getAddress().getHostName());
            System.out.println(new String(packet.getData(), 0, packet.getLength()));
            // 关闭流
            socket.close();
        }

# 8、UDP 实现循环发送


  • Sender 端

    public static void main(String[] args) throws Exception {
            // 建立端口
            DatagramSocket socket = new DatagramSocket(8888);
            // 数据,通过控制台输入数据
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while (true){
                String data =  reader.readLine();
                byte[] datas = data.getBytes();
                DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
                socket.send(packet);
                if (data.equals("bye")){
                    break;
                }
            }
            socket.close();
        }
  • Receive 端

    public static void main(String[] args) throws Exception {
            DatagramSocket socket = new DatagramSocket(6666);
            while (true){
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container, 0, container.length);
                // 阻塞式接收
                socket.receive(packet);
                byte[] data = packet.getData();
                String receiveData = new String(data, 0, data.length);
                System.out.println(receiveData);
    		
                if (receiveData.equals("bye")){
                    break;
                }
            }
    		// 关闭流
            socket.close();
        }
  • 实际示例:
    • 在线咨询:通信双方既是发送方,也是接收方

请我喝[茶]~( ̄▽ ̄)~*

Peter Pan 微信支付

微信支付

Peter Pan 支付宝

支付宝