文章目录
网络编程
1.1 概念
-
计算机网络:将分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,达到使不同计算机之间方便的床底信息,等资源的目的;
-
网络编程:使用套接字来达到进程间通信;现在一般称为TCP/IP编程;
-
套接字(socket):是一个抽象层,是一个接口,用来区分不同应用程序进程间的网络通信和连接
-
通信要素:
-
通信双方的地址:即在网络上准确的定位一台主机;
- IP
- 端口
-
通信的规则(协议):即实现数据的传输;包括对速率、传输代码、代码结构、传输控制、出错控制等制定的标准;
-
分层:
- 由于节点之间联系很复杂,在制定协议时,把复杂成分分解成一些简单的成分,在将他们复合起来。
- 最常用的方式就是层次方式,即同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。
- 各层互不影响,利于系统的开发和扩展;
-
分层规定:
- 把用户应用程序作为最高层;
- 物理通信线路作为最底层;
- 协议处理分为若干层;
- 规定每层处理的任务,也规定每层的接口标准;
-
参考模型:
-
-
-
1.2 IP协议
1. 概述
- IP最大贡献就是提供了独一无二的IP地址;
- 分类:
- ipv4 / ipv6
- ipv4:
- 4个字节组成,每个字节为0~255;
- 本机IP为:127.0.0.1(localhost);
- ipv6:
- 128位,8个无符号正数;
- 例:2001:0bb2:cccc:0015:0000:0000:1aaa:1312
- ipv4:
- 公网(互联网)–私网(局域网)
- ipv4 / ipv6
2. InetAddress类
-
InetAddress类表示互联网协议(IP)地址;
-
无构造方法,所以不可以直接new出一个对象;但是可以通过静态方法获得InetAddress的对象;
-
常用方法:
byte[] getAddress() //返回此 InetAddress 对象的原始 IP 地址。 static InetAddress getByName(String host) //在给定主机名的情况下确定主机的 IP 地址。 String getHostAddress() //返回 IP 地址字符串(以文本表现形式)。 String getHostName() //获取此 IP 地址的主机名。 static InetAddress getLocalHost() //返回本地主机。
-
代码:
import java.net.InetAddress; import java.net.UnknownHostException; /* 测试IP */ public class Demo01InetAddress { public static void main(String[] args) { try { //查询本机地址 InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1"); InetAddress inetAddress2 = InetAddress.getByName("localhost"); InetAddress inetAddress3 = InetAddress.getLocalHost(); System.out.println(inetAddress1); System.out.println(inetAddress2); System.out.println(inetAddress3); //查询网站ip地址 InetAddress inetAddress4 = InetAddress.getByName("www.baidu.com"); System.out.println(inetAddress4); //常用方法: System.out.println(inetAddress4.getCanonicalHostName()); //规范的名字 System.out.println(inetAddress4.getHostAddress()); //获得ip System.out.println(inetAddress4.getHostName()); //域名或者自己电脑的名字 } catch (UnknownHostException e) { e.printStackTrace(); } } }
-
结果演示:
1.3 端口
1. 概述
-
IP地址是用来定位一台计算机,但是一台计算机上可能提供多种网络应用程序,就需要用端口来区分这些不同的程序;
-
端口是虚拟的概念,并不是说在主机上真的存在若干个端口;
-
通过端口,可以在一个主机上运行多个网络应用程序;
-
端口的表示是一个16位的二进制数,2个字节,对应十进制的0~65535;
-
单个协议下,端口号不能冲突,多个协议下,端口号可以相同;
-
分类:
-
公有端口:0~1023
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
-
程序注册端口:1024~49151,用户分配或者程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
-
动态、私有:49152~65535
netstat -ano #查看所有端口 netstat -ano|findstr "5900" #查看指定的端口 tasklist|findstr "8696" #查看指定端口的进程
-
1.2 InetSocketAddress类
-
此类实现IP套接字地址(IP地址 + 端口号);
-
构造方法:
InetSocketAddress(InetAddress addr, int port) //根据 IP 地址和端口号创建套接字地址。 InetSocketAddress(int port) //创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。 InetSocketAddress(String hostname, int port) //根据主机名和端口号创建套接字地址。
-
常用方法
InetAddress getAddress() //返回此 InetAddress 对象的原始 IP 地址。 String getHostName() //获取此 IP 地址的主机名。 int getPort() //获取端口号。
-
代码:
import java.net.InetSocketAddress; /* 端口: */ public class Demo02InetSocketAddress { public static void main(String[] args) { //InetSocketAddress(String hostname, int port) 根据主机名和端口号创建套接字地址。 InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1", 8080); InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(inetSocketAddress1); System.out.println(inetSocketAddress2); // InetAddress getAddress() 返回此 InetAddress 对象的原始 IP 地址。 System.out.println(inetSocketAddress1.getAddress()); // String getHostName() //获取此 IP 地址的主机名 System.out.println(inetSocketAddress1.getHostName()); // int getPort() //获取端口号。 System.out.println(inetSocketAddress1.getPort()); } }
-
结果演示:
1.4 TCP协议和UDP协议
1.概述:
- TCP(transmission control protocol):是专门设计用于在不可靠的因特网上提供可靠的、端到端的字节流通信协议。它是一种面向连接的协议,它连接的是字节流而非报文流;
- UDP(user data protocol):UDP向应用程序提供了一种发送封装的原始IP数据报的方法、并且发送时无需建立连接,是一种不可靠的连接;
- TCP和UDP位于同一层,都是建立在IP层基础上;由于两台电脑之间的IP不同,因此被区分的两台的电脑就可以通信了;
- TCP是可靠连接,类似于打电话,只有等待对方接通的时候才可以交流,也就是确认了对方可以传信息,才会发送信息;但是传输速度慢;
- UDP是不可靠的,就像发短信,发出去就完事了,对方是否接收到就与自己无关了;但是传输速度快;
2. TCP
1. 传输消息
-
代码:
-
客户端:
/* 1. 连接服务器 Socket 2. 发送消息 */ import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; /* 客户端 */ public class Demo03TcpClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; try { //获得服务段的地址,端口号 InetAddress serverIP = InetAddress.getByName("127.0.0.1"); int port = 9999; //创建一个socket连接 socket = new Socket(serverIP, port); //发送消息 IO流 os = socket.getOutputStream(); os.write("你好,世界".getBytes()); } catch (Exception e) { e.printStackTrace(); }finally { if(os!=null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
服务端:
/* 1. 建立服务的端口 ServerSocket 2. 等待用户的链接 accept 3. 接收用的消息 */ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Demo03TcpSever { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { //地址: serverSocket = new ServerSocket(9999); while (true) { //等待客户端连接过来 socket = serverSocket.accept(); //读取客户端的信息 is = socket.getInputStream(); //管道流 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } System.out.println(baos.toString()); } } catch (IOException e) { e.printStackTrace(); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
-
结果:
2. 文件上传
-
代码:
-
客户端:
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; public class Demo04TCPClient { public static void main(String[] args) throws IOException { //创建一个Socket连接 Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000); //床加一个文件输出流 OutputStream os = socket.getOutputStream(); //读取文件 FileInputStream fis = new FileInputStream(new File("null.jpg")); //写出文件 byte[] bytes = new byte[1024]; int len; while ((len = fis.read(bytes)) != -1) { os.write(bytes, 0, len); } //通知服务器:此刻已经传输完成 socket.shutdownOutput(); //确定服务器接收完毕,才能够断开连接 InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len2; while ((len2 = is.read(buffer)) != -1) { baos.write(buffer, 0, len2); } System.out.println(baos.toString()); //关闭资源 baos.close(); is.close(); fis.close(); os.close(); socket.close(); } }
-
服务器端:
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Demo04TcpServer { public static void main(String[] args) throws IOException { //创建服务 ServerSocket serverSocket = new ServerSocket(9000); //监听客户端的连接:阻塞式监听,会一直等待客户端连接 Socket socket = serverSocket.accept(); //获取输入流 InputStream is = socket.getInputStream(); //文件输出 FileOutputStream fos = new FileOutputStream(new File("copyNull.jpg")); byte[] bytes = new byte[1024]; int len; while ((len = is.read(bytes)) != -1) { fos.write(bytes, 0, len); } //通知客户端 OutputStream os = socket.getOutputStream(); os.write("接收完毕,可以断开!".getBytes()); //关闭资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
-
-
结果演示:
3. UDP
1. 发送消息
-
不用连接,需要知道对方的地址;
-
代码:
-
发送者:
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Demo05UDPSender { public static void main(String[] args) throws Exception { //建立一个Socket DatagramSocket socket = new DatagramSocket(); //建个包 String msg = "你好,接收者!"; InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; //数据,数据的长度起始,要发送给谁 DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); //发送包 socket.send(packet); //释放资源 socket.close(); } }
-
接收者:
import java.net.DatagramPacket; import java.net.DatagramSocket; public class Demo05Receiver { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(9090); // 接收数据包 byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet); //阻塞接收 System.out.println(packet.getAddress().getHostAddress()); System.out.println(new String(packet.getData(),0,packet.getLength())); //释放资源 socket.close(); } }
-
-
结果演示:
2. 咨询
-
两个人都可以是发送方,也都可以是接收方;
-
代码:
-
发送方:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; public class Demo06UDPSender { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(8888); //准备数据 BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.print("Sender:"); String data = bReader.readLine(); //要发送的数据 byte[] datas = data.getBytes(); //数据打包 DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress("localhost", 6666)); //发送包 socket.send(packet); if (data.equals("bye")) { break; } } //释放资源 socket.close(); } }
-
接收方:
import java.net.DatagramPacket; import java.net.DatagramSocket; public class Demo06Receiver { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(6666); //准备接收包裹 while (true) { byte[] bytes = new byte[1024]; //数据打包 DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length); //接收包裹 socket.receive(packet); //获取包裹中的信息 byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); //接收到的信息 System.out.println("Receive:" + receiveData); //断开连接 if (receiveData.equals("bye")) { break; } } //释放资源 socket.close(); } }
-
-
结果演示:
- 发送方:
- 接收方:
- 发送方:
4. URL
-
统一资源定位符:定位资源的,定位互联网上的某一个资源;
-
构造方法:
//根据 String 表示形式创建 URL 对象。 URL(String spec) //根据指定 protocol、host、port 号和 file 创建 URL 对象。 URL(String protocol, String host, int port, String file) //根据指定的 protocol 名称、host 名称和 file 名称创建 URL。 URL(String protocol, String host, String file)
-
常用方法:
String getAuthority() //获取此 URL 的授权部分。 int getDefaultPort() //获取与此 URL 关联协议的默认端口号。 String getFile() //获取此 URL 的全路径。 String getHost() //获取此 URL 的主机名。 String getPath() //获取此 URL 的路径部分。 int getPort() //获取此 URL 的端口号。 String getUserInfo() //获取此 URL 的 userInfo 部分
-
代码:
import java.net.MalformedURLException; import java.net.URL; public class Demo07URL { public static void main(String[] args) throws MalformedURLException { URL url = new URL("http://localhost:8080/helloworld/index.hsp?username=user&password=123456"); System.out.println("协议:" + url.getProtocol()); //协议 System.out.println("IP:" + url.getHost());//主机IP System.out.println("端口:" + url.getPort());//端口 System.out.println("文件:" + url.getPath());//文件 System.out.println("全路径:" + url.getFile());//全路径 System.out.println("参数:" + url.getQuery());//获得参数 } }
-
结果演示:
下载资源
-
代码:
package com.sd.day24_NEt; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class UrlDownLoad { public static void main(String[] args) throws Exception { //1.下载地址 URL url = new URL("https://m10.music.126.net/20191203153305/461b409d4de7fe8b89cf0dcce1783f47/yyaac/075c/0109/000e/06acc637d46c59e3b9917da4ed03d17f.m4a"); //2.链接到资源 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream is = urlConnection.getInputStream(); FileOutputStream fos = new FileOutputStream("a.m4a"); byte[] bytes = new byte[1024]; int len; while ((len = is.read(bytes)) != -1) { fos.write(bytes, 0, len); } //释放资源 fos.close(); is.close(); urlConnection.disconnect(); //断开连接 } }