网络编程

网络编程

1. 概念

2. 网络模型

  • OSI 7层

    • 应用层

    • 表示层

    • 会话层

    • 传输层

    • 网络层

    • 数据链路层

    • 物理层

  • TCP/IP 4层

    • 应用层

    • 传输层

    • 网络层

    • 网络接口层

3. 网络通信三要素

4. 协议:TCP/UDP/IP

  • TCP:传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制,通过三次握手建立连接,通过四次挥手断开连接。

  • UDP:UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,数据包大小限制64KB。

  • IP:IP是Internet Protocol(网际互连协议)的缩写。IP协议主要包含三方面内容:IP编址方案、分组封装格式及分组转发规则。

    • ip地址分类

      • A类:地址范围1.0.0.1到127.255.255.254

      • B类:地址范围128.0.0.1-191.255.255.254

      • C类:地址范围192.0.0.1-223.255.255.254

    • 特殊IP地址

      • 特殊的网址

        1. 255.255.255.255:子网广播地址。

        2. 127.0.0.1 本机地址。

    • 域名 domain

    • ipconfig 在cmd 窗口查看本机ip

    • ping x.x.x.x

5. 端口号

  • 取值范围[0-65535]

  • [0-1023] 分配给了一些常用的应用程序

  • package com.qf.net;

    /**
    * 网络相关的概念:
    * 1:网络,将设备(电脑+手机)通过有线|无线的方式连接在一起。
    * 2:网络的分类
    * 1:局域网 LAN
    * 2:城域网   (校园网)
    * 3:广域网   www 万维网
    * 3:网络的作用:
    *   1:资源共享
    *   2:数据传输
    *
    * 4:java 中的关于网络相关的类:java.net
    *  
    * 5:网络通信参考模型
    * 1:OSI 七层参考模型,(理论的)
    * 2:TCP/IP 实际的通信模型。
    *  
    * 6:网路通信的三要素:
    * 1:ip地址。ip地址决定了和网络中的哪台计算机交互。
    * 2:端口号:端口号决定了和计算机中的哪个软件交互。
    * 3:通信协议:数据传输的规则。
    *  
    * 7:IP地址:
    * PIV4:由4 bytes 构成。使用 三个 . 分开了4bytes。每个字节的取值范围[0-255]
    * 0.0.0.0   255.255.255.255
    *  
    * 分类:
    * 1:公网地址。
    * 可以通过浏览器直接访问的。
    * 2:私网地址。
    * ipv4不够用了。
    * 局域名满足需求。局域网中的电脑的ip地址,就是私网地址。
    * A类地址:10.0.0.0~10.255.255.255
    B类地址:172.16.0.0 ~172.31.255.255
    C类地址:192.168.0.0~192.168.255.255
    *  
    * 域名:Domain:浏览器输入一个网址,回撤,本质上是访问了网络中的一台主机中的一个文件。
    * 如果直接使用ip地址去定位主机。 一般是使用一个域名 (www.baidu.com)来替代ip地址去访问主机。
    * 如何将域名和ip地址对应上?域名解析器 DNS。Domain name system
    * DNS:域名解析服务器。就是一台电脑。负责将域名解析为 域名对应的ip地址。然后再通过ip地址去访问主机。
    *
    * 特殊的ip地址:
    * 1: 127.0.0.1 本机测试地址。
    * 2:localhost   127.0.0.1   ip地址的域名
    * 3:255.255.255.255 广播地址。
    *  
    * 8:端口号 port
    * 1:就是一个整数。
    * 2:取值范围 [0-65535]
    * 3: 80 端口 8080 端口 [0-1023]范围的端口是预留的端口,
    * 我们可以使用[1024-5000] 范围内的端口号进行通信。
    * 4:端口不是一个硬件设备,是一个虚拟的编号。
    *  
    *  
    * 9:协议: protocol
    * TCP协议(掌握)
    * 1:传输层协议。
    * 2:基于字节流的、面向连接的、可靠的、安全的、全双工的协议。
    * 面向连接的:先建立连接然后再传输数据。类似于打电话。
    * 可靠的安全的是基于一套机制实现的。
    * 全双工:收发数据可以同时进行。
    *
    * 机制:
    * 三次握手:
    * 建立连接的过程
    * 1:A 给 B :我可以连接你吗?
    * 2:B 给 A:可以,来吧。
    * 3:A 给 B:好的,我现在就连接你。
    * 四次挥手:
    * 断开连接的过程
    * 1:A 给 B 数据发送完毕,你检查一下是否都接收到了。
    * 2:B 给 A,你等一下,我检查一下。
    * 3:B 给 A,数据接收完毕,你可以断开了。
    * 4:A 给 B ,好的,拜拜。
    *  
    * 优点:安全,可靠。
    * 缺点:占用系统资源、要传输一些辅助数据,保证数据的安全。浪费流量。
    *
    * UDP协议(了解)
    * 特点:不安全,不可靠,面向非连接的,基于数据报的协议。
    * 类似于写信。  
    *
  •  

5. InetAddress

package com.qf.net;

import java.net.InetAddress;

/**
* InetAddress:
* 封装的是主机的【ip地址+主机名】
*
*/
public class InetAddressTest {

public static void main(String[] args) throws Exception {
// 获得本机的 InetAddress 对象。
InetAddress host = InetAddress.getLocalHost();
System.out.println(host);//qq-358586145/10.9.25.181

// 获得 百度 的服务器的主机地址 + 名称。
InetAddress address = InetAddress.getByName("www.baidu.com");
System.out.println(address);//www.baidu.com/110.242.68.3

InetAddress address1 = InetAddress.getByName("localhost");
System.out.println(address1);//localhost/127.0.0.1

// 获取百度 所有的服务器的地址。
InetAddress[] addresses = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inetAddress : addresses) {
System.out.println(inetAddress);
}

// 回环测试地址。
InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
System.out.println(loopbackAddress);//localhost/127.0.0.1
}
}

 

6. Socket 编程

  • Socket

  • ServerSocket

  • 案例

    • 简单的客户端给服务器发送信息

    • package com.qf.socket;

      import java.io.InputStream;
      import java.io.ObjectInputStream;
      import java.io.OutputStream;
      import java.net.Socket;

      /**
      * 客户端代码。
      *
      */
      public class MyClient {

      public static void main(String[] args) throws Exception{
      // 连接服务器。
      Socket socket = new Socket("127.0.0.1", 1777);

      // 得到信息通道的输出流对象。
      OutputStream os = socket.getOutputStream();
      InputStream is = socket.getInputStream();

      String str = "千万里我追寻着你";
      byte[] bytes = str.getBytes();

      os.write(bytes);
      os.flush();

      // 读取服务器的反馈。
      ObjectInputStream ois = new ObjectInputStream(is);
      System.out.println("服务器的反馈:"+ois.readBoolean());

      // 在finally 中
      socket.close();

      }
      }

      package com.qf.server;

      import java.io.InputStream;
      import java.io.ObjectOutputStream;
      import java.io.OutputStream;
      import java.net.ServerSocket;
      import java.net.Socket;

      /**
      * 服务器端代码。
      * @author Administrator
      *
      */
      public class MyServer {

      public static void main(String[] args) throws Exception{
      // 创建一个服务器对象,用于给所有的客户端提供的服务的。
      ServerSocket server = new ServerSocket(1777);

      // 负责接收客户端的请求,阻塞式方法。只有客户端连接请求发生过来了,该方法才能返回。
      // 一旦有请求过来了,该方法立即返回,并生成一个socket对象。
      // socket 对象中包含了,请求的信息。
      Socket socket = server.accept();
      System.out.println("连接成功,"+socket);

      // 获取输入流,读取数据。
      InputStream is = socket.getInputStream();
      OutputStream os = socket.getOutputStream();

      byte[] buf = new byte[100];
      int count = is.read(buf);

      String msg = new String(buf,0,count);
      System.out.println("客户端发送来了:"+msg);

      // 给客户端回馈一个boolean值。
      ObjectOutputStream oos = new ObjectOutputStream(os);
      oos.writeBoolean(true);
      oos.flush();

      // 在finally 中
      // Closing this socket will also close the socket's InputStream and OutputStream.
      socket.close();
      // 关闭服务。
      server.close();
      //
      }

      }

    •  

    • 客户端上传文件给服务器

    • package com.qf.socket;

      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.BufferedWriter;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.InputStream;
      import java.io.OutputStream;
      import java.io.OutputStreamWriter;
      import java.net.Socket;


      public class UpLoadClient {

      public static void main(String[] args) throws Exception {
      upload();
      }

      // 读取本地字节数据,发送。
      private static void upload() throws Exception{
      Socket socket = new Socket("127.0.0.1",1777);

      InputStream is = socket.getInputStream();
      OutputStream os = socket.getOutputStream();

      File file = new File("./res/线程状态图.png");

      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));

      // 先发送文件的名字。
      BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
      bw.write(file.getName());
      bw.newLine();
      bw.flush();

      BufferedOutputStream bos = new BufferedOutputStream(os);

      byte[] buf = new byte[100];

      int count = 0;
      while((count = bis.read(buf)) != -1){
      //
      bos.write(buf, 0, count);
      bos.flush();
      }

      bis.close();

      socket.close();
      }

      }
      ..................................................................

      package com.qf.server;

      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.BufferedReader;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.io.OutputStream;
      import java.net.ServerSocket;
      import java.net.Socket;

      public class FileServer {

      public static void main(String[] args) throws Exception {
      ServerSocket server = new ServerSocket(1777);

      Socket socket = server.accept();

      InputStream is = socket.getInputStream();
      OutputStream os = socket.getOutputStream();

      BufferedInputStream bis = new BufferedInputStream(is);

      // 读取文件的名字
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      String fileName = br.readLine();

      // 写到磁盘上。
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./res/"+fileName));

      byte[] buf = new byte[200];

      int count = bis.read(buf);
      while(count != -1){
      bos.write(buf, 0, count);
      bos.flush();

      count = bis.read(buf);
      }
      bos.close();

      socket.close();
      server.close();
      }

      }
    •  

    • 多个客户端上传文件给服务器

    • package com.qf.server;

      import java.io.BufferedInputStream;
      import java.io.BufferedOutputStream;
      import java.io.BufferedReader;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.io.OutputStream;
      import java.net.ServerSocket;
      import java.net.Socket;

      import com.qf.util.MyUtil;

      public class FileServer2 {

      public static void main(String[] args) throws Exception {
      ServerSocket server = new ServerSocket(1777);
      // 使用主线程负责和多个客户端创建连接。
      try {
      while (true) {
      Socket socket = server.accept();
      // 每来一个客户端,生成一个线程去处理他的请求。
      new ReceiveThread(socket).start();
      }
      } finally {
      server.close();
      }
      }
      }

      class ReceiveThread extends Thread {
      private Socket socket;

      public ReceiveThread(Socket socket) {
      super();
      this.socket = socket;
      }

      @Override
      public void run() {
      try {
      InputStream is = socket.getInputStream();
      OutputStream os = socket.getOutputStream();

      BufferedInputStream bis = new BufferedInputStream(is);

      // 读取文件的名字
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      String fileName = br.readLine();

      // 写到磁盘上。
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:/res/" + fileName));

      byte[] buf = new byte[200];

      int count = bis.read(buf);
      while (count != -1) {
      bos.write(buf, 0, count);
      bos.flush();

      count = bis.read(buf);
      }
      bos.close();
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      MyUtil.closeAll(socket);
      }

      }
      }
  • 聊天功能

  • package com.qf.socket;

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.net.Socket;

    import com.qf.util.MyUtil;

    /**
    * 发送数据的
    * 接收键盘输入。将输入文本。发送出去。
    *
    */
    public class ChatClient {

    public static void main(String[] args) {
    Socket client = null;
    final BufferedReader br;
    try {
    // 连接服务器。
    client = new Socket("localhost",1777);
    // 接收键盘输入的。
    br = new BufferedReader(new InputStreamReader(System.in));

    OutputStream os = client.getOutputStream();
    InputStream is = client.getInputStream();

    // 字符--字节---写出去
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));

    // 线程负责发送数据。
    new Thread(){
    public void run() {
    try {
    while(true){
    // 读取一行数据。
    String line = br.readLine();
    // 将读取的数据发送出去。
    bw.write(line);
    bw.newLine();
    bw.flush();
    //
    if("bye".equals(line)){
    System.exit(0);
    break;
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    MyUtil.closeAll(br);
    }
    };
    }.start();


    BufferedReader serverBr = new BufferedReader(new InputStreamReader(is));
    // 负责接收数据的线程。
    new Thread(){
    public void run() {
    try {
    while(true){
    String line = serverBr.readLine();
    System.out.println("服务器:"+line);
    }
    } catch (Exception e) {
    e.printStackTrace();
    }

    };
    }.start();

    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    // MyUtil.closeAll(client);
    }
    }

    }


    /////////////////////////////////////////////////////////////////////////////
    package com.qf.server;

    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;

    import com.qf.util.MyUtil;

    public class ChatServer {

    public static void main(String[] args) {
    ServerSocket server = null;
    Socket socket = null;
    //ServerSocket 提供服务的。
    try {
    // 提供创建连接的服务。
    server = new ServerSocket(1777);

    socket = server.accept();
    // 获取对方的ip地址。
    String clientAddress = socket.getInetAddress().getHostAddress();

    InputStream is = socket.getInputStream();
    OutputStream os = socket.getOutputStream();

    BufferedReader br = new BufferedReader(new InputStreamReader(is));

    // 负责 接收线程。
    new Thread(){
    public void run() {
    try {
    while(true){
    String line = br.readLine();
    System.out.println( clientAddress + "客户端:" + line);

    if("bye".equals(line)){
    System.exit(0);
    break;
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    };
    }.start();


    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
    Scanner scanner = new Scanner(System.in);
    // 线程负责发送数据。
    new Thread(){
    public void run() {
    try {
    while(true){
    // 读取一行数据。
    String line = scanner.next();
    // 将读取的数据发送出去。
    bw.write(line);
    bw.newLine();
    bw.flush();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    MyUtil.closeAll(br);
    }

    };
    }.start();

    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    // MyUtil.closeAll(socket,server);
    }
    }

    }
  •  

7. UDP 编程

  • DatagramPacket

  • DatagramSocket

  • 案例

    • 简单的信息的收发

    • package com.qf.udp;

      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;

      public class TestUdp {

      public static void main(String[] args) throws Exception{
      // 使用指定的端口号进行通信。
      DatagramSocket ds = new DatagramSocket(1777);

      byte[] buf = new byte[100];
      //接收数据的对象。利用 DatagramPacket 对象将接收到的数据存入 指定的 buf中。
      DatagramPacket dp = new DatagramPacket(buf, buf.length);
      // 将接收到的数据存入 dp 中的buf 中。 阻塞方法。
      ds.receive(dp);
      // 接收到的字节个数。
      int length = dp.getLength();
      // 还原 buf 中的字节数据到 字符串。

      String msg =  new String(buf,0,length);

      System.out.println("接收到的信息:"+msg);

      // 回复一个信息。
      // 获取发送方的信息
      InetAddress address = dp.getAddress();
      int port = dp.getPort();

      // 回复的数据报
      String str = "大家好才是真的好";
      byte[] buf1 = str.getBytes();
      DatagramPacket dp1 = new DatagramPacket(buf1, buf1.length, address, port);

      ds.send(dp1);

      ds.close();
      }
      }

      ---------------------------------------------
      package com.qf.udp;

      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;

      /**
      * DatagramSocket
      * 负责发送和接收数据报的类型。
      * DatagramPacket
      * 被发送的数据。
      *
      * 优点:
      * 效率高
      * 缺点:不安全、数据包的大小有限制。
      *
      */
      public class TestUdp {

      public static void main(String[] args) throws Exception{
      String msg = "你好";
      byte[] data = msg.getBytes();

      // 创建发送数据的对象。
      DatagramSocket ds = new DatagramSocket();

      // 目标地址。
      InetAddress addresses = InetAddress.getByName("127.0.0.1");

      // 创建被发送的数据对象。
      DatagramPacket dp = new DatagramPacket(data, data.length, addresses, 1777);

      //发送数据
      ds.send(dp);

      byte[] buf = new byte[100];
      DatagramPacket dp1 = new DatagramPacket(buf, buf.length);
      ds.receive(dp1);

      String str = new String(buf,0,dp1.getLength());
      System.out.println("回复信息:"+str);

      ds.close();
      }

      }
    •  

    • 聊天室

    • package com.qf.udp;

      import java.awt.Button;
      import java.awt.FlowLayout;
      import java.awt.Frame;
      import java.awt.Label;
      import java.awt.TextArea;
      import java.awt.TextField;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.awt.event.WindowAdapter;
      import java.awt.event.WindowEvent;
      import java.net.DatagramPacket;
      import java.net.DatagramSocket;
      import java.net.InetAddress;
      import java.net.SocketException;
      import java.net.UnknownHostException;

      /**
      * 聊天室
      */
      public class ChatRoomTest {

      public static void main(String[] args) {
      new ChatRoom();
      }

      }

      class ChatRoom {
      public static final int PORT = 1777;

      private DatagramSocket ds;

      private Frame frame;
      private TextArea area;
      private TextField ipField;
      private TextField msgField;
      private Button sendBtn;

      private Label ipLabel;
      private Label msgLabel;

      public ChatRoom() {
      initFrame();

      try {
      ds = new DatagramSocket(PORT);
      } catch (SocketException e) {
      e.printStackTrace();
      }

      receiveMsg();
      }

      private void initFrame() {
      frame = new Frame("千峰聊天室");
      frame.setSize(500, 500);
      frame.setLocation(500, 100);
      // 关闭功能
      frame.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
      System.exit(0);
      }
      });
      frame.setResizable(false);

      // 设置布局
      frame.setLayout(new FlowLayout());

      initConponents();

      frame.add(area);
      frame.add(ipLabel);
      frame.add(ipField);
      frame.add(msgLabel);
      frame.add(msgField);
      frame.add(sendBtn);

      frame.setVisible(true);
      }

      // 初始化组件
      private void initConponents() {
      area = new TextArea(23, 66);
      ipField = new TextField(50);
      msgField = new TextField(50);

      ipLabel = new Label("对方IP地址:");
      msgLabel = new Label("发送内容:");

      sendBtn = new Button("发送");

      // 给按钮添加单击事件
      sendBtn.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
      // 点击发送执行的代码
      // 获取输入丶内容。转换为字节数组。
      String msg = msgField.getText();
      byte[] buf = msg.getBytes();

      String ipStr = ipField.getText();

      try {
      InetAddress address = InetAddress.getByName(ipStr);
      DatagramPacket dp = new DatagramPacket(buf, buf.length, address, PORT);
      ds.send(dp);

      // 清空内容
      msgField.setText("");

      // 将发送的内容,显式在area 中。
      area.append("【我】: " + msg + "\n");
      } catch (Exception e1) {
      e1.printStackTrace();
      }
      }
      });
      }

      // 接收其他人的数据。
      private void receiveMsg() {
      new Thread() {
      public void run() {
      try {
      byte[] buf = new byte[200];
      // 接收数据的对象。利用 DatagramPacket 对象将接收到的数据存入 指定的 buf中。
      DatagramPacket dp = new DatagramPacket(buf, buf.length);
      while (true) {
      // 将接收到的数据存入 dp 中的buf 中。 阻塞方法。
      ds.receive(dp);
      // 接收到的字节个数。
      int length = dp.getLength();
      // 还原 buf 中的字节数据到 字符串。
      String msg = new String(buf,0,length);
      String msg1 = new String(buf,0,length,"utf-8");
      // 将msg 显式在 area 中。
      String ipStr = dp.getAddress().getHostAddress();

      // 自己的发送个了自己。
      if(ipStr.equals(InetAddress.getLocalHost().getHostAddress())){
      // ipStr = "我";
      continue;
      }

      area.append("【"+ipStr + "】 : " + msg + "("+msg1+")\n");
      }
      } catch (Exception e) {
      e.printStackTrace();
      }
      };
      }.start();
      }
      }
    •  

 

 

 

 

 

 

 

 

 

 

 

posted @   ITboy搬砖人  阅读(87)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示