热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

第十六章、网络编程

网络编程1.网编先导知识网络应用开发架构CS即client(客户端)server(服务端)​飞秋、Git、百度云、输入法.BS即browser(浏览器)server(服务器

网络编程

1. 网编先导知识



  1. 网络应用开发架构



    • C / S即client(客户端) / server(服务端)

      ​ 飞秋、Git、百度云、输入法....



    • B / S即browser(浏览器)/ server(服务器)

      ​ 淘宝、邮箱、百度、知乎....



    • B / S是特殊的C / S架构





  2. 网卡:每个实际存在在计算机硬件里面的



  3. mac地址:每块网卡上都有一个全球唯一的mac地址



  4. 交换机:是连接多台机器并帮助通讯的物理设备,只可以识别mac地址



  5. 协议:两台物理设备之间对于要发送的内容,长度和顺序做的一些规范



  6. ip地址(规格)



    • ipv4协议:韦德点分十进制,32位的二进制

      ​ 范围:0.0.0.0~255.255.255.255



    • ipv6协议:8位的冒分十六制,128位十进制来表示 (点分十进制不足以表示)

      ​ 范围:0:0:0:0:0:0:0:0 ~ FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF





  7. ip地址的使用:



    • 如果一个ip地址向北所有人都看到,这个ip地址是必须要申请的,即公网ip



    • 提供内网ip,供局域网使用:

      192.168.0.0 - 192.168.255.255

      172.16.0.0 - 172.31.255.255

      10.0.0.0 - 10.255.255.255





  8. 交换机实现的ARP协议(地址解析协议)



    • 通过ip地址获取一台机器的mac地址



    • 交换机工作原理:收到一个请求,通知所有连接他的ip地址,获取对应的ip地址的mac地址并返回给请求的ip地址





  9. 网关ip:一个局域网的网络出口,访问局域网以外的区域都需要经过路由器的网关



  10. 网段:一般是一个末尾为0的地址段



  11. 子网掩码:判断两个机器是否在同一个网段

    屏蔽一个IP地址的网络部分的“全1”比特模式。对于A类地址来说,默认的子网掩码是255.0.0.0;对于B类地址来说默认的子网掩码是255.255.0.0;对于C类地址来说默认的子网掩码是255.255.255.0

    # 示例:通过将请求的计算的子网掩码和两个要匹配的计算机的二进制按位与运算
    ip = 255.255.255.255
    11111111.11111111.11111111.11111111
    ip = 192.168.12.87
    11000000.10101000.00001100.00000111
    ip = 192.168.12.7


  12. ip地址可以确认一台机器,port端口可以确认一台机器的一个应用,端口的范围:0~65535



  13. 一般实现互联,使用127.0.0.1,是自己的地址,不过减缓及ip地址是可以过交换机的。




2. ISO模型(五层结构)



  1. 物理层



    • 物理层是ISO模型的最底层,负责网络设备在各种物理介质上传输比特流,并规定各种各种物理传输介质、接口的机械特性和电气特性。一般用位表示。



  2. 数据链路层



    • mac地址,ARP协议 物理设备:网卡,交换机。



  3. 网络层



    • IPV4/IPV6协议,物理设备:路由器,三层交换机(交换机具有路由功能)ip通过DNS解析获取(DNS域名和ip互相映射的数据库)



  4. 传输层



    • tcp协议和udp协议,物理设备:端口,四层路由器,四层交换机。



  5. 应用层



    • 应用层 :https/http/ftp/smtp协议 所有的应用层协议是基于tcp或者是udp协议



  6. 数据封装和解封

    数据封装

    图12-3 数据封装.png

    数据解封



图12-4 数据解封.png


3. 传输层的两种协议(tcp/udp)


3.1 tcp协议



  1. 特点



    • 面向连接的,可靠,但是慢,可以实现全双工通信,即双方都是实时的,区别于半双工(传呼机)

    • 无边界,流式传输(导致粘包问题)

    • 长连接:会一直占用双方的端口

    • 能够传输的数据长度几乎没有限制



  2. 三次握手和四次挥手



    • 具体的三次握手(连接方式):

      # accept接受过程中等待客户端的连接
      # connect客户端发起了一个syn连接请求(附带了一个随机数)
      # 如果得到了server端的响应ack的同时还会再收到一个由server端发来的syn链接请求
      # client端进行回复ack之后,就建立起了一个tcp协议的链接
      # 备注:三次握手的过程再代码中是由accept和connect共同完成的,具体的细节再socket中没有体现出来


    • 具体的四次挥手(断开连接方式):

      # server和client端对应的在代码中都有close方法
      # 每一端发起的close操作都是一次fin的断开请求,得到'断开确认ack'之后,就可以结束一端的数据发送
      # 如果两端都发起close,那么就是两次请求和两次回复,一共是四次操作
      # 可以结束两端的数据发送,表示链接断开了




  3. 应用场景



    • QQ和微信等上面的传输压缩文件,缓存下载的电影等等




3.2 udp协议



  1. 特点

    • 面向数据报的,无连接,速度很快,类似于发短信,能实现一对一,多对一,一对多的高效通讯

    • 由于没有回执,对于发送信息和接受信息的双方来说,可能存在丢失消息的情况

    • 能够传递的长度有限,是根据数据传递设备的位置有关系



  2. 应用场景

    • 通信类的 如QQ 微信,发短信, 在线观看小视频等




3.3 Socket



  1. 概念:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。



  2. 原理:进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的

    图12-5 Socket的作用.png



  3. Socket之间的连接过程



    • 服务器监听

    • 客户端请求

    • 连接确认



  4. java实现Socket步骤



    • 创建Socket



    • 打开连接到Socket的输入/出流



    • 按照一定的协议对Socket进行读/写操作



    • 关闭Socket





  5. 代码实现

    // 服务端
    package demo2;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class Server {
    public static void main(String[] args) {
    try {
    // 1.创建服务器socket服务。通过ServerSocket对象,指定端口号
    ServerSocket ss = new ServerSocket(8888);
    System.out.println("服务端等待连接....");
    // 2.获取连接过来的客户端对象,使用accept()
    Socket s = ss.accept(); // 进行阻塞态
    System.out.println("客户端连接成功....");
    // 3.通过客户端对象获取socket流读取客户端发来的数据
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String str = br.readLine();
    System.out.println("客户端发过来的消息是:" + str);
    // 4.通过客户端对象获取socket流向客户端发送数据
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    bw.write("你好,客户端!");

    // 关闭相关资源
    bw.close();
    br.close();
    s.close();
    ss.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }

    // 客户端
    package demo2;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    public class Client {
    public static void main(String[] args) {
    try {
    // Socket(String host,int port);
    // 1.创建Socket对象,指定服务器的ip地址和端口号
    Socket s = new Socket("127.0.0.1", 8888);
    // 2.通过客户端对象获取socket流读取服务端发来的数据
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    bw.write("你好,服务端!");
    bw.flush();
    s.shutdownOutput();
    // 3.通过客户端对象获取socket流读取客户端发来的数据
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String str = br.readLine();
    System.out.println("服务端发送过来的信息是:" + str);
    // 4.关闭相关资源
    br.close();
    bw.close();
    s.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }



4.基于TCP实现Socket编程模型



  • 服务端



    1. 创建ServerSocket类的对象,并提供端口号。



    2. 等待客户端连接,使用accept()方法



    3. 等Socket对象,并使用输入输出流进行通信



    4. 关闭相互资源





  • 客户端



    1. 创建Socket类型的对象,并指定服务器的IP地址和端口号

    2. 使用输入输出流进行通信

    3. 关闭相互资源



  • 代码示例



    • 双向通信

      // 服务端
      package demo2;
      import java.io.BufferedReader;
      import java.io.BufferedWriter;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.OutputStreamWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      /*
      * 建立TCP服务器端思路
      * 1.创建服务器socket服务。通过ServerSocket对象
      * 2.服务器端必须对外提供一个端口,否则客户端无法连接
      * 3.获取连接过来的客户端对象
      * 4.通过客户端对象获取socket流读取客户端发来的数据
      * 5.关闭资源,关闭流,关闭服务器
      */
      public class Server {
      public static void main(String[] args) {
      try {
      // 1.创建服务器socket服务。通过ServerSocket对象,指定端口号
      ServerSocket ss = new ServerSocket(8888);
      System.out.println("服务端等待连接....");
      // 2.获取连接过来的客户端对象,使用accept()
      Socket s = ss.accept(); // 进行阻塞态
      System.out.println("客户端连接成功....");
      // 3.通过客户端对象获取socket流读取客户端发来的数据
      BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
      String str = br.readLine();
      System.out.println("客户端发过来的消息是:" + str);
      // 4.通过客户端对象获取socket流向客户端发送数据
      BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
      bw.write("你好,客户端!");
      // 关闭相关资源
      bw.close();
      br.close();
      s.close();
      ss.close();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }
      }

      // 客户端
      package demo2;
      import java.io.BufferedReader;
      import java.io.BufferedWriter;
      import java.io.InputStreamReader;
      import java.io.OutputStreamWriter;
      import java.net.Socket;
      /*
      * 客户端建立思路
      * 1.创建TCP客户端socket服务,使用的是Socket对象
      * 2.如果连接成功,说明数据传输链接建立成功
      * 通过的是socket流,是底层建立好的
      * 既然是流的话,就应该有输入输出
      * 想要获取输入或输出对象,可以找socket获取
      * 可以通过getOutputStream()和getInputStream()来获取两个字符流
      * 3.使用输入流,将数据写入
      * 4.关闭资源
      *
      * 建立连接后,通过socket中的IO流进行数据传输
      * 向服务器发送:你好,服务器
      * 如果想要使用字符流就需要使用OutputStreamWriter/InputStreamReader 转换流
      */
      public class Client {
      public static void main(String[] args) {
      try {
      // Socket(String host,int port);
      // 1.创建Socket对象,指定服务器的ip地址和端口号
      Socket s = new Socket("127.0.0.1", 8888);
      // 2.通过客户端对象获取socket流读取服务端发来的数据
      BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
      bw.write("你好,服务端!");
      bw.flush();
      s.shutdownOutput();
      // 3.通过客户端对象获取socket流读取客户端发来的数据
      BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
      String str = br.readLine();
      System.out.println("服务端发送过来的信息是:" + str);
      // 4.关闭相关资源
      br.close();
      bw.close();
      s.close();
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
      }


    • 多人聊天室

      // 服务端
      package demo4;
      import java.io.IOException;
      import java.net.ServerSocket;
      import java.net.Socket;
      /*
      * 要求客户端发送的内容由用户手动输入,使用BufferedReader类
      要求服务器收到客户端的消息之后,想客户端回发消息”I Receive!”
      要求服务器和客户端可以不断地进行通信,当客户端发送”bye”时结束通信。
      要求服务能够同时支持多个客户端的连接,而且能够和多个客户端同时聊天,多线程。
      */
      public class Server {
      public static void main(String[] args) {
      try {
      // 1.创建ServerSocket类型的对象。并绑定端口
      ServerSocket ss = new ServerSocket(8999);
      while (true) {
      System.out.println("等待客户端连接...");
      // 等待客户端连接请求
      Socket s = ss.accept();
      System.out.println("客户端" + s.getInetAddress() + "连接成功!");
      // 只要有客户端连接成功,应该启动一个新线程为之服务,主线程始终接待
      new ServerThread(s).start();
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }

      // 服务端线程
      package demo4;
      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.Socket;
      public class ServerThread extends Thread {
      private Socket s;
      public ServerThread(Socket s) {
      this.s = s;
      }
      @Override
      public void run() {
      try {
      // 用来接收客户端发来的内容
      BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
      // 向客户端发送字符串内容”I Receive!“
      PrintStream ps = new PrintStream(s.getOutputStream());

      while (true) {
      String str = br.readLine();
      if ("bye".equalsIgnoreCase(str)) {
      System.out.println("客户端" + s.getInetAddress() + "已下线");
      break;
      }
      System.out.println("客户端" + s.getInetAddress() + "发来的消息是:" + str);
      ps.println("I Receive!");
      }
      ps.close();
      br.close();
      s.close();
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
      }

      // 客户端
      package demo4;
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.Socket;
      import java.net.UnknownHostException;
      public class Client {
      public static void main(String[] args) {
      try {
      // 创建Socket类型的对象,并提供IP地址和端口号
      Socket s = new Socket("localhost", 8999);
      // 使用输入输出流进行通信
      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      // 用来接收服务端发来的内容
      BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
      PrintStream ps = new PrintStream(s.getOutputStream());
      while (true) {
      System.out.println("请输入要发送的内容:");
      String str = br.readLine();
      ps.println(str);
      System.out.println("成功发送数据到服务器");
      // 判断客户端发送的内容是否是"bye",若是则结束通信
      if ("bye".equalsIgnoreCase(str)) {
      break;
      }
      String str2 = br2.readLine();
      System.out.println("服务器端发来的消息是:" + str2);
      }
      br2.close();
      br.close();
      ps.close();
      s.close();
      } catch (UnknownHostException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }
      }





5. 基于UDP实现Socket编程模型



  • 接收方



    1. 创建DatagramSocket类型的对象,并提供端口号



    2. 创建DatagramPacket类型的对象,用于接收发来的数据



    3. 使用上述的对象接收数据内容,使用recieve()方法



    4. 关闭相关资源





  • 发送方



    1. 创建DatagramSocket类型的对象。

    2. 创建DatagramPacket类型的对象,并提供端口号和IP地址

    3. 使用上述的对象发送数据内容,使用send()方法。

    4. 关闭相关资源



  • 代码示例

    // 发送方
    package demo5;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    public class TestRecieve {
    public static void main(String[] args) {
    try {
    // 1.创建DatagramSocket类型的对象
    DatagramSocket ds = new DatagramSocket();
    // 2.创建DatagramPacket类型的对象,并向外提供一个端口号和ip地址
    byte[] data = "hello!".getBytes();
    InetAddress ia = InetAddress.getLocalHost();
    DatagramPacket dp = new DatagramPacket(data, data.length, ia, 8888);
    // 3.发送数据内容,使用send()方法
    ds.send(dp);
    System.out.println("成功发送数据内容!");
    // 4.关闭套接字
    ds.close();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }

    // 接收方
    package demo5;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    public class TestSend {
    public static void main(String[] args) {
    try {
    // 1.创建DatagramSocket类型的对象,并提供端口号
    DatagramSocket ds = new DatagramSocket(8888);
    // 2.创建DatagramPacket类型的对象,用于接收数据内容
    byte[] data = new byte[1024];
    DatagramPacket dp = new DatagramPacket(data, data.length);
    // 3.接收数据内容并保存到数据报中,使用receive()方法
    ds.receive(dp);
    System.out.println("接收到的数据是:" + new String(data, 0, dp.getLength()) + "!");
    // 4.关闭套接字
    ds.close();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }




推荐阅读
  • HTTP协议相关的网络经典五层模型
    网络通信相关概念的讲解–网络协议分层(经典五层模型)在我们了解HTTP相关内容之前我们先来了解一下“网络协议分层”相关内容,因为这个是我们了解HTTP相关内容的前提条件;大家有一 ... [详细]
  • 缤果串口网络蓝牙调试助手的特点和下载链接
    本文介绍了缤果串口网络蓝牙调试助手的主要特点,包括支持常用的波特率、校验、数据位和停止位设置,以及以ASCII码或十六进制接收或发送数据或字符的功能。该助手还能任意设定自动发送周期,并能将接收数据保存成文本文件。同时,该软件支持网络UDP/TCP和蓝牙功能。最后,提供了腾讯微云和百度网盘的下载链接。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文分享了一位Android开发者多年来对于Android开发所需掌握的技能的笔记,包括架构师基础、高级UI开源框架、Android Framework开发、性能优化、音视频精编源码解析、Flutter学习进阶、微信小程序开发以及百大框架源码解读等方面的知识。文章强调了技术栈和布局的重要性,鼓励开发者做好学习规划和技术布局,以提升自己的竞争力和市场价值。 ... [详细]
  • 如何使用PLEX播放组播、抓取信号源以及设置路由器
    本文介绍了如何使用PLEX播放组播、抓取信号源以及设置路由器。通过使用xTeve软件和M3U源,用户可以在PLEX上实现直播功能,并且可以自动匹配EPG信息和定时录制节目。同时,本文还提供了从华为itv盒子提取组播地址的方法以及如何在ASUS固件路由器上设置IPTV。在使用PLEX之前,建议先使用VLC测试是否可以正常播放UDPXY转发的iptv流。最后,本文还介绍了docker版xTeve的设置方法。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了一些好用的搜索引擎的替代品,包括网盘搜索工具、百度网盘搜索引擎等。同时还介绍了一些笑话大全、GIF笑话图片、动态图等资源的搜索引擎。此外,还推荐了一些迅雷快传搜索和360云盘资源搜索的网盘搜索引擎。 ... [详细]
  • php支持中文文件名
    2019独角兽企业重金招聘Python工程师标准大家可能遇到过上传中文文件名的文件,或者读取中文目录时不能读取,出现错误的情况这种情况是因为php自动将中文字符转成了utf8 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • 域名解析系统DNS
    文章目录前言一、域名系统概述二、因特网的域名结构三、域名服务器1.根域名服务器2.顶级域名服务器(TLD,top-leveldomain)3.权威(Authoritative)域名 ... [详细]
author-avatar
SP_Club
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有