22_网络编程

网络编程

1. 什么是网络

  • 线构成,表示诸多对象间的相互联系

2. 什么是计算机网络

  • 为实现资源共享和信息传递,通过通信线路连接起来的若干主机(Host)
  • 按照地理范围网络分为:
    • 局域网
    • 城域网
    • 广域网
      • 互联网: (Internet) 点与点相连
      • 万维网: (WWW - World Wide Web) 端与端相连
      • 物联网: (IOT - Internet of things) 物与物相连
  • 网络编程: 让计算机与计算机之间建立连接,进行通信

3. 网络模型-OSI参考模型

  • OSI (Open System Interconnection) 开放式系统互联
    • 第七层: 应用层负责文件访问和管理, 可靠运输服务, 远程操作服务(HTTP, FTP, SMTP)
    • 第六层: 表示层负责定义转换数据格式及加密, 允许选择以二进制或ASCII格式传输
    • 第五层: 会话层负责使应用建立和维持会话, 使通信在失效时继续恢复通信 (断点续传)
    • 第四层: 传输层负责是否选择差错恢复协议, 数据流重用, 错误顺序重排 (TCP, UDP)
    • 第三层: 网络层负责定义了能够标识所有网络节点的逻辑地址 (IP地址)
    • 第二层:链路层在物理层上,通过规程或协议 (差错控制) 来控制传输数据的正确性 (MAC)
    • 第一层: 物理层为设备之间的数据通信提供传输信号和物理介质 (双绞线, 光导纤维)

4. 网络模型-TCP/IP模型

  • 一组用于实现网络互连的通信协议, 将协议分为四个层次
    • 第四层: 应用层负责传送各种最终形态的数据, 是直接与用户打交道的层, 典型协议是HTTP, FTP等
    • 第三层: 传输层负责传送文本数据, 主要协议是TCP, UDP协议
    • 第二层: 网络层负责分配地址和传送二进制数据, 主要协议是IP协议
    • 第一层:接口层负责建立电路连接, 是整个网络的物理基础, 典型的协议包括以太网, ADSL等等

5.TCP/UDP

  • TCP协议 : Transmission Control Protocol 传输控制协议
    • 是一种面向连接的, 可靠的, 基于字节流的传输层通信协议. 数据大小无限制.建立连接的过程需要三次握手, 断开连接的过程需要四次挥手
  • UDP协议: User Datagram Protocol 用户数据报协议
    • 是一种无连接的传输层协议, 提供面向事务的简单不可靠信息传送服务, 每个包的大小64KB

6. IP

  • IP协议: Internet Protocol 互联网协议/网际互连协议
    • 负责数据从一台机器发送到另一台机器
    • 给互联网每台设备分配一个唯一标识 (IP地址)
  • IP地址分为两种:
    • IPV4: 4字节32位整数, 并分成4段8位的二进制数, 每8位之间用圆点隔开, 每8位整数可以转换为一个0~255的十进制整数
      • 格式: D.D.D.D 例如: 255.255.255.255
    • IPV6: 16字节128位整数, 并分为8段十六进制数, 每16位之间用圆点隔开, 每16位整数可以转换为一个0~65535的十进制数
      • 格式: X.X.X.X.X.X.X.X 例如: FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
  • IPV4的应用分类
    • A类: 政府机构, 1.0.0.1 ~ 126.255.255.254
    • B类: 中型企业, 128.0.0.1 ~ 191.255.255.254
    • C类: 个人用户, 192.0.0.1 ~ 223.255.255.254
    • D类: 用于组播, 224.0.0.1 ~ 239.255.255.254
    • E类: 用于实验, 240.0.0.1 ~ 255.255.255.254
    • 回环地址: 127.0.0.1, 指本机, 一般用于测试使用
    • 测试IP命令: ping D.D.D.D
    • 查看IP命令: ipconfig

7. Port

  • 端口号: 在通信实体上进行网络通讯程序的唯一标识
  • 端口分类:
    • 公认端口: 0~1023
    • 注册端口: 1024~49151
    • 动态或私有端口: 49152~65535
  • 常用端口:
    • Mysql: 3306
    • Oracle: 1521
    • Tomcat: 8080
    • SMTP: 25
    • Web服务器: 80
    • FTP服务器: 21

8.InetAddress

  • 概念: 表示互联网协议(IP)地址对象, 封装了与该IP地址相关的所有信息, 并提供获取信息的常用方法
public static InetAddress getLocalHost() 获得本地主机地址对象
public static InetAddress getByName(String host) 根据主机名称获得地址对象
public static InetAddress[] getAllByName(String host) 获得所有相关地址对象
public String getHostAddress() 获取IP地址字符串
public String getHostName() 获得IP地址主机名
		//1. 创建本机IP地址对象
        //1.1 getLocalhost()方法
        InetAddress ia1 = InetAddress.getLocalHost();
        System.out.println("ip地址: " + ia1.getHostAddress() + "主机名: " + ia1.getHostName());
        //1.2 getByName("ip地址")
        InetAddress ia2 = InetAddress.getByName("192.168.99.1");
        System.out.println("ip地址: " + ia2.getHostAddress() + "主机名: " + ia2.getHostName());
        //1.3 getByName("127.0.0.1")
        InetAddress ia3 = InetAddress.getByName("127.0.0.1");
        System.out.println("ip地址: " + ia3.getHostAddress() + "主机名: " + ia3.getHostName());
        //1.3 getByName("localhost")
        InetAddress ia4 = InetAddress.getByName("127.0.0.1");
        System.out.println("ip地址: " + ia4.getHostAddress() + "主机名: " + ia4.getHostName());

        //2. 创建局域网IP地址对象

//        InetAddress ia5 = InetAddress.getByName("192.168.99.2");
//        System.out.println("ip地址: " + ia5.getHostAddress() + "主机名: " + ia5.getHostName());
//        System.out.println("两秒是否可达:" + ia5.isReachable(2000));

        //3. 创建外网IP地址对象
        InetAddress ia6 = InetAddress.getByName("www.baidu.com");
        System.out.println("ip地址: " + ia6.getHostAddress() + "主机名: " + ia6.getHostName());
        System.out.println("两秒是否可达:" + ia6.isReachable(2000));
        System.out.println("-----------------");
        InetAddress[] ias = InetAddress.getAllByName("www.baidu.com");
        for (InetAddress ia : ias) {
            System.out.println(ia.getHostAddress());
        }

9. 基于TCP的网络编程

(1)Socket编程:

  • Socket(套接字)是网络中的一个通信节点
  • 分为客户端Socket与服务器ServerSocket
  • 通信要求:IP地址 + 端口号

(2)开发步骤

  • 服务器端:
    • 创建ServerSocket, 指定端口号
    • 调用accept等待客户端接入
    • 使用输入流, 接收请求数据到服务器(等待)
    • 使用输出流, 发送响应数据给客户端
    • 释放资源
  • 客户端:
    • 创建Socket, 指定服务器IP + 端口号
    • 使用输出流,发送请求数据给服务器
    • 使用输入流,接收响应数据到客户端(等待)
    • 释放资源
案例一: TCP编程实现客户端发送数据给服务器端

基于TCP协议的服务器端开发

//        * 1. 创建ServerSocket并指定端口号
        ServerSocket listener = new ServerSocket(8899);
//        * 2. 调用accept(), 接收客户端请求,阻塞方法(如果没有客户端请求,则阻塞)
        System.out.println("服务器已启动...");
        Socket socket = listener.accept();
//        * 3. 获取输入流, 读取客户端发送的数据
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
        String data = br.readLine();
        System.out.println("客户端发送: " + data);
//        * 4. 获取输出流, 发送数据给客户端[可选]
//        * 5. 关闭释放资源
        br.close();
        socket.close();
        listener.close();

基于TCP协议的客户端开发

//        *  1. 创建客户端套接字, 并指定服务器的地址和端口号
        Socket socket = new Socket("192.168.0.103", 8899);
//        *  2. 获取输出流, 发送数据给服务器
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "utf-8"));
        bw.write("好久不见!");
//        *  3. 获取输入流, 读取服务器回复的信息[可选]
//        *  4. 关闭释放资源
        bw.close();
        socket.close();

案例二: TCP编程实现客户端上传文件给服务器端

文件传输-服务器端

		//1. 创建ServerSocket
        ServerSocket listener = new ServerSocket(9999);
        //2. 监听,接收客户端请求
        System.out.println("服务器已启动!");
        Socket socket = listener.accept();
        //3. 获取输入流
        InputStream is = socket.getInputStream();
        //4. 边读取,边保存
        FileOutputStream fos = new FileOutputStream("d:\\美女.jpg");
        byte[] buf = new byte[1024];
        int count = 0;
        while ((count = is.read(buf)) != -1){
            fos.write(buf, 0, count);
        }
        //5. 关闭
        fos.close();
        is.close();
        socket.close();
        listener.close();
        System.out.println("接收完毕!");

文件传输-客户端

		//1. 创建Socket
        Socket socket = new Socket("192.168.0.103", 9999);
        //2. 获取输出流
        OutputStream os = socket.getOutputStream();
        //3. 边读取,边发送
        FileInputStream fis = new FileInputStream("d:\\谷歌下载\\4K壁纸.jpg");
        byte[] buf = new byte[1024*4];
        int count = 0;
        while ((count = fis.read(buf)) != -1){
            os.write(buf, 0, count);
        }
        //4. 关闭
        fis.close();
        os.close();
        socket.close();
        System.out.println("发送完毕!");
案例三: TCP编程实现多个客户端发送数据给服务器端

服务器端

public class TcpServer {

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

        //1. 创建ServerSocket
        ServerSocket listener = new ServerSocket(1122);

        //2. 调用accept(), 接收客户端请求
        System.out.println("服务器已启动...");
        while (true){
            Socket socket = listener.accept();//持续接收客户端请求
            System.out.println(socket.getInetAddress() + "进来了...");
            //创建线程对象, 负责接收数据
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (socket != null){
                        BufferedReader br = null;
                        try {
                            InputStream is = socket.getInputStream();//获取字节流
                            br = new BufferedReader(new InputStreamReader(is, "utf-8"));//转换为字符缓冲流
                            while (true){
                                String data = br.readLine();
                                if (data == null){//客户端已经关闭
                                    break;
                                }
                                System.out.println(socket.getInetAddress() + "说: " + data);
                                if (data.equals("886") || data.equals("bye")){
                                    break;
                                }
                            }
                        } catch (IOException e) {
                            //e.printStackTrace();
                        } finally {
                            try {
                                br.close();
                                socket.close();
                                System.out.println(socket.getInetAddress() + "退出了...");
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }).start();
        }

    }

}

客户端

public class TcpClient {

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

        //1.创建Socket
        Socket socket = new Socket("192.168.0.103", 1122);
        //2. 获取字节输出流
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "utf-8"));

        //3. 控制台输出
        Scanner input = new Scanner(System.in);
        System.out.println("请开始聊天: ");
        while (true) {
            String data = input.nextLine();
            bw.write(data);
            bw.newLine();//发送换行符
            bw.flush();
            if (data.equals("886") || data.equals("bye")){
                break;
            }
        }
        //4. 关闭
        bw.close();
        socket.close();
    }
}
案例四: 使用Socket实现注册登录
  • 使用Socket编程实现服务器端注册
    • 注册信息保存在properties文件中
    • 封装格式:
      • id =
      • 注册成功后返回字符串"注册成功"
  • 使用Socket编程实现服务器端登录
    • 获取properties文件中的用户信息, 进行用户id与密码的校验
    • 校验成功后返回字符串"登录成功"

UserServer 用户注册登录服务器端

public class UserServer {

    public static void main(String[] args) {

        new RegisterThread().start();
        new LoginThread().start();
    }
}

UserClient 用户注册登录客户端

public class UserClient {

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

        System.out.println("------欢迎, 请选择: 1. 注册 2. 登陆------");
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();
        switch (choice){
            case 1:
                register();
                break;
            case 2:
                login();
                break;
            default:
                break;
        }
    }
    public static void register() throws Exception {
        //1. 创建Socket
        Socket socket = new Socket("192.168.0.103", 666);
        //2. 获取流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
        //3. 获取用户信息
        String json = getRegisterInfo();
        //4. 发送
        bw.write(json);
        bw.newLine();
        bw.flush();
        //5. 接收
        String reply = br.readLine();
        System.out.println("服务器回复: " + reply);
        //6. 关闭
        bw.close();
        br.close();
        socket.close();
    }

    public static String getRegisterInfo(){
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户编号: ");
        int id = input.nextInt();
        System.out.println("请输入姓名: ");
        String name = input.next();
        System.out.println("请输入密码: ");
        String pwd = input.next();
        System.out.println("请输入年龄: ");
        int age = input.nextInt();
        //{id : "1001", name : "tom", pwd: "123", age: 20}
        String json = "{id:"+id+", name: "+name+", pwd: "+pwd+", age: "+age+"}";

        return json;
    }

    public static void login() throws Exception{
        //1. 创建Socket
        Socket socket = new Socket("192.168.0.103", 777);
        //2. 获取流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
        //3. 获取用户信息
        String json = getLoginInfo();
        //4. 发送
        bw.write(json);
        bw.newLine();
        bw.flush();
        //5. 接收
        String reply = br.readLine();
        System.out.println("服务器回复: " + reply);
        //6. 关闭
        bw.close();
        br.close();
        socket.close();
    }

    public static String getLoginInfo(){
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户编号: ");
        int id = input.nextInt();
        System.out.println("请输入密码: ");
        String pwd = input.next();
        //{id : "1001", pwd: "123"}
        String json = "{id:"+id+", pwd: "+pwd+"}";

        return json;
    }

}

注册

public class RegisterThread extends Thread{

    @Override
    public void run() {

        try {
            //1. 创建ServerSocket
            ServerSocket listener = new ServerSocket(666);
            //2. 调用accept方法
            System.out.println("注册服务器已启动...");
            Socket socket = listener.accept();
            //3. 获取输入输出流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
            //4. 接收客户端发送的数据{id : "1001", name : "tom", pwd: "123", age: 20}
            String json = br.readLine();//id : "1001", name : "tom", pwd: "123", age: 20

            String[] infos = json.substring(1, json.length()-1).split(",");
            String id = infos[0].split(":")[1];
            //5. 加载属性文件
            Properties properties = Tools.loadProperties();
            //6. 判断
            if (properties.containsKey(id)){
                //有
                bw.write("此用户已存在");
            }else{
                //保存属性文件
                Tools.saveProperties(json);
                bw.write("注册成功");
            }
            bw.newLine();
            bw.flush();
            bw.close();
            br.close();
            socket.close();
            listener.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

登录

public class LoginThread extends Thread{

    @Override
    public void run() {
        try {
            //1. 创建ServerSocket
            ServerSocket listener = new ServerSocket(777);
            //2. 调用accept方法
            System.out.println("登陆服务器已启动...");
            Socket socket = listener.accept();
            //3. 获取输入输出流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"));
            //4. 接收客户端发送的数据{id : "1001", pwd: "123"}
            String json = br.readLine();//id : "1001", pwd: "123"

            String[] infos = json.substring(1, json.length()-1).split(",");
            String id = infos[0].split(":")[1];
            //5. 加载属性文件
            Properties properties = Tools.loadProperties();
            //6. 判断是否存在
            if (properties.containsKey(id)){
                //判断密码是否正确
                //id : "1001", pwd: "123"
                String pwd = infos[1].split(":")[1];
                String value = properties.getProperty(id);
                String[] arr = value.substring(1, value.length()-1).split(",");
                String pwd2 = arr[2].split(":")[1];
                if (pwd.equals(pwd2)){
                    bw.write("登陆成功");
                }else{
                    bw.write("密码错误");
                }

            }else{

                bw.write("用户名或密码错误");
            }
            bw.newLine();
            bw.flush();
            bw.close();
            br.close();
            socket.close();
            listener.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

工具类 (用来加载保存文件)

public class Tools {

   //加载属性文件
   public static Properties loadProperties() {
       //1. 创建属性集合
       Properties properties = new Properties();
       //2. 判断文件是否存在
       File file = new File("users.properties");
       if (file.exists()){
           FileInputStream fis = null;
           try {
               fis = new FileInputStream(file);
               properties.load(fis);
           } catch (Exception e) {
               e.printStackTrace();
           }finally {
               if (fis != null){
                   try {
                       fis.close();
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
           }
       }

       return properties;
   }

   //保存属性文件
   public static void saveProperties(String json){
       String[] infos = json.substring(1, json.length()-1).split(",");
       String id = infos[0].split(":")[1];
       //保存
       FileOutputStream fos = null;
       try {
           fos = new FileOutputStream("users.properties", true);
           Properties properties = new Properties();
           properties.setProperty(id, json);
           properties.store(fos, "");
       } catch (Exception e) {
           e.printStackTrace();
       }finally {
           if (fos != null){
               try {
                   fos.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
   }
}

posted @ 2021-03-09 20:46  MARSdoubleZ  阅读(73)  评论(0编辑  收藏  举报