day26(026-网络编程)
###26.02_网络编程(网络编程三要素之IP概述)
-
-
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
-
-
每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
-
端口号范围从0-65535
-
编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
-
常用端口
-
mysql: 3306
-
oracle: 1521
-
web: 80
-
-
-
为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
-
UDP
-
面向无连接,数据不安全,速度快。不区分客户端与服务端。
-
-
TCP
-
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
-
-
Socket套接字概述:
-
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
-
通信的两端都有Socket。
-
网络通信其实就是Socket间的通信。
-
数据在两个Socket间通过IO流传输。
-
-
-
1.发送Send
-
创建DatagramSocket, 随机端口号(空参构造new即可)
-
创建DatagramPacket, 指定数据, 长度, 地址, 端口
-
使用DatagramSocket发送DatagramPacket
-
关闭DatagramSocket
-
-
2.接收Receive
-
创建DatagramSocket, 指定端口号
-
创建DatagramPacket, 指定数组, 长度
-
使用DatagramSocket接收DatagramPacket
-
关闭DatagramSocket
-
-
-
- String ip = packet.getAddress().getHostAddress();
打开cmd黑窗口,进入.java编译后字节码的bin目录。
cd C:\Users\kangy\Desktop\demo\day26\bin
先执行启动接收端
java com.heima.socket.Demo1_Receive
然后启动发送端
java com.heima.socket.Demo1_Send
Demo1_Send
package com.heima.socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; public class Demo1_Send { /** * * 1.发送Send * 创建DatagramSocket, 随机端口号 * 创建DatagramPacket, 指定数据, 长度, 地址, 端口 * 使用DatagramSocket发送DatagramPacket * 关闭DatagramSocket * @throws SocketException * @throws UnknownHostException */ public static void main(String[] args) throws Exception { String str = "what are you 弄啥呢?"; DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头 DatagramPacket packet = //创建Packet相当于集装箱 new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发货,将数据发出去 socket.close(); //关闭码头 } }
Demo1_Receive
package com.heima.socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class Demo1_Receive { /** ** 2.接收Receive * 创建DatagramSocket, 指定端口号 * 创建DatagramPacket, 指定数组, 长度 * 使用DatagramSocket接收DatagramPacket * 关闭DatagramSocket * 从DatagramPacket中获取数据 * @throws SocketException */ public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱 socket.receive(packet); //接货,接收数据 byte[] arr = packet.getData(); //获取数据 int len = packet.getLength(); //获取有效的字节个数 System.out.println(new String(arr,0,len)); socket.close(); } }
Demo2_Send
package com.heima.socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Scanner; public class Demo2_Send { /** * * 1.发送Send * 创建DatagramSocket, 随机端口号 * 创建DatagramPacket, 指定数据, 长度, 地址, 端口 * 使用DatagramSocket发送DatagramPacket * 关闭DatagramSocket * @throws SocketException * @throws UnknownHostException */ public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); //创建键盘录入对象 DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头 while(true) { String line = sc.nextLine(); //获取键盘录入的字符串 if("quit".equals(line)||"exit".equals(line)) { break; } DatagramPacket packet = //创建Packet相当于集装箱 new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发货,将数据发出去 } socket.close(); //关闭码头 sc.close(); //关闭Scanner } }
Demo2_Receive
package com.heima.socket; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class Demo2_Receive { /** ** 2.接收Receive * 创建DatagramSocket, 指定端口号 * 创建DatagramPacket, 指定数组, 长度 * 使用DatagramSocket接收DatagramPacket * 关闭DatagramSocket * 从DatagramPacket中获取数据 * @throws Exception */ public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱 while(true) { socket.receive(packet); //接货,接收数据 byte[] arr = packet.getData(); //获取数据 int len = packet.getLength(); //获取有效的字节个数 String ip = packet.getAddress().getHostAddress(); //获取ip地址 int port = packet.getPort(); //获取端口号 System.out.println(ip + ":" + port + ":" + new String(arr,0,len)); } } }
测试命令
java com.heima.socket.Demo2_Receive
java com.heima.socket.Demo2_Send
###26.08_网络编程(UDP传输多线程)
Demo3_MoreThread
package com.heima.socket; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Scanner; public class Demo3_MoreThread { /** * main方法入口 * @param args */ public static void main(String[] args) { new Receive().start(); new Send().start(); } } class Receive extends Thread { public void run() { try { DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱 while(true) { socket.receive(packet); //接货,接收数据 byte[] arr = packet.getData(); //获取数据 int len = packet.getLength(); //获取有效的字节个数 String ip = packet.getAddress().getHostAddress(); //获取ip地址 int port = packet.getPort(); //获取端口号 System.out.println(ip + ":" + port + ":" + new String(arr,0,len)); } } catch (IOException e) { e.printStackTrace(); } } } class Send extends Thread { public void run() { try { Scanner sc = new Scanner(System.in); //创建键盘录入对象 DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头 while(true) { String line = sc.nextLine(); //获取键盘录入的字符串 if("quit".equals(line)||"exit".equals(line)) { break; } DatagramPacket packet = //创建Packet相当于集装箱 new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发货,将数据发出去 } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
-
创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
-
调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
-
输入流可以读取服务端输出流写出的数据
-
输出流可以写出数据到服务端的输入流
-
-
2.服务端
-
创建ServerSocket(需要指定端口号)
-
调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
-
调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
-
输入流可以读取客户端输出流写出的数据
-
-
Demo1_Server
package com.heima.tcp; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Demo1_Server { /** * * 2.服务端 * 创建ServerSocket(需要指定端口号) * 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket * 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流 * 输入流可以读取客户端输出流写出的数据 * 输出流可以写出数据到客户端的输入流 * @throws IOException */ public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(12345); Socket socket = server.accept(); //接受客户端的请求 InputStream is = socket.getInputStream(); //获取客户端输入流 OutputStream os = socket.getOutputStream(); //获取客户端的输出流 os.write("百度一下你就知道".getBytes()); //服务器向客户端写出数据 byte[] arr = new byte[1024]; int len = is.read(arr); //读取客户端发过来的数据 System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印 socket.close(); } }
Demo1_Client
package com.heima.tcp; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Demo1_Client { /** * * 1.客户端 * 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器 * 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流 * 输入流可以读取服务端输出流写出的数据 * 输出流可以写出数据到服务端的输入流 * @throws IOException * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1", 12345); InputStream is = socket.getInputStream(); //获取客户端输入流 OutputStream os = socket.getOutputStream(); //获取客户端的输出流 byte[] arr = new byte[1024]; int len = is.read(arr); //读取服务器发过来的数据 System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印 os.write("学习挖掘机哪家强?".getBytes()); //客户端向服务器写数据 socket.close(); } }
java com.heima.tcp.Demo1_Server
java com.heima.tcp.Demo1_Client
###26.17_网络编程(TCP协议代码优化)
Demo2_Server
package com.heima.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Demo2_Server { /** * * 2.服务端 * 创建ServerSocket(需要指定端口号) * 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket * 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流 * 输入流可以读取客户端输出流写出的数据 * 输出流可以写出数据到客户端的输入流 * @throws IOException */ public static void main(String[] args) throws IOException { //demo1(); ServerSocket server = new ServerSocket(12345); while(true) { final Socket socket = server.accept(); //接受客户端的请求 new Thread() { //匿名内部类 public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流 PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法 ps.println("欢迎咨询黑马程序员"); System.out.println(br.readLine()); ps.println("不好意思,爆满了"); System.out.println(br.readLine()); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } } public static void demo1() throws IOException { ServerSocket server = new ServerSocket(12345); Socket socket = server.accept(); //接受客户端的请求 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流 PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法 ps.println("欢迎咨询黑马程序员"); System.out.println(br.readLine()); //BufferedReader.readLine() ps.println("不好意思,爆满了"); System.out.println(br.readLine()); socket.close(); } }
Demo2_Client
package com.heima.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; public class Demo2_Client { /** * * 1.客户端 * 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器 * 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流 * 输入流可以读取服务端输出流写出的数据 * 输出流可以写出数据到服务端的输入流 * @throws IOException * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1", 12345); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流 PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法 System.out.println(br.readLine()); ps.println("我想报名黑马程序员"); System.out.println(br.readLine()); ps.println("大哭!!!能不能给次机会"); socket.close(); } }
Test1_Server
package com.heima.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Test1_Server { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(54321); System.out.println("服务器启动,绑定54321端口"); while(true) { final Socket socket = server.accept(); //接受客户端的请求 new Thread() { //开启一条线程 public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取输入流 PrintStream ps = new PrintStream(socket.getOutputStream());//获取输出流 String line = br.readLine(); //将客户端写过来的数据读取出来 line = new StringBuilder(line).reverse().toString(); //链式编程 ps.println(line); //反转后写回去 socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } } }
Test1_Client
package com.heima.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Test1_Client { /** * 客户端向服务器写字符串(键盘录入),服务器(多线程)将字符串反转后写回,客户端再次读取到是反转后的字符串 * @throws IOException * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException, IOException { Scanner sc = new Scanner(System.in); //创建键盘录入对象 Socket socket = new Socket("127.0.0.1", 54321); //创建客户端,指定ip地址和端口号 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取输入流 PrintStream ps = new PrintStream(socket.getOutputStream());//获取输出流 ps.println(sc.nextLine()); //将字符串写到服务器去 System.out.println(br.readLine()); //将反转后的结果读出来 socket.close(); } }
###26.20_网络编程(练习)
- 客户端向服务器上传文件
Test2_UpdateServer
package com.heima.test; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Test2_UpdateServer { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //3,建立多线程的服务器 ServerSocket server = new ServerSocket(12345); System.out.println("服务器启动,绑定12345端口号"); //4.读取文件名 while(true) { final Socket socket = server.accept(); //接受请求 new Thread() { public void run() { try { InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); PrintStream ps = new PrintStream(socket.getOutputStream()); String fileName = br.readLine(); //5.判断文件是否存在, 将结果发回客户端 File dir = new File("update"); dir.mkdir(); //创建文件夹 File file = new File(dir,fileName); //封装成File对象 if(file.exists()) { //如果服务器已经存在这个文件 ps.println("存在"); //将存在写给客户端 socket.close(); //关闭socket return; }else { ps.println("不存在"); } //8.定义FileOutputStream, 从网络读取数据, 存储到本地 FileOutputStream fos = new FileOutputStream(file); byte[] arr = new byte[8192]; int len; while((len = is.read(arr)) != -1) { fos.write(arr, 0, len); } fos.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } } }
Test2_UpdateClient
package com.heima.test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Test2_UpdateClient { /** * @param args * @throws IOException * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException, IOException { // 1.提示输入要上传的文件路径, 验证路径是否存在以及是否是文件夹 File file = getFile(); // 2.发送文件名到服务端 Socket socket = new Socket("127.0.0.1", 12345); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(file.getName()); // 6.接收结果, 如果存在给予提示, 程序直接退出 String result = br.readLine(); //读取存在后不存在的结果 if("存在".equals(result)) { System.out.println("您上传的文件已经存在,请不要重复上传"); socket.close(); return; } // 7.如果不存在, 定义FileInputStream读取文件, 写出到网络 FileInputStream fis = new FileInputStream(file); byte[] arr = new byte[8192]; int len; while((len = fis.read(arr)) != -1) { ps.write(arr, 0, len); } fis.close(); socket.close(); } private static File getFile() { Scanner sc = new Scanner(System.in); //创建键盘录入对象 System.out.println("请输入一个文件路径:"); while(true) { String line = sc.nextLine(); File file = new File(line); if(!file.exists()) { System.out.println("您录入的文件路径不存在,请重新录入:"); }else if(file.isDirectory()) { System.out.println("您录入的是文件夹路径,请输入一个文件路径:"); }else { return file; } } } }