• Java网络编程


    1.基本的通信架构

    通信架构分为两种:CS架构(客户端/服务器),BS架构(浏览器/服务器)
    cs架构

    • 客户端、服务端需要程序员开发
    • 需要用户安装客户端

    bs架构:

    • 不需要安装客户端,通过浏览器就能访问
    • 程序员只需开发服务端

    2.网络通信三要素

    1.ip,设备的唯一标识
    2.端口号,程序的id标识
    3.协议,连接和数据传输的规则

    2.1 IP地址对象–InetAddress

    在这里插入图片描述

    2.2 端口号

    端口分类
    在这里插入图片描述

    2.3 协议

    在这里插入图片描述
    UDP协议

    • 无连接,不可靠通信
    • 事先不建立连接,数据按照包发,一包数据包含:自己的IP,程序端口,目的地IP,程序端口和数据(限制在64KB内)等
    • 发送消息的时候不管对方是否在线,数据是否在中途丢失也不管,接收方接收到消息也不会返回确认,所以是不可靠的
    • 通信的效率较高,传输的速率高,丢了极个别的包影响不大

    TCP协议

    • 面向连接,可靠通信
    • TCP的最终目的:要保证在不可靠的信道上实现可靠传输
    • TCP主要有三个步骤实现可靠传输:三次握手连接,传输数据进行确认,四次挥手断开连接

    可靠连接:确定通信双方,收发消息都是正常无问题的(全双工通信)

    三次握手
    在这里插入图片描述

    四次挥手断开连接
    在这里插入图片描述

    3.UDP通信

    在这里插入图片描述

    //
    1.将传输的字符放入字节数组(getbytes方法,将字符串转为字节)
    2.传入的字节长度
    3.接收端的ip地址
    4.接收端的端口号
    public DatagramPacket(byte[] buf,int length,InetAddress address, int port)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    消息通信,一发一收实现步骤
    客户端

    • 1.创建客户端对象DatagramSocket对象
    • 2.创建DatagramPacket对象封装需要发送的数据(数据包对象)
    • 3.使用DatagramSocket对象的send方法,传入DatagramPacket对象
    • 4.关闭释放资源,close

    服务端

    • 1.创建DatagramSocket对象并指定端口(服务端对象)
    • 2.创建DatagramPacket对象接收数据(数据包对象)
    • 3.使用DatagramSocket对象的receive方法,传入DatagramPacket对象
    • 4.关闭,释放资源。close()

    消息通信,多发多收实现步骤

    //服务端
    public class UdpSocketServer {
        public static void main(String[] args) throws IOException {
    
            /**
             * UDP不可靠通信,服务器
             */
            DatagramSocket datagramSocket = new DatagramSocket(9000);//申明一个服务器对象
            byte[]bytes=new byte[1024*64];
            DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length);//申明一个容器用于接收传输过来的数据
            while(true)
            {
                datagramSocket.receive(datagramPacket);//服务器对象接收容器的类容
                String str=new String(bytes,0,datagramPacket.getLength());//将字节数组转换成字符串
                System.out.println(str);
            }
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    //客户端
    public class UdpSocketConsumer {
        public static void main(String[] args) throws Exception {
            Scanner scanner=new Scanner(System.in);
            while (true)
            {
                System.out.println("开始输入吧!");
                String str = scanner.nextLine();//将传输的数据转换成字节数组
                if (str.equals("exit"))
                {
                    break;
                }
                byte[] bytes = str.getBytes();
                DatagramSocket datagramSocket=new DatagramSocket();//申明一个客户端对象
                DatagramPacket datagramPacket=new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),9000);//用于存储传输数据,长度,ip,端口
                datagramSocket.send(datagramPacket);//发送消息
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.TCP通信

    特点:面向连接,可靠通信

    TCP通信的步骤
    服务端

    • 创建ServerSocket对象,并填写服务端端口
    • 调用ServerSocket对象的accept方法,等待客户端的连接,连接上后,返回一个Socket管道对象
    • 通过得到的Socket对象调用getInputStream方法得到字节输入流,完成数据的接收
    • 关闭释放资源,关闭socket连接
      在这里插入图片描述
      在这里插入图片描述

    客户端

    • 创建客户端对象
    • 通过客户端对象调用字节输出流
    • 把低级的字节输出流包装成数据输出流
    • 用高级输出流对象,调用writeUTF()进行输出
    • 关闭流,关闭客户端通信
      在这里插入图片描述
      当客户端建立连接后,后续又关闭连接,需要对服务端进行异常处理,否则服务端一直监听离线的客户端,会报错
      在这里插入图片描述

    4.1 TCP实现多发多收

    必须将接收到的socket对象交给多个线程管理

    聊天室多人通信—cs架构

    //客户端,负责向服务器发送消息,服务器转发给其他线程
    public class TCPSocketConsumer {
        public static void main(String[] args) throws IOException {
            Socket socket = new Socket("127.0.0.1", 8999);
            new TCPSocketConsumerThead(socket).start();
            OutputStream outputStream = socket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(outputStream);
            Scanner sc=new Scanner(System.in);
            System.out.println("服务已经启动,开始聊天");
            while (true)
            {
                String line = sc.nextLine();
                if (line.equals("exit"))
                {
                    socket.close();
                    outputStream.close();
                    break;
                }
                dos.writeUTF(line);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    //客户端线程,负责接收服务端的消息,看到关于自己的线程信息
    public class TCPSocketConsumerThead extends Thread{
      private Socket socket;
       public TCPSocketConsumerThead(Socket socket)
       {
           this.socket=socket;
       }
        @Override
        public void run() {
            try {
                InputStream inputStream = socket.getInputStream();
                DataInputStream dataInputStream = new DataInputStream(inputStream);
                while(true)
                {
                    try {
    
                        String s = dataInputStream.readUTF();
                        System.out.println(s);
                    } catch (Exception e) {
    
                    }
    
                }
            } catch (IOException e) {
                System.out.println("自己下线了");
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    //服务端,负责接收客户端的消息
    public class TCPSocketServer {
        public static List<Socket> sockets=new ArrayList<>();
        public static void main(String[] args) throws Exception {
    
            System.out.println("------服务端启动-----");
            ServerSocket serverSocket = new ServerSocket(8999);
            while (true)
            {
                Socket accept = serverSocket.accept();
                sockets.add(accept);
                System.out.println(accept.getInetAddress()+"已经上线");
                TcpSocketServerThead thead=new TcpSocketServerThead(accept);
                thead.start();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    //服务端线程,负责将服务端接收到的信息传递给其他客户端线程
    public class TcpSocketServerThead extends Thread{
        private Socket socket;
    
        private DataInputStream dataInputStream;
        public TcpSocketServerThead(Socket socket) {
            this.socket=socket;
        }
    
        @Override
        public void run()
        {
          while(true){  try
            {
                InputStream inputStream = socket.getInputStream();
                dataInputStream = new DataInputStream(inputStream);
                String s = dataInputStream.readUTF(dataInputStream);
                transAll(s);
                System.out.println(s);
    
            } catch (Exception e) {
                System.out.println(socket.getInetAddress()+"已经下线");
                TCPSocketServer.sockets.remove(socket);
                try {
                    socket.close();
                    dataInputStream.close();
                    break;
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }}
    
        public void transAll(String msg) throws IOException
        {
            for(Socket s:TCPSocketServer.sockets)
            {
                OutputStream outputStream = s.getOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                dataOutputStream.writeUTF(msg);
                dataOutputStream.flush();
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    BS架构

    //之开发服务端,通过网页通信
    public class BSSocket {
        public static void main(String[] args) throws IOException {
            System.out.println("------服务端启动-----");
            ServerSocket serverSocket = new ServerSocket(8999);
            while (true)
            {
                Socket accept = serverSocket.accept();
                System.out.println(accept.getInetAddress()+"已经上线");
                BSSocketThread bsSocketThread=new BSSocketThread(accept);
                bsSocketThread.start();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    //线程
    public class BSSocketThread extends Thread{
        private Socket socket;
        public BSSocketThread(Socket socket)
        {
            this.socket=socket;
        }
    
        @Override
        public void run() {
            try {
                OutputStream outputStream = socket.getOutputStream();
                PrintStream printStream=new PrintStream(outputStream);
                printStream.println("HTTP/1.1 200 OK");
                printStream.println("Content-Type:text/html;charset=UTF-8");
                printStream.println();
                printStream.println("
    程序员666
    "
    ); printStream.close(); socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    使用BS架构实现通信的话,必须遵守HTTP协议
    在这里插入图片描述
    如果每次访问都创建一个线程,如果并发很高的话,就可能实现宕机。需要使用线程池

  • 相关阅读:
    如何使用virtualenv的虚拟环境
    AI伦理:科技发展中的人性之声
    MySQL主从复制与读写分离
    Docker创建mysql容器
    含文档+PPT+源码等]精品基于Java的社区团购系统SSM[包运行成功]计算机毕业设计Java毕设
    Jackson 化学发光免疫印迹解决方案
    MySQL 及 jdbc 问题汇总
    MyBatis:3_增删查改
    Java中的lambda表达式如何理解——精简
    Shopify主题二次开发必备技能:全面指南和最佳实践
  • 原文地址:https://blog.csdn.net/Hey_Join/article/details/132583555