引言:
当一台计算机需要与另一台计算机通信时,需要知道另一台计算机的地址。互联网协议(Internet Protocol,IP)可以用来唯一地标识互联网上的计算机。IP地址由四段用点隔开的0~255的十进制数组成。由于不容易记住这么多数字,所以,经常将他们映射为被称为域名(domain name)的有含义的名字,例如www.baidu.com。在互联网上有特殊的被称为域名服务器(Domain Name Server,DNS)的服务器,它把主机的名字转换成IP地址。当一台计算机要连接www.baidu.com时,他首先请求DNS将这个域名转换成IP地址,然后用这个IP地址来发送请求。
互联网协议是在互联网中从一台计算机向另一台计算机传输数据的一种底层协议,数据是以包的形式封装的。两个和IP一起使用的较高层的协议是传输控制协议(Transmission Control Protocol,TCP)和用户数据报协议(User Datagram Protocol,UDP)。TCP能够让两台主机交换连接并交换数据流。TCP确保数据的传送,也确保数据包以它们发送的顺序正确传送。UDP是一种用在IP之上的标准的、低开销的、无连接的、主机对主机的协议。UDP允许一台计算机上的应用程序向另一台计算机上的应用程序发送数据报。
Java支持基于流的通信(stream-based communication)和基于包的通信(packet-based communication)。基于流的通信使用传输控制协议(TCP)进行数据传输,而基于包的通信使用用户数据报协议(UDP)。因为TCP能够发现丢失的传输信息并重新发送,所以,传输过程是无损和可靠的。相对而言,UDP协议不能保证数据没有丢失。因此,大多数Java程序设计使用基于流的通信。
计算机网络:
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
网络编程的目的:
数据交换,通信
想要达到这个效果需要什么:
如何准确定位网络上的一台主机 通过IP地址 端口 定位到计算机上的某个资源
找到了主机,如何传输数据?
Javaweb与网络编程的区别:
Javaweb:网页编程 B/S 架构
网络编程:TCP/IP C/S架构
OSI(Open System Interconnect):即开放式系统互连,一般称为OSI参考模型。
TCP/IP(Transmission Control Protocol/Internet Protocol):即传输控制协议/网际协议,是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
OSI开放互联参考模型:
物理层:
物理层处于OSI的最底层,是整个开放系统的基础。物理层涉及通信信道上传输的原始比特流(bits),它的功能主要是为数据端设备提供传送数据的通路以及传输数据。
数据链路层:
数据链路层的主要任务是实现计算机网络中相邻节点之间的可靠传输,把原始的、有差错的物理传输线加上数据链路协议以后,构成逻辑上可靠的数据链路。需要完成的功能有链路管理、成帧、差错控制以及流量控制等。其中成帧是对物理层的原始比特流进行界定,数据链路层也能够对帧的丢失进行处理。
网络层:
网络层涉及源主机节点到目的主机节点之间可靠的网络传输,它需要完成的功能主要包括路由选择、网络寻址、流量控制、拥塞控制、网络互连等。
传输层:
传输层起着承上启下的作用,涉及源端节点到目的端节点之间可靠的信息传输。传输层需要解决跨越网络连接的建立和释放,对底层不可靠的网络,建立连接时需要三次握手,释放连接时需要四次挥手。
会话层:
会话层的主要功能是负责应用程序之间建立、维持和中断会话,同时也提供对设备和结点之间的会话控制,协调系统和服务之间的交流,并通过提供单工、半双工和全双工3种不同的通信方式,使系统和服务之间有序地进行通信。
表示层:
表示层关心所传输数据信息的格式定义,其主要功能是把应用层提供的信息变换为能够共同理解的形式,提供字符代码、数据格式、控制信息格式、加密等的统一表示。
应用层:
应用层为OSI的最高层,是直接为应用进程提供服务的。其作用是在实现多个系统应用进程相互通信的同时,完成一系列业务处理所需的服务。
TCP/IP:
数据链路层:
网络接口层TCP/IP模型的最底层是网络接口层,也被称为网络访问层,它包括了可使用TCP/IP与物理网络进行通信的协议,且对应着OSI的物理层和数据链路层。TCP/IP标准并没有定义具体的网络接口协议,而是旨在提供灵活性,以适应各种网络类型,如LAN、MAN和WAN。这也说明,TCP/IP协议可以运行在任何网络上。
网络层:
网际层是在Internet标准中正式定义的第一层。网际层所执行的主要功能是处理来自传输层的分组,将分组形成数据包(IP数据包),并为该数据包在不同的网络之间进行路径选择,最终将数据包从源主机发送到目的主机。在网际层中,最常用的协议是网际协议IP,其他一些协议用来协助IP的操作。
传输层:
传输层传输层也被称为主机至主机层,与OSI的传输层类似,它主要负责主机到主机之间的端对端可靠通信,该层使用了2种协议来支持2种数据的传送方法,它们是TCP协议和UDP协议。
应用层:应用层在TCP/IP模型中,应用程序接口是最高层,它与OSI模型中高3层的任务相同,都是用于提供网络服务,如文件传输、远程登录、域名服务和简单网络管理等。
两者的对比:
OSI七层网络模型 | TCP/IP四层概念模型 | 对应网络协议 |
应用层(Application) | 应用层 | HTTP、TFTP、NFS、WAIS、SMTP |
表示层(Presentation) | Telnet、Rlogin、SNMP、Gopher | |
会话层(Session) | SMTP、DNS | |
传输层(Transport) | 传输层 | TCP、UDP |
网络层(Network) | 网络层 | IP、ICMP、ARP、RARP、AKP、UUCP |
数据链路层(Data Link) | 数据链路层 | FDDI、Ethernet、Arpanet、PDN、SLIP、PPP |
物理层(Physical) | IEEE 802.1A、IEEE802.2到IEEE 802.11 |
互联网协议地址,一个IP地址唯一定位到一台网络设备
127.0.0.1:本机IP(localhost)
IP地址分类
IP地址分类—IPv4/IPv6
IPv4: 127.0.0.1 ,4个字节组成,每个字节0~255,42亿:30亿在北美,4亿在亚洲,在2011年用尽。
IPv6: 2409:893c:2710:39aa:59ca:ded2:714a:6636 ,128位,8个无符号整数
公网(互联网使用)-私网(局域网)
ABCD类地址
A类:IP地址范围1.0.0.1~127.255.255.254
B类:IP地址范围128.0.0.1~191.255.255.254
C类:IP地址范围192.0.0.1~223.255.255.254
D类:IP地址范围224.0.0.1~239.255.255.255
E类:IP地址范围240.0.0.1~255.255.255.254
一般来说,A类地址保留给政府机构,B类地址分配给中等规模的公司,C类地址分配给任何需要的人,D类用于组播,E类用于实验,各类可容纳的地址数目不同
IP地址划分大概依据是通过不断二分获得
192.168.xx.xx 专门给组织内部使用的局域网
域名:记忆IP问题
IP
DNS:域名系统,是互联网的一项服务,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。(访问网络资源时使用IP地址不够方便,故有了DNS来将IP地址和域名联系起来)
此类表示互联网协议 (IP) 地址。
使用示例:
package com.test.netTest; import java.net.InetAddress; import java.net.UnknownHostException; /* * 测试IP * */ public class InetAddressTest { public static void main(String[] args) { try { //查询本机地址 //1. InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1"); System.out.println(inetAddress1); //2. InetAddress inetAddress3 = InetAddress.getByName("localhost"); System.out.println(inetAddress3); //3. InetAddress inetAddress4 = InetAddress.getLocalHost(); System.out.println(inetAddress4); //查询网站IP地址 InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com"); System.out.println(inetAddress2); //常用方法 System.out.println(inetAddress2.getAddress()); System.out.println(inetAddress2.getCanonicalHostName());//获得规范名 System.out.println(inetAddress2.getHostAddress());//IP System.out.println(inetAddress2.getHostName());//域名或自己电脑的名字 } catch (UnknownHostException e) { e.printStackTrace(); } } }
执行结果:
此处端口专指协议端口,即端口表示计算机上的一个程序的进程
不同的进程有不同的端口号,用来区分软件,单个协议下端口号不能重复,不同协议可以重复
被规定 0~65535
TCP端口,UDP端口,每个都有0~65535个端口
端口分类
共有端口 0~1023
HTTP:80
HTTPS:443
FTP:21
Telnet:23
程序注册端口:1024~49151,分配给用户或程序
Tomcat :8080
MySQL:3306
Oracle:1521
动态端口(私有端口):49152~65535
#几个doc命令: netstat -ano #查看所有端口 netstat -ano|findstr "端口号" #查看指定的端口 tasklist|findstr "端口号" #根据端口号查看进程 Ctrl + shift + Esc #快速打开任务管理器
在计算机进行通信时由发送端主机的某端口发送信息到接收端主机的端口,如果接收端端口不匹配则无法接收
此类实现 IP 套接字地址(IP 地址 + 端口号)
示例:
package com.test.netTest; import java.net.InetSocketAddress; /* * 测试端口 * */ public class InetSocketAddressTest { public static void main(String[] args) { InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8080); System.out.println(inetSocketAddress); InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(inetSocketAddress2); System.out.println(inetSocketAddress.getAddress()); System.out.println(inetSocketAddress.getHostName());//host文件,地址 System.out.println(inetSocketAddress.getPort());//端口 } }
执行结果:
网络通信协议:速率,传输码率,代码结构,传输控制......
TCP/IP协议簇
重要(都在传输层):
TCP:用户传输协议(类似打电话)
UDP:用户数据报协议(类似发短信)
出名的协议:
TCP协议:用户传输协议
IP协议:网络互连协议
TCP UDP对比
TCP:打电话
连接,稳定
三次握手、四次挥手
三次挥手: A:请求连接 B:回应请求 A:确认收到回复 最少三次,保证稳定连接
四次挥手: A:请求断开 B:得知A断开请求 B:询问A是否确定断开 A:确定断开
客户端、服务端
传输完成,释放连接,效率低
UDP:发短信
不连接,不稳定
客户端、服务端:没有明确的界限
不管有没有准备好都可以发送
DDOS:洪水攻击!
打电话:需要连接
Socket类:
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
ServerSocket类:
此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
什么是套接字?
所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口
客户端
连接服务器 Socket
发送消息
package com.test.communicationTset; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; /* * 客户端 * */ public class TCPClientDome01 { public static void main(String[] args) { Socket socket = null; OutputStream os =null; try { //1.需要服务器的地址 端口号 InetAddress serverIP = InetAddress.getByName("127.0.0.1"); int port = 9999; //2.创建一个socket连接 socket = new Socket(serverIP,port); //3.发送消息 IO流 os = socket.getOutputStream(); os.write("qwddkxs".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(); } } } } }
服务器
建立服务端口 ServerSocket
等待用户的连接 accept
接受用户消息
package com.test.communicationTset; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /* * 服务端 * */ public class TCPServerDemo01 { public static void main(String[] args){ ServerSocket serverSocket =null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos =null; try { //1.服务器地址 serverSocket = new ServerSocket(9999); while (true){//使服务器一直处于等待状态 //2.等待客户端连接 socket = serverSocket.accept(); //3.读取客户端消息 is = socket.getInputStream(); //4.使用流 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(); } } } } }
执行结果:
服务器端
package com.test.communicationTset; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TCPServerDemo02 { public static void main(String[] args) throws Exception { //1.创建服务端 ServerSocket serverSocket = new ServerSocket(9000); //2.监听客户端连接 Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端连接 //3.获取输入流 InputStream is = socket.getInputStream(); //4.文件输出 FileOutputStream fos = new FileOutputStream(new File("receive.txt")); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer))!=-1){ fos.write(buffer,0,len); } //通知客户端接收完毕 OutputStream ops = socket.getOutputStream(); ops.write("服务器接收完毕,可以断开".getBytes()); //关闭资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
客户端
package com.test.communicationTset; import java.io.*; import java.net.InetAddress; import java.net.Socket; public class TCPClientDome02 { public static void main(String[] args) throws Exception { //1.创建一个Socket连接 Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000); //2.创建一个输出流 OutputStream os = socket.getOutputStream(); //3.读取文件 FileInputStream fis = new FileInputStream(new File("E:\\学习\\ps学习.txt")); //4.写出文件 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer))!=-1){ os.write(buffer,0,len); } //5.通知服务器传输完毕 socket.shutdownOutput();//传输完毕 //确定服务器接收完毕,才能断开连接 InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[1024]; int len2; while ((len2 = inputStream.read(buffer2))!=-1){ baos.write(buffer2,0,len2); } System.out.println(baos.toString()); //5.关闭资源 baos.close(); inputStream.close(); fis.close(); os.close(); socket.close(); } }
发短信:不需要连接,需要知道对方的地址
此类表示数据报包
此类表示用来发送和接收数据报包的套接字
发送端:
package com.test.UDPTest; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.nio.charset.StandardCharsets; /* * 不需要连接服务器 * */ public class UDPCilentDemo01 { public static void main(String[] args) throws Exception { //1.建立一个Socket DatagramSocket socket = new DatagramSocket(); //2.建立一个包 String msg = "哈喽啊"; //发送给谁 InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; //数据,数据的长度,要发送给谁, DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); //3.发送包 socket.send(packet); //4.关闭 socket.close(); } }
接收端:
package com.test.UDPTest; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /* * 服务器 * */ public class UDPServerDemo01 { //开放端口 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(); } }
运行结果:
实现单向聊天重复发送消息
发送端:
package com.test.UDPTest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class UDPUser01 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); //准备数据:控制台读取 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true) { String data = reader.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(); } }
接收端:
package com.test.UDPTest; import javax.print.DocFlavor; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPUser02 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); while (true) { //准备接收数据 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); socket.receive(packet);//阻塞式接受包裹 //断开连接 byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(receiveData.trim());//不加trim()会导致输入的内容后面还有1024数组剩下的空内容 if (receiveData.startsWith("bye")){ break; } } socket.close(); } }
执行结果:
实现双向聊天重复发送消息
发送类:
package com.test.UDPTest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; /* * 发送类 * */ public class TalkSend01 implements Runnable{ DatagramSocket socket = null; BufferedReader reader = null; private int fromPort; private String toIP; private int toPort; public TalkSend01(int fromPort, String toIP, int toPort) { this.fromPort = fromPort; this.toIP = toIP; this.toPort = toPort; try { socket = new DatagramSocket(fromPort); reader = new BufferedReader(new InputStreamReader(System.in)); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true) { try { String data = reader.readLine(); byte[] datas = data.getBytes(); DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toIP,this.toPort)); socket.send(packet); if (data.equals("bye")){ break; } }catch (Exception e){ e.printStackTrace(); } } socket.close(); } }
接收类:
package com.test.UDPTest; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /* * 接收类 * */ public class TalkReceive01 implements Runnable{ DatagramSocket socket = null; private int port; private String msgFrom; public TalkReceive01(int port, String msgFrom) { this.port = port; this.msgFrom = msgFrom; try { socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true) { try { //准备接收数据 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); socket.receive(packet);//阻塞式接受包裹 //断开连接 byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(msgFrom+":"+receiveData.trim());//不加trim()会导致输入的内容后面还有1024数组剩下的空内容 if (receiveData.startsWith("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
两个使用者
package com.test.UDPTest; public class TalkStudent { public static void main(String[] args) { //开启两个线程 new Thread(new TalkSend01(7777,"localhost",9999)).start(); new Thread(new TalkReceive01(8888,"老师")).start(); } }
package com.test.UDPTest; public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend01(5555,"localhost",8888)).start(); new Thread(new TalkReceive01(9999,"学生")).start(); } }
运行结果:
统一资源定位系统(uniform resource locator;URL)
由五部分组成:协议://IP地址:端口号/项目名/资源
URL类代表一个统一资源定位符,它是指向互联网“资源”的指针。
示例:
package com.test.URLTest; import java.net.MalformedURLException; import java.net.URL; public class URLTest01 { public static void main(String[] args) throws MalformedURLException { URL url = new URL("http://localhost:8080/helloword/index.jsp?username=qwddkxs&password=123"); System.out.println(url.getProtocol());//协议名 System.out.println(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.test.URLTest; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; public class URLDown { public static void main(String[] args) throws Exception{ //1.下载地址 URL url = new URL("http://localhost:8080//qwddkxs/ConfidentialDocuments.txt"); //2.连接到资源 HTTP HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream inputStream = urlConnection.getInputStream(); FileOutputStream fos = new FileOutputStream("qwddkxsFile.txt"); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer))!=-1){ fos.write(buffer,0,len); } fos.close(); inputStream.close(); urlConnection.disconnect();//断开连接 } }
运行结果:
初识Tomcat
服务器
自定义 S
Tomcat服务器 S :java后台开发
客户端
自定义 C
浏览器 B