网络编程

概述

需要回顾一些计算机网络知识

  1. 网页编程——javaweb——B/S
  2. 网络编程——TCP/IP——C/S

网络通信的要素

  1. 网络编程中有两个主要的问题
    • 如何准确的定位到网络上的一台或者多台主机
    • 找到主机之后如何进行通信
  2. 网络编程中的要素
    • IP 和 端口号
    • 网络通信协议
  3. 万物皆对象

IP地址表示

Java中网络编程相关资源在net包下,其中表示IP地址的类是InetAddress,具体见帮助文档,一些方法不建议硬记,用到的时候知道在哪里查即可。

//测试IP
public class Demo03 {
    public static void main(String[] args) {
        try {
            //查询本机地址
            InetAddress inetAddress1 = InetAddress.getByName("172.0.0.1");
            System.out.println(inetAddress1);
            InetAddress inetAddress2 = InetAddress.getByName("localhost");
            System.out.println(inetAddress2);
            InetAddress inetAddress3 = InetAddress.getLocalHost();
            System.out.println(inetAddress3);

            //查询网站ip地址
            InetAddress inetAddress4 = InetAddress.getByName("www.baidu.com");
            System.out.println(inetAddress4);

            //常用方法
//            System.out.println(inetAddress4.getAddress());
            System.out.println(inetAddress4.getHostName());//域名,或者自己电脑名字
            System.out.println(inetAddress4.getHostAddress());//ip
            System.out.println(inetAddress4.getCanonicalHostName());//规范名字

        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }
}
/*
/172.0.0.1
localhost/127.0.0.1
-略-
www.baidu.com/39.156.66.14
[B@74a14482
www.baidu.com
39.156.66.14
39.156.66.14
 */

端口

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

  • 不同的进程有不同的端口号!用来区分软件!

  • 被规定 0~65535

  • TCP,UDP:65535 * 2 tcp:80,udp:80吗,单个协议下,端口号不能冲突

  • 端口分类

    • 公有端口 0~1023
      • HTTP:80
      • HTTPS:443
      • FTP:21
      • Telent : 23
    • 程序注册端口:1024~49151,分配用户或者程序
      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    • 动态、私有:49152~65535
  • 常用dos命令

    netstat -ano #查看所有的端口
    netstat -ano|findstr "5900" #查看指定的端口tasklist|findstr "8696" #查看指定端口的进程
    Ctrl+ shift + EsC #任务管理器快捷键
    
  • Java关于端口的方法

    public class Demo04 {
      public static void main(String[] args) {
          InetSocketAddress socketAddress1 = new InetSocketAddress("172.0.0.1", 8080);
          InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080);
          System.out.println(socketAddress1);
          System.out.println(socketAddress2);
    
          System.out.println(socketAddress1.getAddress());
          System.out.println(socketAddress1.getHostName());//地址
          System.out.println(socketAddress1.getPort());//端口号
      }
    

}

### 通信协议

回顾计算机网络中协议是什么,有哪些方面的协议,分层思想,TCP/IP协议簇、和TCP和UDP的区别、TCP连接的建立与断开。可以看一眼石墨文档。

### TCP实现聊天

**客户端**

1. 连接服务器Socket

2. 发送消息

 ```java
 //客户端
 public class TcpClientDemo01 {
     public static void main(String[] args) {
         Socket socket = null;
         OutputStream os = null;
         try {
             //1. 要知道服务器的地址,端口号
             InetAddress serverIP = InetAddress.getByName("127.0.0.1");
             int port = 9999;
             //2. 创建一个socket连接
             socket = new Socket(serverIP, port);
             //3. 发送消息 IO流
             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();
                 }
             }
         }
     }
 }

服务器

  1. 建立服务的端口 ServerSocket

  2. 等待用户的链接 accept

  3. 接收用的消息

    //服务端
    public class TcpServerDemo01 {
        public static void main(String[] args) throws IOException {
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream is = null;
            ByteArrayOutputStream baos = null;
    
            try {
                //1. 我要有一个地址
                serverSocket = new ServerSocket(9999);
                while (true) {
                    //2. 等待客户端连接过来
                    socket = serverSocket.accept();
                    //3. 读取客户端的消息
                    is = socket.getInputStream();
    
                    //管道流,相比传统的的方式,相当于多了一个过滤器,避免出现乱码
                    baos = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int count = 0;
                    while ((count = is.read(buffer)) != -1) {
                        baos.write(buffer, 0, count);
                    }
                    System.out.println(baos.toString());
                }
    
                //传统方式
    //            byte[] buffer = new byte[1024];
    //            int count = 0;
    //            while ((count = is.read(buffer)) != -1) {
    //                String msg = new String(buffer, 0, count);
    //                System.out.println(msg);
    //            }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭资源,后打开的先关闭
                if (baos != null) {
                    baos.close();
                }
                if (is != null) {
                    is.close();
                }
                if (socket != null) {
                    socket.close();
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            }
        }
    }
    

TCP文件上传实现

  • 客户端

    public class TcpClient {
        public static void main(String[] args) throws Exception {
            //1.创建一个Socket连接
            Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
            //2.创建一个输出流
            OutputStream os = socket.getOutputStream();
            //3.读取文件
            FileInputStream fis = new FileInputStream(new File("1.png"));
            //4.写出文件
            byte[] buffer = new byte[1024];
            int count = 0;
            while ((count = fis.read(buffer)) != -1) {
                os.write(buffer, 0, count);
            }
            //通知服务器,我已经结束了
            socket.shutdownOutput();//我已经传输完毕了
            //确定服务器接收完毕,才能够断开连接,这里打印出来了
            InputStream inputStream = socket.getInputStream();
            //Stirng byte[]
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer2 = new byte[1024];
            int count2;
            //getInputStream() 方法本身并不阻塞,但后续从该流中读取数据时(如使用 read() 方法),通常是阻塞式的
            while ((count2 = inputStream.read(buffer2)) != -1) {
                baos.write(buffer2, 0, count2);
            }
            System.out.println(baos.toString());
    
            //5.关闭资源
            baos.close();
            inputStream.close();
            fis.close();
            os.close();
            socket.close();
        }
    }
    
  • 服务器

    public class TcpServer {
        public static void main(String[] args) throws IOException {
            //1.创建服务
            ServerSocket serverSocket = new ServerSocket(9000);
            //2.监听客户端的链接
            Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端连接
            //3.获取输入流
            InputStream is = socket.getInputStream();
            //4.文件输出
            FileOutputStream fos = new FileOutputStream(new File("receive.png"));
            byte[] buffer = new byte[1024];
            int count = 0;
            while ((count = is.read(buffer)) != -1) {
                fos.write(buffer, 0, count);
            }
            //5.通知客户端已经接受完了
            OutputStream os = socket.getOutputStream();
            os.write("我接受完毕了,你可以断开了".getBytes());
            //6.关闭资源
            os.close();
            fos.close();
            is.close();
            socket.close();
            serverSocket.close();
        }
    }
    

Tomcat

本质上还是信息传递

服务端

  • 自定义 S
  • Tomcat服务器 S:Java后台开发

客户端

  • 自定义 C
  • 浏览器 B

UDP消息发送

发短信:不用连接,需要知道对方的地址!

发送端,即便没有正确接收也不会报错,是一种不可靠的协议

public class UdpClient {
    public static void main(String[] args) throws Exception {
        //1.建立一个Socket
        DatagramSocket socket = new DatagramSocket();
        //2.建个包
        String msg = "你好,对岸的人";
        InetAddress localhost = InetAddress.getByName("localhost");
        int port = 9090;
        //数据,数据长度,发给谁
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);

        //3.发送包
        socket.send(packet);

        //4.关闭流
        socket.close();
    }
}

接收端

public class UdpServer {
    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().getHostAddress());
        System.out.println(new String(packet.getData(), 0, packet.getLength()));

        //关闭连接
        socket.close();
    }
}

Upd聊天实现

发送方

public class UdpUser1 {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8888);

        //准备数据:控制台System.in
        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();
    }
}

接收方

public class UdpUser2 {
    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);//阻塞式接收包裹
            //断开连接 bye
            byte[] data = packet.getData();
            String receiveData = new String(data, 0, packet.getLength());
            //这里写data.length是不对的,因为它来自container
            // 同时packet.getData().length也不对:
            //这个方法返回的是 DatagramPacket 内部使用的字节数组(也就是你在创建 DatagramPacket 时传入的 container 数组)。
            //这个数组的长度是固定的,是你初始化时指定的(在你的代码中是 1024)

            System.out.println(receiveData);

            if (receiveData.equals("bye")) {
                break;
            }
        }
        socket.close();
    }
}

UDP多线程在线咨询

  1. 发送线程

    public class TalkSend implements Runnable{
        DatagramSocket socket = null;
        BufferedReader reader = null;
    
        private  int fromPort;
        private String toIp;
        private int toProt;
    
        public TalkSend(int fromPort, String toIp, int toProt) {
            this.fromPort = fromPort;
            this.toIp = toIp;
            this.toProt = toProt;
    
            try {
                socket = new DatagramSocket(fromPort);
                //准备数据:控制台System.in
                reader = new BufferedReader(new InputStreamReader(System.in));
            } catch (SocketException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public void run() {
            try {
                while (true) {
                    String data = reader.readLine();
                    byte[] datas = data.getBytes();
                    DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toIp, this.toProt));
    
                    socket.send(packet);
                    if (data.equals("bye")) {
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            socket.close();
        }
    }
    
  2. 接收线程

    public class TalkReceive implements Runnable{
        DatagramSocket socket = null;
        private int formPort;
        private String msgFrom;
    
        public TalkReceive(int formPort, String msgFrom) {
            this.formPort = formPort;
            this.msgFrom = msgFrom;
            try {
                socket = new DatagramSocket(formPort);
            } catch (SocketException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public void run() {
            try {
                while (true) {
                    //准备接收包裹
                    byte[] container = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(container, 0, container.length);
                    socket.receive(packet);//阻塞式接收包裹
                    //断开连接 bye
                    byte[] data = packet.getData();
                    String receiveData = new String(data, 0, packet.getLength());
                    System.out.println(msgFrom + ":" + receiveData);
    
                    if (receiveData.equals("bye")) {
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            socket.close();
        }
    }
    
  3. 对象类1

    public class TalkStudent {
        public static void main(String[] args) {
            //开启两个线程
            new Thread(new TalkSend(5555, "localhost", 7777)).start();
            new Thread(new TalkReceive(6666, "老师")).start();//相当于备注了
        }
    }
    
  4. 对象类2

    public class TalkTeacher {
        public static void main(String[] args) {
            //开启两个线程
            new Thread(new TalkSend(8888, "localhost", 6666)).start();
            new Thread(new TalkReceive(7777, "学生")).start();//相当于备注了
        }
    }
    

URL

https://www.baidu.com/
统一资源定位符:定位资源的,定位互联网上的某一个资源

DNS 域名解析 www.baidu.com xxx.x..x..x

协议://ip地址:端口/项目名/资源

常用方法

public class URLMothed {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=ario&password=123");
        System.out.println(url.getProtocol());//协议
        System.out.println(url.getHost());//主机ip
        System.out.println(url.getPort());//端口
        System.out.println(url.getPath());//文件
        System.out.println(url.getFile());//全路径
        System.out.println(url.getQuery());//参数
    }
}

从网上下载资源

public class UrlDown {
    public static void main(String[] args) throws Exception {
        //下载地址
        URL url = new URL("https://ws6.stream.qqmusic.qq.com/C400002PmWEJ4VJHtR.m4a?guid=2492379522&vkey=CC4138C4021DDEDE5D73D32A5C5821F1FA28CBFEEFAFCC7D29C9EB21B5E8665905D63F55E64210BEEA59E18BCDC1511C0F1EA476254B84AF__v21ea059de&uin=1152921505246736145&fromtag=120032&src=C4000042W3aI296cbd.m4a");
        //连接这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream inputStream = urlConnection.getInputStream();

        FileOutputStream fos = new FileOutputStream("music.m4a");
        byte[] buffer = new byte[1024];
        int count = 0;
        while ((count = inputStream.read(buffer)) != -1) {
            fos.write(buffer, 0, count);//写出这个数据
        }
        fos.close();
        inputStream.close();
        urlConnection.disconnect();
    }
}
posted @ 2025-01-24 23:10  韩熙隐ario  阅读(14)  评论(0)    收藏  举报