首页 > 编程语言 >Java 实训第17天 Java网络编程

Java 实训第17天 Java网络编程

时间:2024-11-14 10:49:49浏览次数:3  
标签:Java socket 17 int void System 实训 println new

Java网络编程

一、网络分层
1、OSI七层
    应用层: HTTP FTP POP3 SMTP TELNET ...  
    表示层:  
    会话层:   
    传输层: TCP UDP  
    网络层: IP  
    数据链路层
    物理层 
    
2、TCP/IP协议
    应用层 ---  应用层,表示层,会话层  
    传输层 --- 传输层   
    网际层 --- 网络层  
    网络层 --- 数据链路层,物理层    
    

二、计算机网络的基本要素

1、IP地址(门牌号)
    计算在网络中的唯一标识  
    ipv4 - 32位  
    127.0.0.1 -- 指向当前机器  
    255.255.255.255 -- 广播地址  
    ipv6 - 128位
    
    
2、主机名
    因为ip地址难于记忆,可以为不同的主机起不同的名字 来唯一标识 这个唯一标识主机的名字 称为主机名 和 ip地址具有映射关系  
  
  127.0.0.1  localhost 代表本机

3、域名
    全网认可的主机名 域名不能随意用 需要注册 先到先得 收取一定费用


4、域名解析
    DNS服务器:域名解析服务器 接受域名 解析为 ip 返回 
    
5、Hosts文件:windows自带的机制 可以在本地做主机名 和ip 的映射

    在windows中使用主机名时 会先查找hosts文件 得到主机名和ip的映射 得到就用 得不到再求访问公网上的dns服务器翻译  
    C:\Windows\System32\drivers\etc\hosts

6、端口
    每个计算机 都有 若干个 可以供外界连接的窗口 每个窗口都有独一无二的编号 程序可以监听指定的端口号 
    外界通过ip连接到当前机器后 将数据发送 给指定端口号 从而 让正在监听该端口的程序收到数据。
    范围:0~65535  其中0~1024是被系统占用了的,我们不能使用。


7、协议:网络中主机之间通信的规范
    HTTP 80
    HTTPS 443
    SMTP 25
    SSH  22

三、InetAddress
    java.net.InetAddress - 此类表示互联网协议 (IP) 地址

主要方法:
    static InetAddress getLocalHost() //获取本机ip地址对象
    static InetAddress getByName(String host) //根据给定ip或主机名 获取ip地址对象
    String getHostName() //获取当前对象代表的主机的主机名
    String getHostAddress() //获取当前对象代表的主机的ip地址
    

四、传输协议
1、UDP
    不需要建立连接  
    将数据及源和目的地封装为数据包  
    每个数据报的大小限制在64k内  
    因为无连接,是不可靠协议  

    优点:快  
    缺点:会丢数据
    
    应用场景:数据及时传输要求高,但是数据稳定性不需保证的场景(例如:QQ,微信聊天)
    
2、TCP
    建立连接,形成传输数据的通道  
    在连接中进行大数据量传输,靠流来进行操作  
    三次握手,是可靠协议  
    必须先建立连接,效率会稍低  

    优点:不丢数据  
    缺点:效率相对较低  

    应用场景: 要求可靠性比较高的场景(web服务)
    

五、java中的socket编程

1、利用socket实现UDP通信

    java.net.DatagramSocket - UDP协议的编程接口类,负责收发数据包
    
    构造方法:
        DatagramSocket()//通常用来发送
        DatagramSocket(int port)//通常用来接收

    相关方法:
        void send(DatagramPacket p) //发送数据包
        void receive(DatagramPacket p) //接收数据包
        void close() //关闭套接字
    
    
    数据包:
        java.net.DatagramPacket - UDP的数据包,内含 数据 数据来源 数据目的地

        构造:
            DatagramPacket(byte[] buf, int length)//一般用做接收
            DatagramPacket(byte[] buf, int length, InetAddress address, int port) //一般用作发送
            
        相关方法:
            InetAddress getAddress()  
            int getLength()  
            byte[] getData()
            int getPort()  
        
    
    案例代码:利用UDP实现客户端和服务器通信
    UDPServer:
    /**
     * java利用socket实现基于UDP协议的服务端
     */
    public class UDPServer {
        public static void main(String[] args) throws Exception {

            //构建UDP服务端并监听服务端口--8000
            DatagramSocket udpSocket = new DatagramSocket(8000);

            //构建接收数据包的对象
            byte[] bytes = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);

            //接收数据包
            System.err.println("数据等待中,请稍后...");
            udpSocket.receive(datagramPacket);

            //获取接收的数据
            byte[] reciveData = datagramPacket.getData();

            //打印获取的内容
            String result = new String(reciveData, 0, reciveData.length, "utf-8");

            System.out.println("客户端发送的信息:"+result);

            //关闭资源
            udpSocket.close();

        }
    }
    
    
    UDPClient:
    /**
     * java利用socket实现基于UDP协议的客户端
     */
    public class UDPClient {
        public static void main(String[] args) throws Exception {

            //构建UDP客户端
            DatagramSocket datagramSocket = new DatagramSocket();


            //扫描器接收用户输入
            Scanner scanner = new Scanner(System.in);
            System.out.println("客户端准备发送数据:");
            byte[] content = scanner.next().getBytes("utf-8");


            //构建服务器的地址对象
            InetAddress localhost = InetAddress.getByName("192.168.176.136");
            //封装数据包
            DatagramPacket datagramPacket = new DatagramPacket(content, content.length, localhost, 8000);

            //发送数据
            datagramSocket.send(datagramPacket);
            System.out.println("数据发送完成...");

            //关闭资源
            datagramSocket.close();

        }
    }
    
2、socket实现TCP
1)主要流程
    需要经历三次握手建立连接  
    用流来传输大量数据  
    有数据包重发机制 实现可靠的数据传输  
    可以双向传输数据  

    TCP基于连接工作 连接具有两端 称为服务器端 和 客户端  
    把主动发起请求的一端 称为客户端 被动等待请求 接收连接的一方称之为 服务器端 
    
2)java中的主要api
    --代表soket地址的类:  

    SocketAddress - InetSocketAddress
    构造方法:  
        InetSocketAddress(InetAddress addr, int port)
        InetSocketAddress(String hostname, int port)

    其他方法:
        InetAddress getAddress()  
        String getHostName()  
        int getPort()
        
    
    --表示TCP socket客户端的类:
        java.net.Socket
    
    构造方法:
        Socket()
        Socket(InetAddress address, int port)
        Socket(String host, int port)
        
    相关方法:
        void connect(SocketAddress endpoint) //开始连接服务器
        void connect(SocketAddress endpoint, int timeout) //开始连接服务器,额外指定超时时间
        InetAddress getInetAddress()  //获取连接的地址
        int getPort() //获取连接的端口
        InputStream getInputStream() //获取输入流  
        OutputStream getOutputStream() //获取输出流
        void shutdownInput() //结束对输入流的读取,不会关闭流,只是无法再从流中读取数据
        void shutdownOutput() //结束对输出流的输入,不会关闭流,只是无法再向流中写出数据
        boolean isInputShutdown()  //判断输入流是否已经被置于结束状态
        boolean isOutputShutdown()  //判断输出流是否已经被置于结束状态
        void close()  //关闭套接字 自动关闭底层输入输出流
        
    
    --表示TCP socket服务端的类:
        java.net.ServerSocket  
    
    构造方法:
        ServerSocket()
        ServerSocket(int port)
        
    相关方法:
        Socket accept()  //开始接受连接 一旦调用 就进入阻塞状态 直到有一个客户端连接过来 才会解除阻塞继续运行
        void close()  //关闭套接字 自动关闭底层输入输出流
        InetAddress getInetAddress()  //获取地址对象
        int getLocalPort()  //获取本地监听端口

java基于socket通信的TCP案例:
服务端:
    /**
     * Server socket Tcp
     */
    public class ServerSocketForTCP {
        public static void main(String[] args) throws Exception {

            //1、构建server socket对象(监听端口)
            ServerSocket serverSocket = new ServerSocket(9999);

            //2、等待客户端链接Socket(套接字)
            Socket accept = serverSocket.accept();

            //3、基于socket获取输入流接收客户端的数据
            InputStream inputStream = accept.getInputStream();

            //4、流处理
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);

            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String msg = bufferedReader.readLine();

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

            //5、关闭资源
            serverSocket.close();


        }
    }
    
客户端:
    /**
     * Client socket Tcp
     */
    public class ClientSocketForTCP {
        public static void main(String[] args) throws Exception {

            //1、构建客户端的socket
            Socket socket = new Socket();

            //2、连接到服务端
            //构建socker地址对象
            InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9999);
            socket.connect(socketAddress);

            //3、基于socker完成数据传递
            OutputStream outputStream = socket.getOutputStream();

            PrintStream printStream = new PrintStream(outputStream);

            printStream.print("你好,我是客户端信息");

            //4、关闭资源
            socket.close();


        }
    }
    
java8中的常用新特性
一、Lambda表达式
    lambda表达式就是匿名函数,匿名函数可以作为参数传递,表示数据。目的是让代码更加简洁,开发更高效!  
    (参数1,参数2...)->{函数体}  
    
    特点:
        * 参数的类型可以不写,lambda表达式可以根据上下文进行推断
        * 函数体如果只有一行代码,大括号可以不写。
        * 如果只有一行代码并且是作为返回值使用,则return也可以不写
        * lambda表达式与函数式接口绑定出现


    案例1:利用lambda表达式改写Thread线程对象构建
        //lambda表达式
        Thread thread = new Thread(() -> {
            System.out.println("倒数:3");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("倒数:2");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("倒数:1");
        });
        thread.start();

    案例2:参数根据上下文自动推算
        //参数x和y的类型进行了自动推算
        MyLambdaTest myLambdaTest = (x, y)->x+y;    //()->{return x+y;}

        interface MyLambdaTest{
            default void printName(){
                System.out.println(this.getClass().getName());
            }

            int sum(int a, int b);
        }

二、函数式接口
1、特点:
    只包含一个抽象方法的接口就是函数式接口。  
    如果需要将接口设置为函数式接口,可以在接口上添加注解:  
    @FunctionalInterface

2、函数式接口分类
    jdk内置的函数式接口:
        java.util.function:(Function、Consumer、Supplier、Predicate)  
                
    函数型接口:有输入参数,也有返回值。Function
    案例:
        Function<String, Integer> fumc = (x)->x.length();

        Integer nihao = fumc.apply("nihao");
        System.out.println(nihao);
    
    
    消费型接口:有参数,没有返回值。Consumer
    供给型接口:没有参数,有返回值。Supplier
    断言型接口:有输入参数,也有返回值,返回boolean类型。 Predicate
    
    
    补充案例:java支持不定长参数
        public static void nums(int ... n){
            //System.out.println(n instanceof int[]);
            int sum = 0;
            for (int num:n) {
                sum+=num;
            }
            System.out.println("所有数值的总和是:"+sum);
        }
        
三、方法引用和构造引用

1、方法引用
    当要传递给Lambda体的操作已经有实现方法,可以直接使用方法引用  
    写法:  
    对象/类::方法名   //仅仅是引用但不执行  
    
    案例:
        lambda:
        Consumer<String> consumer = (x)-> System.out.println(x);
        consumer.accept("hello world");

        lambda+函数引用:
        Consumer<String> consumer = System.out::println;    //此处只是引用out对象的println方法,而不是调用
        consumer.accept("hello world");
        

2、构造引用
    //普通构造引用
    
    Supplier<Students> students = Students::new;
    students.get().printClassInfo();
    
    class Students{
        public void printClassInfo(){
            System.out.println(this.getClass().getName());
        }
    }
    
    //数组构造引用
      //可以传递一个参数(表示数组长度),返回数组对象,通过相应类型的构造引用创建对象。
      Integer[] arr = new Integer[5];
      Function<Integer, Integer[]> integersFunc = (len)->new Integer[len];
      //Integer数组的构造引用
      Function<Integer, Integer[]> integersFunc1 = Integer[]::new;
      Integer[] apply = integersFunc1.apply(6);
      System.out.println(Arrays.toString(apply));

    
        
    
        


    
    

标签:Java,socket,17,int,void,System,实训,println,new
From: https://blog.csdn.net/binishuaio/article/details/143761835

相关文章