线程池、网络编程——day21
2021/7/3 9:51:24
本文主要是介绍线程池、网络编程——day21,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在jdk1.5之后引入了了线程池的概念
生产线程池的工厂类
/* 线程池:JDK1.5之后提供的 java.util.concurrent.Executors:线程池的工厂类,用来生成线程池 Executors类中的静态方法: static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池 参数: int nThreads:创建线程池中包含的线程数量 返回值: ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程) java.util.concurrent.ExecutorService:线程池接口 用来从线程池中获取线程,调用start方法,执行线程任务 submit(Runnable task) 提交一个 Runnable 任务用于执行 关闭/销毁线程池的方法 void shutdown() 线程池的使用步骤: 1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务 3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法 4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行) */
代码实现
public class Demo01ThreadPool { public static void main(String[] args) { //1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池 ExecutorService es = Executors.newFixedThreadPool(2); //3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法 es.submit(new RunnableImpl());//pool-1-thread-1创建了一个新的线程执行 //线程池会一直开启,使用完了线程,会自动把线程归还给线程池,线程可以继续使用 es.submit(new RunnableImpl());//pool-1-thread-1创建了一个新的线程执行 es.submit(new RunnableImpl());//pool-1-thread-2创建了一个新的线程执行 //4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行) es.shutdown(); es.submit(new RunnableImpl());//抛异常,线程池都没有了,就不能获取线程了 } }
/* 2.创建一个类,实现Runnable接口,重写run方法,设置线程任务 */ public class RunnableImpl implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"创建了一个新的线程执行"); } }
网络编程
网络编程前文:
import java.net.InetAddress; import java.net.UnknownHostException; //static InetAddress getByName(String host) // 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 //String getHostName() 获取此IP地址的主机名 //String getHostAddress() 返回文本显示中的IP地址字符串 public class InetadressDemo1 { public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("沉迷代码"); String hostName = address.getHostName(); System.out.println("主机名为" + hostName); String ip = address.getHostAddress(); System.out.println("IP为" + ip); } }
一个端口号只能被一个应用程序使用
端口号是由两个字节组成 取值在0—65535之间,但是1024之前的端口号不能用,已经被系统分配给已知的网络软件了,网络软件的端口号不能重复
通信概述
UDP编程
Client端代码实现
import java.io.IOException; import java.net.*; public class ClientDemo { public static void main(String[] args) throws IOException { //1.找码头 DatagramSocket ds = new DatagramSocket();//空参表示会随机绑定一个动态端口把包发送出去 //2.打包 //DatagramPacket(byte[] buf, int length, InetAddress address, int port) String s = "这是我要发送的数据"; //把一个字符串变成字节数组 byte[] bytes = s.getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10000; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port); //3.由码头发送包裹 ds.send(dp); //4.关闭资源 ds.close(); } }
Server端代码实现
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class ServerDemo { //注意点: //1.要先运行接收端,再运行发送端;因为UDP是面向无连接的, // 所以发送端直接把数据已经发出来了 在运行接收端就收不到数据了。。 //2.如果接收端再启动之后,没有接收到数据,那么会死等(阻塞). //3.在接收数据的时候,需要调用一个getLength方法,表示接收到了多少字节 public static void main(String[] args) throws IOException { //1.找码头 ---- 表示接收端从10000端口接收数据的. DatagramSocket ds = new DatagramSocket(10000); //2,创建一个新的箱子 byte [] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes,bytes.length); //3.接收礼物,把礼物放到新的箱子中 System.out.println("-----------接收前----------"); ds.receive(dp); System.out.println("------------接收后---------"); //4.从新的箱子里面获取礼物 // byte[] data = dp.getData(); //因为字节数组定义1024会输出很多空格,所以在这里把有效数据转换成字符串 int length = dp.getLength(); //把数组变成字符串打印输出 System.out.println(new String(bytes,0,length)); //5.关掉资源 ds.close(); } }
UDP通讯练习题
发送端代码实现
import java.io.IOException; import java.net.*; import java.util.Scanner; public class ClientDemo { public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); DatagramSocket ds = new DatagramSocket(); while (true) {//选中后ctrl+alt+t即可 //传输的数据就来自键盘录入 String s = sc.nextLine(); if("886".equals(s)){ break; } //要把字符串转换为字节数组才能传输 byte[] bytes = s.getBytes(); //告知要把数据发送到哪台电脑上 InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10000; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port); ds.send(dp); } ds.close(); } }
接收端代码实现
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class ServerDemo { public static void main(String[] args) throws IOException { DatagramSocket ds = new DatagramSocket(10000); while (true) { byte [] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes,bytes.length); ds.receive(dp); //把数据放到数组中 byte[] data = dp.getData(); //然后设置有效字符 把字符转换成字符串输出 int length = dp.getLength(); System.out.println(new String(data,0,length)); } // ds.close(); } }
UDP拓展——实现聊天功能
实现客户机和服务器之间互动,一发一回;这种缺陷是只能一发一回,因为接收端的receive方法是个阻塞的,它是需要等客户端发过来消息才进行下一步
先做一个工具类,代码实现
import java.net.DatagramPacket; import java.net.InetAddress; import java.net.UnknownHostException; /** * @Author: kerwin * @Description: */ public class NetworkUtils { // 获取发送端数据报包的方法 public static DatagramPacket getSendPacket(String msg, String ip, int port) throws UnknownHostException { // 把需要发送的数据转化为字节数组 byte[] bytes = msg.getBytes(); InetAddress targetIp = InetAddress.getByName(ip); // 创建用于发送的数据报包 DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, targetIp, port); return sendPacket; } // 获取用于接收的数据报包的方法 public static DatagramPacket getReceivePacket() { byte[] bytes = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(bytes, 0, bytes.length); return receivePacket; } // 解析数据报包的方法 public static String parsePacket(DatagramPacket packet){ byte[] data = packet.getData(); int offset = packet.getOffset(); int length = packet.getLength(); String s = new String(data, offset, length); return s; } }
发送端代码实现
import com.kerwin.lianxi.util.NetworkUtils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; /** * @Author: kerwin * @Description: */ public class Sender { public static void main(String[] args) throws IOException { // 创建用于发送的socket对象 DatagramSocket datagramSocket = new DatagramSocket(8888); // 键盘接收数据 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String msg; while ((msg = br.readLine()) != null) { // 把键盘输入的数据封装到数据报包里面 DatagramPacket sendPacket = NetworkUtils.getSendPacket(msg, "127.0.0.1", 9999); // send方法发送出去 datagramSocket.send(sendPacket); // 以上是发送的接收 // 下面是接收数据 // 获取一个用于接收的数据报包 DatagramPacket receivePacket = NetworkUtils.getReceivePacket(); // receive方法接收 // receive方法是一个阻塞方法 datagramSocket.receive(receivePacket); // 解析数据报包 String s = NetworkUtils.parsePacket(receivePacket); // 获取数据 报包的ip地址 SocketAddress socketAddress = receivePacket.getSocketAddress(); System.out.println("接收到了来自"+socketAddress+"的消息: " + s); } } }
接收端代码实现
import com.kerwin.lianxi.util.NetworkUtils; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; import java.util.Scanner; /** * @Author: kerwin * @Description: */ public class Receiver { public static void main(String[] args) throws IOException { // 创建用于接收的socket对象 DatagramSocket datagramSocket = new DatagramSocket(9999); // 接盘接收数据 Scanner scanner = new Scanner(System.in); while (true) { // 创建用于接收的数据报包 DatagramPacket receivePacket = NetworkUtils.getReceivePacket(); // receive datagramSocket.receive(receivePacket); // 解析数据报包 String msg = NetworkUtils.parsePacket(receivePacket); SocketAddress socketAddress = receivePacket.getSocketAddress(); System.out.println("Receiver接收到了来自"+socketAddress+"的消息: " + msg); // 下面是给Sender发送消息 // 创建用于发送的数据报包 数据来源就是键盘输入 String s = scanner.nextLine(); DatagramPacket sendPacket = NetworkUtils.getSendPacket(s, "127.0.0.1", 8888); // send方法发送出去 datagramSocket.send(sendPacket); } } }
UDP拓展——把上面的案例优化
实现可以重复发送消息,这里使用多线程的方式,一个线程是发送,一个线程接收;还需要两个类,一个人和另一个人
两个类代码实现
import java.io.IOException; import java.net.DatagramSocket; /** * @Author: kerwin * @Description: */ public class OnePerson { public static void main(String[] args) throws IOException { // 创建UDP的socket对象 DatagramSocket datagramSocket = new DatagramSocket(8888); // 创建线程并启动 new Thread(new SendTask(datagramSocket,"127.0.0.1",9999)).start(); new Thread(new ReceiveTask(datagramSocket)).start(); } }
import java.io.IOException; import java.net.DatagramSocket; /** * @Author: kerwin * @Description: */ public class AnotherPerson { public static void main(String[] args) throws IOException { // 创建UDP的socket对象 DatagramSocket datagramSocket = new DatagramSocket(9999); // 创建线程并启动 new Thread(new SendTask(datagramSocket,"127.0.0.1",8888)).start(); new Thread(new ReceiveTask(datagramSocket)).start(); } }
两个线程代码实现
import com.kerwin.lianxi.util.NetworkUtils; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.UnknownHostException; import java.util.Scanner; /** * @Author: kerwin * @Description: */ public class SendTask implements Runnable{ // 定义成员变量 DatagramSocket datagramSocket; // 目标ip port String ip; int port; public SendTask(DatagramSocket datagramSocket, String ip, int port) { this.datagramSocket = datagramSocket; this.ip = ip; this.port = port; } @Override public void run() { // 只干一件事情 发送消息 Scanner scanner = new Scanner(System.in); while (true) { // 从键盘接收数据 String sendMsg = scanner.nextLine(); // 创建用于发送的数据报包 try { DatagramPacket sendPacket = NetworkUtils.getSendPacket(sendMsg, ip, port); // 发送出去 datagramSocket.send(sendPacket); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
import com.kerwin.lianxi.util.NetworkUtils; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * @Author: kerwin * @Description: */ public class ReceiveTask implements Runnable{ // 成员变量 DatagramSocket datagramSocket; public ReceiveTask(DatagramSocket datagramSocket) { this.datagramSocket = datagramSocket; } @Override public void run() { // 只干一件事情 接收数据 并打印 while (true) { // 创建接收的数据报包 DatagramPacket receivePacket = NetworkUtils.getReceivePacket(); // receive方法接收数据 try { datagramSocket.receive(receivePacket); // parse数据报包 String receiveMsg = NetworkUtils.parsePacket(receivePacket); System.out.println(receiveMsg); } catch (IOException e) { e.printStackTrace(); } } } }
TCP编程
客户端代码实现
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据 表示客户端的类: java.net.Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。 套接字:包含了IP地址和端口号的网络单位 构造方法: Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。 参数: String host:服务器主机的名称/服务器的IP地址 int port:服务器的端口号 成员方法: OutputStream getOutputStream() 返回此套接字的输出流。 InputStream getInputStream() 返回此套接字的输入流。 void close() 关闭此套接字。 实现步骤: 1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号 2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象 3.使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据 4.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象 5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据 6.释放资源(Socket) 注意: 1.客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象 2.当我们创建客户端对象Socket的时候,就会去请求服务器和服务器经过3次握手建立连接通路 这时如果服务器没有启动,那么就会抛出异常ConnectException: Connection refused: connect 如果服务器已经启动,那么就可以进行交互了 */ public class TCPClient { public static void main(String[] args) throws IOException { //1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号 Socket socket = new Socket("127.0.0.1",8888); //2.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象 OutputStream os = socket.getOutputStream(); //3.使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据 os.write("你好服务器".getBytes()); //4.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象 InputStream is = socket.getInputStream(); //5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据 byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes,0,len)); //6.释放资源(Socket) socket.close(); } }
服务器代码实现
未完持续...
这篇关于线程池、网络编程——day21的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-27消息中间件底层原理资料详解
- 2024-11-27RocketMQ底层原理资料详解:新手入门教程
- 2024-11-27MQ底层原理资料详解:新手入门教程
- 2024-11-27MQ项目开发资料入门教程
- 2024-11-27RocketMQ源码资料详解:新手入门教程
- 2024-11-27本地多文件上传简易教程
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器