Java学习的第二十七天(JavaSE最终篇_线程常用方法_网络编程之UDP与TCP)

一、线程一些常用方法的讲解

1.setDaemon()---设置某个线程为守护线程

package com.bianyiit.cast;

public class XianChenTuoZhanDemo1 {
    public static void main(String[] args) {
        ShouHu sh = new ShouHu();
        sh.setName("守护线程");
        //将sh设置成守护线程
        sh.setDaemon(true);
        //还是交叉执行
        sh.start();
        //守护线程
        for (int i = 1; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+i);
            if(i>500){
                break;
                //随着被守护的线程结束,守护线程而跟着结束掉
            }
        }
        //两个线程交叉执行
    }
}
class ShouHu extends Thread{
    @Override
    public void run() {
        int i=1;
        while (true) {
            //继承了Thread,可以直接用getName()
            System.out.println(getName()+"守护线程启动了"+i);
            i++;
            if(i==1000){
                break;
            }
        }
    }
}

总结:随着被守护的线程结束,守护线程而跟着结束掉

2.join()---让当前线程一直处于运行状态(一直获取cpu的执行时间)

package com.bianyiit.cast;

public class JoinDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Join join = new Join();
        join.setName("join");
        join.start();
        //把线程设置为join线程,优先获取CPU的执行权
        join.join();
        //主线程
        for (int i = 0; i < 500 ; i++) {
            System.out.println(Thread.currentThread().getName()+"主线程"+i);
        }
    }
}
class Join extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println(getName()+"线程"+i);
        }
    }
}

注意:join线程全部执行完之后才执行主线程

3.setPriority(int newPriority)---设置线程的优先级

package com.bianyiit.cast;

public class PriorityDemo3 {
    public static void main(String[] args) {
        Priority p1 = new Priority();

        Thread t1=new Thread(p1);
        t1.setName("线程1");
        t1.setPriority(Thread.MAX_PRIORITY);  //最大优先级
        Thread t2=new Thread(p1);
        t2.setName("线程2");
        t2.setPriority(Thread.MIN_PRIORITY);  //最小优先级
        Thread t3=new Thread(p1);
        t3.setName("线程3");
        t3.setPriority(Thread.NORM_PRIORITY); //默认优先级
        t1.start();
        t2.start();
        t3.start();
        //优先级高的线程获取CPU执行权的概率要比优先级低的线程大的多
        //setPriority---设置线程的优先级
        /*Thread.MAX_PRIORITY; //最大优先级10
        Thread.MIN_PRIORITY;   //最小优先级1
        Thread.NORM_PRIORITY;  //默认优先级5*/

    }
}
class Priority implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

注意:优先级高的线程获取CPU执行权的概率要比优先级低的线程大的多

4.在开发时,可以使用匿名内部类来完成线程的创建和启动

package com.bianyiit.cast;

public class NiMingNeiBuNeiDemo4 {
    public static void main(String[] args) {
    //三种使用匿名内部类启动线程的方式
        /*new Thread(){
            @Override
            public void run() {
                for (int i = 0; i <1000 ; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }.start();*/
        /*new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <1000 ; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }).start();*/
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <1000 ; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        });
        t.start();
    }
}

5.Timer的对象.schedule()---定期重复执行某一个线程/步骤

package com.bianyiit.cast;

import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo5 {
    public static void main(String[] args) throws InterruptedException {
        //工具,定期重复执行某一个线程/步骤----相当于就是一个定时器
        //创建定时器对象
        Timer t=new Timer();
      /*  //创建一个date对象--从1900年开始计算,月份要减一
        Date date=new Date(119,10,28,10,17,40);
        //定时某个任务执行的时间
        t.schedule(new RenWu(),date,5000);
        //TimerTask是一个抽象类,不能直接创建对象*/
        for (int i = 5; i >0 ; i--) {
            System.out.print(i+" ");
            Thread.sleep(1000);
        }
        t.schedule(new RenWu(),0);
    }
}
//创建一个任务类
class RenWu extends TimerTask {
    //重写父类的抽象方法
    @Override
    public void run() {
        System.out.println("Suprise MZ fuck!!");
    }
}

注意:上述代码相当于一个定时器,定时时间到,启动线程,执行run()里面的代码

二、网络编程概述

1.什么是网络编程?就是通过网络进行数据的传输(设备与设备之间进行数据的传输)
2.##设备与设备(不一定是电脑)##如何进行数据的传输??遵循TCP和UDP协议
3.浏览器和服务器之间如何进行数据数据的传输??遵循http和https协议

1.OSI标准模型

OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI标准模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模型。ISO为了更好的使网络应用更为普及,推出了OSI参考模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,就能互联了。


2.TCP/IP参考模型

在TCP/IP参考模型中,去掉了OSI参考模型中的会话层和表示层(这两层的功能被合并到应用层实现)。同时将OSI参考模型中的数据链路层和物理层合并为主机到数据链路层层

TCP/IP四层概念模型
3.网络通信三要素:协议、IP地址和端口号

3.1 什么是协议:规定我们的具体操作(定义了规则/传输数据的一些方式)
	  具体的协议:http和https是浏览器与服务器之间的协议,而今天学的网络编程的协议是TCP和UDP是设备与设备之间的协议

3.2 IP地址:www.bianyiit.com(域名/IP地址)--127.0.0.1(点分十进制法)---代表的是电脑的地址

3.3 端口号:代表的是具体的应用程序的地址---默认是80,
	  IP地址是唯一的,端口号是可以重复的

3.4 计算机都有自己唯一的IP地址,计算机中每一个正在运行的程序都有一个端口号
	IP地址分为两种:IPV4(四个字节/32位)和IPV6,都是0-255之间
		IPV4最多能设置2的32次方个IP(40多亿个)
		IPV6---2的128次方个

注意1:端口号取值范围0--65535 但是0-1023这些端口号已经被一些知名的应用程序占用了,所以建议大家使用1024之后的端口号
注意2:每个电脑都可以用127.0.0.1访问自己电脑,这个叫做本地回环地址

三、那么该如何进行数据的传输??

1.学习一个类InetAddress,它提供了一系列与IP地址相关的方法
2.InetAddress的常用方法

2.1 static InetAddress getByName(String host)---在给定主机名的情况下确定主机的 IP 地址
2.2 static InetAddress getLocalHost()---返回本地主机
2.3 String getHostName()---获取此 IP 地址的主机名
2.4 String getHostAddress()---返回 IP 地址字符串(以文本表现形式)

3.代码演示

package com.bianyiit.internet;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressDemo3 {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress address1 =InetAddress.getLocalHost();
        //返回IP地址的对象---主机名/IP地址
        System.out.println(address1);
        //返回IP地址的对象---主机名/IP地址
        InetAddress byName = InetAddress.getByName("电脑的主机名");
        System.out.println(byName);
        //通过IP地址对象调用getHostName(),以字符串的方式返回的是主机名
        String hostName = address1.getHostName();
        System.out.println(hostName);
        //通过IP地址对象调用getHostAddress(),以字符串的方式返回的是IP地址
        String hostAddress = address1.getHostAddress();
        System.out.println(hostAddress);
    }
}

四、UDP协议

1.UDP协议解释

1.1 不安全协议(只管传输数据,不管数据是否真正的传了过去也不管对方是否完全接收了数据)
1.2 效率高(如果传输数据对数据的安全性不做要求,或者丢失数据不会产生太大的影响)选择使用UDP协议,否则就选择TCP协议

2.JDK中提供了一个DatagramSocket类,此类表示用来发送和接收数据报包的套接字。

//DatagramSocket用于发送的构造方法
2.1--DatagramSocket()---构造数据报套接字并将其绑定到本地主机上任何可用的端口。

//DatagramSocket用于发送的常用方法
2.2--void send(DatagramPacket p)----从此套接字发送数据报包。 

//DatagramSocket用于接收的构造方法
2.3--DatagramSocket(int port)---创建数据报套接字并将其绑定到本地主机上的指定端口。

//DatagramSocket用于接收的常用方法
2.4--void receive(DatagramPacket p)---从此套接字接收数据报包。 

3.JDK中提供了一个DatagramPacket类,用于封装UDP通信中发送或者接收的数据

//DatagramPacket用于发送的构造方法
3.1--DatagramPacket(byte[] buf, int length, InetAddress address, int port) ---构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

//DatagramPacket用于接收的构造方法
3.2--DatagramPacket(byte[] buf, int length)---构造 DatagramPacket,用来接收长度为 length 的数据包。

//DatagramPacket用于接收的常用方法
3.3--byte[] getData()---返回数据缓冲区。 
3.4--int getLength()---返回将要发送或接收到的数据的长度。 
3.5--int getPort()---返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。 
3.6--InetAddress getAddress()---返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。 

//将接收到的字节数组转换成字符串的方法
3.7--String(byte[] bytes)---通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
3.8--String(byte[] bytes, int offset, int length)---通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。

4.UDP通信Java代码

package com.bianyiit.internet;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*UDP协议:发送端*/
public class SendDataSocketDemo5 {
    public static void main(String[] args) throws IOException {
        //发送和接收端都需要用到的一个套接字---DatagramSocket(类)
        //第一步:创建发送端的连接对象
        DatagramSocket ds = new DatagramSocket();  //不需要指定发送端的端口号,默认生成一个端口号
        String s="hello world";
        //需要把数据进行打包操作,首先要有一个数据包
        DatagramPacket dp = new DatagramPacket(s.getBytes(),s.getBytes().length,InetAddress.getByName("127.0.0.1"),8888);
        //发送数据
        ds.send(dp);
        //释放资源
        ds.close();
    }
}
package com.bianyiit.internet;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*UDP协议:接收端*/
public class ReceiveDataSocketDemo6 {
    public static void main(String[] args) throws IOException {
        //发送和接收端的一个套接字DatagramSocket(类)
        //第一步:创建接收端的连接对象
        DatagramSocket ds = new DatagramSocket(8888);//接收端要指定端口号
        //定义一个字节数组
        byte[] bytes=new byte[20];
        //创建一个空的集装箱对象(数据包对象)----用来接收数据
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        ds.receive(dp); //这时会处于一种阻塞状态---等待发送端把数据发送过来
        //发送过来的具体数据
        byte[] data = dp.getData();
        System.out.println(data);
        //将字节数组转换成字符串
        System.out.println(new String(data));
        //发送过来的数据的具体长度
        int length = dp.getLength();
        System.out.println(length);
        //返回发送端的端口号
        int port = dp.getPort();
        System.out.println(port);
        /*String s = new String(data, 0, data.length);
        System.out.println(s);*/
        InetAddress address = dp.getAddress();
        System.out.println(address);
    }
}

5.使用UDP构建一个基本的网络聊天室

package com.bianyiit.udpchat;
//发送端1----接收端2
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        while (true) {
            Scanner sc=new Scanner(System.in);
            //创建发送端的对象
            DatagramSocket ds = new DatagramSocket();
            System.out.print("发送端送:");
            String s = sc.next();
            //数据的打包
            DatagramPacket dp = new DatagramPacket(s.getBytes(), s.getBytes().length, InetAddress.getByName("127.0.0.1"), 9999);
            ds.send(dp);
            ds.close();

            //创建接收端链接对象
            DatagramSocket ds1 = new DatagramSocket(8888);
            //创建数据包接收数据
            byte[] arr=new byte[50];
            DatagramPacket dp1=new DatagramPacket(arr,arr.length);
            //接收数据包
            ds1.receive(dp1);
            //将数据包拆开
            byte[] data = dp1.getData();
            String s1=new String(data);
            System.out.println(s1);
            ds1.close();
        }
    }
}
package com.bianyiit.udpchat;
//接收端1----发送端2
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        while (true) {
            DatagramSocket ds = new DatagramSocket(9999);
            byte[] arr=new byte[50];
            //创建数据包对象
            DatagramPacket dp = new DatagramPacket(arr,arr.length);
            //接收数据包
            ds.receive(dp);
            //将数据包拆开
            byte[] data=dp.getData();
            String s=new String(data);
            System.out.println(s);
            ds.close();

            Scanner sc=new Scanner(System.in);
            //创建发送端对象
            DatagramSocket ds1 = new DatagramSocket();
            System.out.println("服务器说:");
            String s1 = sc.next();
            //创建数据包对象
            DatagramPacket dp1 = new DatagramPacket(s1.getBytes(),s1.getBytes().length, InetAddress.getLocalHost(),8888);
            ds1.send(dp1);
            ds1.close();
        }
    }
}

注意:UDP协议:发送端和接收端,同时UDP是通过数据包的方式发送数据

五、TCP协议

1.TCP协议解释

1.1 什么是TCP协议??---重点掌握
	  安全协议(要经过三次握手,确定对方完全接收数据)
      效率要低点
1.2 简单解释什么是三次握手
      A问B,在吗??  B回答我在,反过来问A你在吗?? A回答我在,这时可以进行数据的交互*/
1.3 UDP称为发送端和接收端,TCP和Http统称为客户端和服务端
1.4 TCP通过流的方式发送数据,通过Socket套接字建立客户端与服务器端的连接
1.5 通过ServerSocket建立服务器端与客户端之间的连接

2.JDK提供了一个Socket类,用于实现TCP客户端程序。

//Socket类的构造方法
2.1--Socket(InetAddress address, int port)---创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

//Socket类的常用方法
2.2--OutputStream getOutputStream()---返回此套接字的输出流。 

//PrintWriter打印流的构造方法
2.3--PrintWriter(OutputStream out, boolean autoFlush)---通过现有的 OutputStream 创建新的 PrintWriter,自带刷新效果

//PrintWriter打印流的写入方法
2.4--void write(char[] buf)---写入字符数组。 
2.5--void write(int c)---写入单个字符。 
2.6--void write(String s)---写入字符串。 

//OutputStream字节输出流的写入方法
2.7--void write(byte[] b)---将 b.length 个字节从指定的 byte 数组写入此输出流。 

//OutputStreamWriter字节流转字符流的构造方法
2.8--OutputStreamWriter(OutputStream out)创建使用默认字符编码的 OutputStreamWriter。

//BufferedWriter高效字符输出流的构造方法
2.9--BufferedWriter(Writer out)---创建一个使用默认大小输出缓冲区的缓冲字符输出流。

//BufferedWriter高效字符输出流的常用方法
2.10-- void write(String s) 写入字符串。 
2.11--void flush()---刷新此输出流并强制写出所有缓冲的输出字节。 

3.JDK提供了一个ServerSocket类,用于实现服务器端的程序

//ServerSocket类的构造方法
3.1--ServerSocket(int port)---创建绑定到特定端口的服务器套接字。

//ServerSocket类的一个很重要的方法,进入监听状态----返回的是一个Socket对象
3.2--Socket accept()---侦听并接受到此套接字的连接。 

//Socket类的一个很重要的方法,通过Socket对象调用该输入流方法获取从客户端传来的信息
3.3--InputStream getInputStream()---返回此套接字的输入流。 

//InputStreamReader字节转字符的构造方法
3.4--InputStreamReader(InputStream in)---创建一个使用默认字符集的 InputStreamReader。

//BufferedReader高效字符输入流的构造方法
3.5--BufferedReader(Reader in)---创建一个使用默认大小输入缓冲区的缓冲字符输入流。

//BufferedReader高效字符输入流的常用方法
3.6--String readLine()---读取一个文本行。 

4.TCP通信Java代码

package com.bianyiit.tcp;
//客户端通信代码
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class SocketDemo1 {
    public static void main(String[] args) throws IOException {
        //创建客户端与服务器端的连接对象
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //传输数据??---需要用到流对象---字节输出流
        //返回连接对象调用getOutputStream()---返回字节输出流对象
        OutputStream os = socket.getOutputStream();
        //把字节输出流转换成打印流
        //因为参数设置为true时,打印流有一个自动刷新的效果,
        PrintWriter pw=new PrintWriter(os,true);
        String s1="hello树先生";
        pw.write(s1);
        //释放资源
        pw.close();
        socket.close();
    }
}
package com.bianyiit.tcp;
//服务端通信代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerSocketDemo1 {
    public static void main(String[] args) throws IOException {
        //创建服务器端和客户端的连接对象
        ServerSocket serverSocket = new ServerSocket(9999);
        //先要进入监听状态----返回的是一个Socket对象
        Socket accept = serverSocket.accept();
        //创建字节输入流对象,调用getInputStream()--返回的是InputStream对象
        InputStream is = accept.getInputStream();
        //把字节输入流转换成字符输入流
        InputStreamReader isr = new InputStreamReader(is);
        //将字符转换流转换成高效流
        BufferedReader br = new BufferedReader(isr);
        //读取数据
        String s = br.readLine();
        System.out.println(s);
    }
}
未完待续....
发布了73 篇原创文章 · 获赞 11 · 访问量 2465

猜你喜欢

转载自blog.csdn.net/weixin_43908333/article/details/103299044