主页 > IT业界  > 

菜鸟之路Day21一一网络编程

菜鸟之路Day21一一网络编程
菜鸟之路Day21一一网络编程(一)

作者:blue

时间:2025.3.2

文章目录 菜鸟之路Day21一一网络编程(一)0.概述1.初识网络编程2.网络编程三要素3.InetAddress类的使用4.UDP通信程序4.1发送数据4.2接受数据4.3UDP通信程序练习(聊天室)4.4单播,组播,广播 5.TCP通信程序6.综合练习6.1综合练习1(多发多收)6.2综合练习2(接收并反馈)6.3综合练习3(上传文件)6.4综合练习4(解决上一题文件名重复的问题)6.5综合练习5(上传文件一一多线程版)6.6综合练习6(线程池优化)

0.概述

内容学习自黑马程序员BV1yW4y1Y7Ms

1.初识网络编程

①什么是网络编程:计算机与计算机之间通过网络进行数据传输

②常见软件架构有哪些:CS/BS

③通信的软件架构CS/BS各有什么区别和优缺点

​ CS:客户端服务端模式需要开发客户端

​ BS:浏览器服务端模式不需要开发客户端

​ CS:适合定制专业化的办公软件如:IDEA,网游

​ BS:适合移动互联网应用,可以在任何地方随时访问的系统

2.网络编程三要素

IP:设备在网络中的地址,是唯一的标识

端口号:应用程序在设备中唯一的标识

协议:数据在网络中传输的规则,常见的协议有UDP,TCP,http,https,ftp

3.InetAddress类的使用

InetAddress类表示互联网协议(IP)地址

public class myInetAddressDemo1 { public static void main(String[] args) throws UnknownHostException { /* * static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 * String getHostName() 获取此IP地址的主机名 * String getHostAddress() 返回文本显示中IP地址字符串 * */ //获取InetAddress对象 //IP的对象或者说是主机的对象 InetAddress address = InetAddress.getByName("LAPTOP-CFHO6DM4"); //InetAddress address = InetAddress.getByName("192.168.213.203"); System.out.println(address); //获取主机名 String hostName = address.getHostName(); System.out.println(hostName); //获取对应的ip String ip = address.getHostAddress(); System.out.println(ip); } } 4.UDP通信程序 4.1发送数据

①创建发送端的DatagramSocket对象;②数据打包(DatagramPacket)

③发送数据;④释放资源

public class SendMessageDemo { public static void main(String[] args) throws IOException { //1.创建发送端的DatagramSocket对象 //细节: //绑定端口,以后我们就是通过这个端口往外发送 //空参:所有可用的都拗口中随机一个进行使用 //有参:指定端口号进行绑定 DatagramSocket ds = new DatagramSocket(); //2.打包要发送的数据 String str = "好好学习,天天向上"; byte[] bytes = str.getBytes();//转为字节数组 InetAddress ip = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port); //3.发送数据 ds.send(dp); //4.释放资源 ds.close(); } } 4.2接受数据

①创建接收端的DatagramSocket对象;②接收打包好的数据

③解析数据包;④释放资源

public class ReceiveMessageDemo { public static void main(String[] args) throws IOException { //1.创建DatagramSocket对象 //注意:此时接收端所指定的端口号,必须与发送方的目的端口号相一致才能接收到数据 DatagramSocket ds = new DatagramSocket(10086); //2.接收打包好的数据 byte[] bytes = new byte[1024];//创建一个字节数组来存放接收到的数据 DatagramPacket dp = new DatagramPacket(bytes,bytes.length); ds.receive(dp);//接收数据,注意,这个方法是阻塞的,收不到数据程序就会停在这里 //3.解析数据包 byte[] data = dp.getData(); //获取接收到的字节数组 int length = dp.getLength();//获取数据报文的长度 int port = dp.getPort(); //获取发送方的端口号 InetAddress ip = dp.getAddress();//获取发送方的ip System.out.println("收到数据:"+new String(data,0,length)); System.out.println("数据长度:"+length); System.out.println("数据从发送方的"+port+"端口发出"); System.out.println("发送方的IP地址为:"+ip); //4.释放资源 ds.close(); } } 4.3UDP通信程序练习(聊天室)

按照下面的要求实现程序

UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束

UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

发送端:

public class SendMessage { public static void main(String[] args) throws IOException { //发送端 DatagramSocket ds = new DatagramSocket(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入你想说的话"); String str = sc.nextLine(); InetAddress ip = InetAddress.getByName("127.0.0.1"); int port = 10086;//目的端口和目的地址 DatagramPacket dp = new DatagramPacket(str.getBytes(),str.getBytes().length,ip,port); ds.send(dp);//发送数据 if("886".equals(str)) break; } //释放资源 ds.close(); } }

接收端:

public class ReceiveMessage { public static void main(String[] args) throws IOException { //接收端 DatagramSocket ds = new DatagramSocket(10086); byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); while (true) { ds.receive(dp); byte[] data = dp.getData(); int length = dp.getLength(); String ip = dp.getAddress().getHostAddress(); String name = dp.getAddress().getHostName(); System.out.println("收到来自ip为:"+ip+"主机名为:"+name+"所发送的信息:"+new String(data,0,length)); } } } 4.4单播,组播,广播

单播:上述代码都是单播

组播:组播地址:224.0.0.0 - 239.255.255.255,其中224.0.0.0 - 224.0.0.255为预留的组播地址

同一分组的ip都可以接收到信息

组播发送端

public class SendMessage { public static void main(String[] args) throws IOException { //组播发送端 //创建MulticastSocket对象 MulticastSocket ms = new MulticastSocket(); //创建DatagramPacket对象 String str = "你好,你好"; byte[] bytes = str.getBytes(); InetAddress ip = InetAddress.getByName("224.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port); //发送数据 ms.send(dp); //释放资源 ms.close(); } }

组播接收端

有多个组播接收端,只要接收端的ip为发送端目的的组播ip,就都能收到信息

public class ReceiveMessageOne { public static void main(String[] args) throws IOException { //组播接收端 //创建MulticastSocket对象 MulticastSocket ms = new MulticastSocket(10086); //将当前本机,添加到224.0.0.1这一组中 InetAddress ip = InetAddress.getByName("224.0.0.1"); ms.joinGroup(ip); //创建DatagramPacket对象 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //接收数据 ms.receive(dp); //解析数据 byte[] data = dp.getData(); int length = dp.getLength(); String HostAddress = dp.getAddress().getHostAddress(); String name = dp.getAddress().getHostName(); System.out.println("收到来自ip为:"+HostAddress+"主机名为:"+name+"所发送的信息:"+new String(data,0,length)); //释放资源 ms.close(); } }

广播:广播地址:255.255.255.255

局域网内任意ip都可以接收到信息

只需要将目的ip改为:255.255.255.255

public class SendMessageDemo { public static void main(String[] args) throws IOException { //1.创建发送端的DatagramSocket对象 //细节: //绑定端口,以后我们就是通过这个端口往外发送 //空参:所有可用的端口中随机一个进行使用 //有参:指定端口号进行绑定 DatagramSocket ds = new DatagramSocket(); //2.打包要发送的数据 String str = "好好学习,天天向上"; byte[] bytes = str.getBytes();//转为字节数组 InetAddress ip = InetAddress.getByName("255.255.255.255"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port); //3.发送数据 ds.send(dp); //4.释放资源 ds.close(); } } 5.TCP通信程序

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象

通信之前要保证连接已经建立

通过Socket产生IO流来进行网络通信

客户端流程:

①创建客户端Socket对象(Socket)与指定服务端连接

Socket(String host,int port)

②获取输出流,写数据

OutputStream getOutputStream()

③释放资源

void close() public class Client { public static void main(String[] args) throws IOException { //创建客户端Socket对象(Socket)与指定服务端连接 Socket socket = new Socket("127.0.0.1",10000); //获取输出流,写数据 OutputStream os = socket.getOutputStream(); os.write("aaaa".getBytes()); //释放资源 os.close(); socket.close(); } }

服务端流程:

①创建服务器端的Socket对象(ServerSocket)

ServerSocket(int port)

②监听客户端连接,返回一个Socket对象

Socket accpet()

③获取输入流,读数据,并把数据显示在控制台

InputStream getInputStream()

④释放资源

void close() public class Server { public static void main(String[] args) throws IOException { //创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(10000); //监听客户端连接,返回一个Socket对象 Socket accept = ss.accept(); //获取输入流,读数据,并把数据显示在控制台 InputStream is = accept.getInputStream(); int b; while((b=is.read())!=-1){ System.out.println((char)b); } //释放资源 is.close(); ss.close(); } } 6.综合练习 6.1综合练习1(多发多收)

客户端:多次发送数据

服务器:接收多次接收数据,并打印

客户端

public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",10000); Scanner sc = new Scanner(System.in); OutputStream os = socket.getOutputStream(); while (true) { System.out.println("请输入你要发送的信息"); String str = sc.nextLine(); os.write(str.getBytes()); if("886".equals(str)) break; } socket.close(); } }

服务端

public class Server { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(10000); //监听 Socket accept = ss.accept(); InputStreamReader isr = new InputStreamReader(accept.getInputStream()); int b; while((b= isr.read())!=-1){ System.out.print((char)b); } //释放资源 accept.close(); ss.close(); } } 6.2综合练习2(接收并反馈)

客户端:发送一条数据,接收服务端反馈的消息并打印

服务器:接收数据并打印,再给客户端反馈消息

客户端

public class Client { public static void main(String[] args) throws IOException { //创建Socket对象 Socket socket = new Socket("127.0.0.1",10000); //发送数据 OutputStream os = socket.getOutputStream(); String str="见到你很高兴!"; os.write(str.getBytes()); //写一个结束标志 socket.shutdownOutput(); //接受服务器端返回数据 InputStreamReader isr = new InputStreamReader(socket.getInputStream()); int b; while((b= isr.read())!=-1){ System.out.println((char)b); } //释放资源 socket.close(); } }

服务端

public class Server { public static void main(String[] args) throws IOException { //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10000); //监听客户端 Socket socket = ss.accept(); //接收来自客户端的数据 InputStreamReader isr = new InputStreamReader(socket.getInputStream()); int b; while((b= isr.read())!=-1){ System.out.println((char)b); } //对客户端进行反馈 OutputStream os = socket.getOutputStream(); String str="有多开心呢?"; os.write(str.getBytes()); socket.close(); ss.close(); } } 6.3综合练习3(上传文件)

客户端:将本地文件上传到服务器。接收服务器的反馈。

服务器:接收客户端上传的文件,上传完毕之后给出反馈。

客户端

public class Client { public static void main(String[] args) throws IOException { //创建Socket Socket socket = new Socket("127.0.0.1",10000); //读本地文件的数据,然后发出去 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src\\ClientDir\\girl1.jpg")); BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); int len; byte[] bytes = new byte[1024*5]; while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bis.close(); //结束标志,很关键 socket.shutdownOutput(); //接收服务端反馈 InputStreamReader isr = new InputStreamReader(socket.getInputStream()); int B; while((B=isr.read())!=-1){ System.out.println((char)B); } //释放资源 socket.close(); } }

服务器

public class Server { public static void main(String[] args) throws IOException { //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10000); //监听客户端 Socket socket = ss.accept(); //接收客户端发来的数据,写到本地 BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\girl1.jpg")); int len; byte[] bytes = new byte[1024*5]; while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bos.close(); //向客户端反馈 BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream()); Bos.write("上传成功".getBytes()); Bos.flush(); // 刷新输出流,确保数据发送到客户端 //释放资源 socket.close(); ss.close(); } } 6.4综合练习4(解决上一题文件名重复的问题)

我们可以用UUID这个类,来形成随机的文件名称

public class UUIDdemo { public static void main(String[] args) { String str = UUID.randomUUID().toString().replace("-",""); System.out.println(str); } }

修改上题的服务端代码,将文件名替换为随机的UUID

public class Server { public static void main(String[] args) throws IOException { //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10000); //监听客户端 Socket socket = ss.accept(); //接收客户端发来的数据,写到本地 BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); String name = UUID.randomUUID().toString().replace("-","");//随机的文件名 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\"+name+".jpg")); int len; byte[] bytes = new byte[1024*5]; while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bos.close(); //向客户端反馈 BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream()); Bos.write("上传成功".getBytes()); Bos.flush(); // 刷新输出流,确保数据发送到客户端 //释放资源 socket.close(); ss.close(); } } 6.5综合练习5(上传文件一一多线程版)

Runnable类

public class MyRunnable implements Runnable{ Socket socket; public MyRunnable(Socket socket) { this.socket = socket; } @Override public void run() { try { //接收客户端发来的数据,写到本地 BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); String name = UUID.randomUUID().toString().replace("-","");//随机的文件名 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\ServerDIr\\"+name+".jpg")); int len; byte[] bytes = new byte[1024*5]; while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bos.close(); //向客户端反馈 BufferedOutputStream Bos = new BufferedOutputStream(socket.getOutputStream()); Bos.write("上传成功".getBytes()); Bos.flush(); // 刷新输出流,确保数据发送到客户端 } catch (IOException e) { throw new RuntimeException(e); } finally { if (socket!=null) { //做一个非空判断 try { socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } }

服务端

public class Server { public static void main(String[] args) throws IOException { //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10000); while (true) { //监听客户端 Socket socket = ss.accept(); //开启一条线程,一个用户对应服务端一条线程 new Thread(new MyRunnable(socket)).start(); } } } 6.6综合练习6(线程池优化)

频繁创建线程并销毁非常浪费系统资源,所以要用线程池优化,需要更改的只有服务端的代码

服务端

public class Server { public static void main(String[] args) throws IOException { //创建ServerSocket对象 ServerSocket ss = new ServerSocket(10000); //线程池 ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor( 3,//核心线程数量,不能小于0 16,//最大线程数,不能小于0,最大数量 >= 核心线程数量 60,//空闲线程最大存活时间 TimeUnit.SECONDS,//时间单位 new ArrayBlockingQueue<>(3),//任务队列 Executors.defaultThreadFactory(),//创建线程工厂 new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略 ); while (true) { //监听客户端 Socket socket = ss.accept(); //开启一条线程,一个用户对应服务端一条线程 poolExecutor.submit(new MyRunnable(socket)); } } }
标签:

菜鸟之路Day21一一网络编程由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“菜鸟之路Day21一一网络编程