chengyuyu

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

【笔记】Java网络编程

网络编程

1.1 概述

网络编程不是JavaWeb开发

协议:

  • TCP
  • UDP

1.2 网络通信的要素

小结

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

1.3 IP

IP地址:InetAddress

  • 唯一定位一台网络计算机
  • 127.0.0.1:本机localhost
  • ip地址的分类
    • IP地址分类:ipv4 / ipv6
      • ipv4 127.0.0.1,4个字节组成
      • ipv6 fe80::ccfd:506a:f5c4:6c31%17,128位。8个无符号整数
    • 公网(互联网) / 私网(局域网)
      • ABCD类地址
      • 192.168.1.10 局域网,一般给组织内部使用
  • 域名:记忆IP问题
public static void main(String[] args) throws UnknownHostException {
    // 获取本机地址
    InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
    System.out.println(inetAddress1);
    InetAddress inetAddress3 = InetAddress.getByName("localhost");
    System.out.println(inetAddress3);
    InetAddress inetAddress4 = InetAddress.getLocalHost();
    System.out.println(inetAddress4);

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


    System.out.println("===================================================");
    // 常用方法
    System.out.println(inetAddress2.getAddress()); // [B@1b6d3586
    System.out.println(inetAddress2.getCanonicalHostName()); // 规范的名字
    System.out.println(inetAddress2.getHostAddress());  // ip
    System.out.println(inetAddress2.getHostName()); // 域名,或者本机名
}

1.4 端口port

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

  • 不同的进程有不同的端口号,用来区分软件。
  • 被规定0~65535.
  • 有TCP/UDP协议,单个协议下,端口号不能重复。
  • 端口分类:
    • 公有端口1-1023
      • HTTP:80
      • HTTPS:443
      • FTP:21
      • Telent:23
    • 程序注册端口:1024-49151,分配用户或程序
      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    • 动态、私有:49152-65535

1.5 通信协议

网络通信协议:速率、传输码率、代码结构、传输控制……

分层:传输层

TCP/IP协议簇

重要:

  • TCP:用户传输协议
  • UDP:用户数据报协议

出名的协议:

  • TCP:
  • IP:网络互连协议

TCP/UDP对比

TCP:相当于打电话

  • 连接,稳定
  • “三次握手” “四次挥手”
  • 客户端、服务端
  • 传输完成、释放连接、效率低

UDP:相当于发短信

  • 不连接,不稳定
  • 客户端、服务端没有明确的界限
  • 不管有没有准备好,都可以发送

1.6 TCP

客户端client

  1. 连接服务器Socked
  2. 发送消息
// 客户端
public class TCPClientDemo1 {
    public static void main(String[] args) throws IOException {
        Socket socket = null;
        OutputStream os = null;
        try {
            // 1.要知道服务器的地址和端口号
            InetAddress serverIP = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            // 2.创建一个socked连接
            socket = new Socket(serverIP,port);
            // 3.发送消息 IO流
            os = socket.getOutputStream();
            os.write("千山鸟飞绝!".getBytes());
        } catch (IOException 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. 建立服务的端口 ServerSocked
  2. 等待用户的连接 accept
  3. 接收用的消息
// 服务端
public class TCPServerDemo1 {
    public static void main(String[] args) throws IOException {
        // 提升作用域,使得关闭能在finally里,符合规范
        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[1023];
                int len;
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);   // 从buffer写到baos,从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();
                }
            }
        }
    }
}

TCP传文件

服务端

// 服务端
public class TCPServerDemo2 {
    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("receive.jpg");
        byte[] buffer = new byte[1024];
        int len;
        while ((len=is.read(buffer))!=-1) {
            fos.write(buffer);
        }

        // 通知客户端数据接收完毕
        OutputStream os = socket.getOutputStream();
        os.write("服务器已经接收完毕,可以断开。".getBytes());

        // 关闭通道
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

// 客户端
public class TCPClientDemo2 {
    public static void main(String[] args) throws IOException {
        // 1.创建一个Socked连接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9000);
        // 2.创建一个输出流
        OutputStream os = socket.getOutputStream();

        // 3.读取文件
        FileInputStream fi = new FileInputStream(new File("C:\\Users\\yuzheyuan\\Desktop\\111.jpg"));

        // 4.写出文件
        byte[] buffer = new byte[1024];
        int len;
        while ((len=fi.read(buffer))!=-1) {
            os.write(buffer,0,len);
        }
        // 通知服务器,我已经结束
        socket.shutdownOutput();  // 我已经传输完了

        // 确定服务器接收完毕,才能断开连接
        InputStream is = socket.getInputStream();
        // String byte[]
        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());

        // 5.关闭资源
        baos.close();
        is.close();
        fi.close();
        os.close();
        socket.close();
    }
}

1.7 UDP

不用连接,但是需要对方的地址

两个重要的类:

  • Class DatagramPacket
  • Class DatagramSocket

UDP实现发送消息

UDP没有服务端的概念(不需要服务器),接收端只是用于接收消息

客户端

public class UDPClientDemo1 {
    public static void main(String[] args) throws IOException {
        // 1.建立一个Socked
        DatagramSocket socked = new DatagramSocket();
        // 2.建个包
        String msg = "建个包。。。";
        // 发送给谁
        InetAddress localhost = InetAddress.getByName("localhost");
        int port = 9000;
        // 数据【msg.getBytes()】, 数据的长度【0,msg.getBytes().length】, 发送对象【localhost,port】
        DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);

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

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

接收端

// 还是需要等待客户端的连接
public class UDPServerDemo1 {
    public static void main(String[] args) throws IOException {
        // 开放端口
        DatagramSocket socket = new DatagramSocket(9000);

        // 接收数据包
        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.getData().length));

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

    }
}

UDP实现聊天

循环发送消息

public class UDPSenderDemo01 {
    public static void main(String[] args) throws IOException {
        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 (datas.equals("bb")) {
                break;
            }
        }
        socket.close();
    }
}

循环接收消息

public class UDPReceiveDemo01 {
    public static void main(String[] args) throws IOException {
        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("bb")) {
                break;
            }
        }
        socket.close();
    }
}

多线程聊天

发送接口 TalkSend

public class TalkSend implements Runnable {
    DatagramSocket socket = null;
    BufferedReader reader = null;

    private int fromPort;
    private String toIP;
    private int toPort;

    public TalkSend(int fromPort, String toIP, int toPort) {
        this.fromPort = fromPort;
        this.toIP = toIP;
        this.toPort = toPort;

        try {
            socket = new DatagramSocket(fromPort);
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        // 准备数据,控制台读数据
        while (true) {
            try {
                String data = reader.readLine();
                byte[] datas = data.getBytes();
                DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toIP, this.toPort));

                socket.send(packet);
                if (data.trim().equals("bb")) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("结束, 释放资源");
        socket.close();

    }
}

接收接口 TalkReceive

public class TalkReceive implements Runnable {
    DatagramSocket socket = null;
    private int receivePort;
    private String msgFrom;


    public TalkReceive(int receivePort, String msgFrom) throws SocketException {
        this.receivePort = receivePort;
        this.msgFrom = msgFrom;
        try {
            socket = new DatagramSocket(receivePort);
        } catch (SocketException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        while (true) {
            // 准备接受包裹
            try {
                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(msgFrom+": "+receivedata);
                if (receivedata.trim().equals("bb")) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

聊天者1(老师)

public class TalkTeacher {
    public static void main(String[] args) throws SocketException {
        new Thread(new TalkSend(5555,"localhost",8888)).start();
        new Thread(new TalkReceive(9999,"学生")).start();
    }
}

聊天者2(学生)

public class TalkStudent {
    public static void main(String[] args) throws SocketException {
        // 开启两个线程
        new Thread(new TalkSend(7777,"localhost",9999)).start();
        new Thread(new TalkReceive(8888,"老师")).start();
    }
}

1.8 URL

统一资源定位符

例子(待补充)

posted on 2021-11-30 15:37  chengyuyu  阅读(42)  评论(0)    收藏  举报