目录
2.InetAddress和InetSocketAddress的区别
一、概述
1.计算机网络
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
2. 网络编程目的
网络编程就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
3. 想要达到数据交换需要什么
- 如何准确的定位网络上的一台主机 ?(通过ip地址、端口、定位到这个计算机上的某个资源)
- 找到了这个主机,如何传输数据?
打电话 TCP
发短信是 UDP
区别:
javaweb: 网页编程 B/S结构 ( 即Browser/Server(浏览器/服务器)结构)
网络编程:TCP/IP C/S结构 (即Client/Server客户机/服务器结构)
二、网络通信的要素
1.如何实现网络的通信?
需要通信双方的地址,即IP地址,端口号(IP+端口号,可以定位到某台电脑的具体的一个应用)
通信双方的地址:
- IP(定位到某台电脑)
- 端口(定位到某个应用)
规则:网络通信的协议
OSI七层协议是一个理想化的协议模型,实际应用的是TCP/IP模型。
TCP/IP参考模型:
小结:
1. 网络编程中的两个主要问题:
如何准确的定位到网络上的一台或者多台主机?
在命令提示符下输入 ping www.baidu.com(ping+域名),返回其IP地址
2.找到主机之后如何进行通信?
网络编程中的要素:
- IP和端口号 IP
- 网络通信协议 UDP、TCP
Java中是万物皆对象:
- 在java中一定存在与网络通信相关的类
- 没有的类需要自己进行相关的定义
三、IP
JAVA下InetAddress类,是表示Internet协议(IP)地址。
IP地址是由IP使用的32位或128位无符号数字,构建UDP和TCP协议的低级协议。 InetAddress的一个实例由一个IP地址和可能的相应主机名组成(取决于它是用主机名构造还是已经完成了反向主机名解析)。
java.net包下的都是和网络有关的。
方法:
ip地址:inteAddress 查看本地ip cmd ipconfig
- 唯一定位一台网络上计算机
- 127.0.0.1:本机localhost
按ip地址的分类:
- ipv4,例如127.0.0.1 ,有4个字节。 0~255 ,共42亿个,2011年用尽了。
- Ipv6,fe80::60f8:dddd:6bea:17a7%5 ,128位。8个无符号整数!
- fe80:8c7b:6835:9b74:e315:1234:233e:56a3 这是一个完整的ipv6地址。
查看本地ip:命令行下输入 ipconfig
公网(互联网)和私网(局域网)
- ABCD类地址(查资料,阿里笔试)
- 192.168.xx.xx,局域网,专门给组织内部使用
域名:IP地址不容易记忆,因此使用域名比较好记忆。
IP:www.jd.com(IP地址要自行购买)
代码练习:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInetAddress {
/*psvm public static void main(String[] args)
sout System.out.println();
没有构造器就不能new,只能通过静态方法返回来
自动补全变量名称 : Ctrl + Alt + v
自动补全属性名称 : Ctrl + Alt + f
变量.sout( System.out.println(变量);)
*/
//测试IP
public static void main(String[] args) {
try {
//查询本机地址
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");//自己主机的名字
System.out.println(inetAddress1);///127.0.0.1
InetAddress inetAddress3 = InetAddress.getByName("localhost");
System.out.println(inetAddress3);//localhost/127.0.0.1
InetAddress inetAddress4 = InetAddress.getLocalHost();
System.out.println(inetAddress4);//LAPTOP-FNEHNFQF/192.168.8.152
//查询网址ip地址
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);//www.baidu.com/36.152.44.95
System.out.println(inetAddress2.getCanonicalHostName());//36.152.44.95
System.out.println(inetAddress2.getHostName());//www.baidu.com
System.out.println(inetAddress2.getHostAddress());//36.152.44.95
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
四、端口
1.概述
端口表示计算机上的一个程序的进程
不同得端口用来区分不同的软件
规定端口的范围:0~65535
TCP和UDP分别占有65535个,即电脑端口总数为65535*2
端口分类
公有端口 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 “端口号” //查看指定的端口号
tasklist|findstr "端口号" //查看指定端口号的进程
演示:
代码练习:
import java.net.InetSocketAddress;
public class TestInetstockAddress {
public static void main(String[] args) {
InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080);
System.out.println(inetSocketAddress1);///127.0.0.1:8080
System.out.println(inetSocketAddress2);//localhost/127.0.0.1:8080
System.out.println(inetSocketAddress1.getHostName());//127.0.0.1
System.out.println(inetSocketAddress1.getPort());//8080
System.out.println(inetSocketAddress1.getAddress());//127.0.0.1/127.0.0.1
}
}
2.InetAddress和InetSocketAddress的区别
InetAddress 类
封装计算机的 IP 地址,不包含端口号
InetAddress 类常用的方法
1. String getHostAddress() 获得 IP 地址
2. String getHostName() 获得主机名
3. static InetAddress getByName(String host) 根据主机名获得 IP 地址
InetSocketAddress 类
此类用于实现 IP 套接字地址 (IP 地址+端口号),用于socket 通信
InetSocketAddress 类常用的方法
1. InetAddress getAddress() 获取 InetAddress 对象
2. int getPort() 获取端口号
3. String getHostName() 获取主机名
套接字Socket=(IP地址:端口号)
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
五、通信协议
网络通信协议:速率、传输码率、代码结构、传输控制等方面的协议
1. TCP/IP协议
TCP/IP协议簇:TCP/IP(传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
重要的三个:
- TCP:用户传输协议
- UDP:用户数据报协议
- IP:网络互连协议
2.TCP与UDP的对比
TCP与UDP的对比:
TCP:例如打电话
- 连接稳定
- 三次握手、四次挥手
- 客户端、服务器
- 传输完成、释放连接、效率低
UDP:例如发短信
- 不连接、不稳定
- 客户端、服务器:没有明确的界限
- 不管有没有准备好,都可以发送给你
- DDOS:洪水攻击(发送大量的信息,堵塞端口,饱和攻击)
3.三次握手、四次挥手
建立TCP需要三次握手才能建立,而断开连接则需要四次握手。
举例:
//三次握手,最少需要三次,保证稳定连接!<连接>
A:你瞅啥?
B:瞅你咋地?
A:干一场
//四次挥手 <断开>
A:我要下班了,东西给你收到了吗?(断开)
B:收到了
B:我也要下班了(我也要断开啦)
A:再见
四次挥手:由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这好比,我们打电话(全双工),正常的情况下(出于礼貌),通话的双方都要说再见后才能挂电话,保证通信双方都把话说完了才挂电话。
六、TCP
1.TCP报文格式
TCP报文内部包含了哪些东西?
TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。TCP在发送数据前必须在彼此间建立连接,这里连接意思是:双方需要内保存对方信息(例如:IP,Port…)
报文主要段的意思
序号:表示发送的数据字节流,确保TCP传输有序,对每个字节编号。
确认序号:发送方期待接收的下一序列号,接收成功后的数据字节序列号加 1。只有ACK=1时才有效。
ACK:确认序号的标志,ACK=1表示确认号有效,ACK=0表示报文不含确认序号信息
SYN:连接请求序号标志,用于建立连接,SYN=1表示请求连接
FIN:结束标志,用于释放连接,为1表示关闭本方数据流
2.文件传输代码
客户端代码:
package TCP;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//客户端
public class TestClientDemo1 {
public static void main(String[] args) {
//1.要知道服务器的IP、端口号
Socket socket = null;
OutputStream os = null;
try {
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("欢迎欢迎!".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();
}
}
}
}
}
服务端代码:
package TCP;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务器端
public class TestServerDemo1 {
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();//与客户端的2.创建的socker相同
//3.读取客户端的消息
is = socket.getInputStream();
//4.管道流
baos = new ByteArrayOutputStream();//字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。
//定义一个字节数组,相当于缓存
byte[] buffer = new byte[1024];
int len;
while((len =is.read(buffer))!=-1){把is里的东西读到buffer数组里去
baos.write(buffer,0,len);//将指定的字节写入此字节数组输出流。
}
System.out.println(baos.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
//一定要关闭数据流。并且关闭流必须放在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();
}
}
}
}
}
先运行服务端,再运行客户端。(客户端运行两次,就会收到两次)
运行结果:
文字传输步骤:
客户端:
- 连接服务器 (Socket)
- 发送消息
服务器端:
- 建立服务器的端口号 ServerSocket
- 等待用户的链接 accept
- 接受用户的信息
3.文件上传代码
客户端:
package TCP;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TestClientDemo2 {
public static void main(String[] args) {
Socket socket=null;
OutputStream os=null;
FileInputStream fis=null;
InputStream inputStream= null;
ByteArrayOutputStream baos= null;
try {
//1.创建一个socket连接
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//2.创建一个输出流
os = socket.getOutputStream();
//3.读取文件
fis = new FileInputStream(new File("d:\\Users\\lenovo\\Pictures\\Saved Pictures\\1.jpg"));
//4.写出文件
byte[] buffer= new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器传输完成
socket.shutdownOutput();//我已经传输完了
//确认服务器接收完毕,才能够断开连接
inputStream = socket.getInputStream();//socket.getInputStream()服务器上取入数据
//String byte[]
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());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (baos != null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务器端:
package TCP;
import com.sun.security.ntlm.Server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServerDemo2 {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket=null;
InputStream is=null;
FileOutputStream fos=null;
OutputStream os=null;
try {
//1.创建服务
serverSocket = new ServerSocket(9999);
//2.监听客户端连接
socket = serverSocket.accept();
//3.获取输入流
is = socket.getInputStream();
//4.文件输出
fos = new FileOutputStream(new File("lala.jpg"));
byte[] buffer= new byte[1024];
int len;
while((len= is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//通知客户端接收完成
os = socket.getOutputStream();//向客户端传出数据
os.write("接收完毕".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.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();
}
}
}
}
}
先运行服务器端,再运行客户端
命令行输出“接收完毕”,同时目录下多了lala.jpg文件:
总结:
客户端:
1.创建socker连接
2.创建输出流
3.读取文件
4.写出文件
5.通知服务器传输完成。
6.确认服务器接收完毕后,断开连接。
7.关闭资源
服务器端
1.创建服务
2.监听客户端消息
3.获取输入流
4.文件输出
5.通知客户端接收完成
6.关闭资源
4.Tomcat
服务端:
- 自定义 S
- Tomcat服务器 S
客户端:
- 自定义 C
- 浏览器 B
七、UDP
UDP没有服务器和客户端得概念,只有发送端和接收端的概念。
使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。
虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。
1.简单发送消息
发送端
package UDP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class TestSendDemo3 {
public static void main(String[] args) throws Exception {
//1.建立一个socket
DatagramSocket socket = new DatagramSocket();
// 2.建个包
InetAddress name = InetAddress.getByName("localhost");
String message = "hello,中国";
int port= 9999;
DatagramPacket packet = new DatagramPacket(message.getBytes(),0,message.getBytes().length,name,port);
//3.发送包
socket.send(packet);
//4.关闭包
socket.close();
}
}
接收端:
package UDP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestReceiveDemo3 {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9999);
//接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(packet.getAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
socket.close();
}
}
运行结果:
实际开发中,建议使用try...catch解决异常,而不是直接抛出异常
2.循环发送消息
发送端:
package UDP;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class TestSendDemo4 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9998);
while (true){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String string = reader.readLine();
byte[] data = string.getBytes();
DatagramPacket packet = new DatagramPacket(data,0,data.length, InetAddress.getByName("localhost"),9999);
socket.send(packet);
if (string.equals("bye")){
break;
}
}
socket.close();
}
}
接收端:
package UDP;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
public class TestReceiveDemo4 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9999);
while (true){
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
byte[] data = packet.getData();
String s = new String(data, 0, data.length);
System.out.println(s);
if (s.equals("bye")){
break;
}
}
socket.close();
}
}
运行结果:
从命令行读取输入
3. 利用多线程实现聊天
双方均可接受、发送消息。
发送方代码:
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :发送消息代码
**/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class TalkSend implements Runnable {
private DatagramSocket socket = null;
private BufferedReader reader = null;
private int port;
private int toPort;
private String toIp;
public TalkSend(int port, int toPort, String toIp) {
this.port = port;
this.toPort = toPort;
this.toIp = toIp;
try {
socket = new DatagramSocket(port);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
String s = reader.readLine();
byte[] data = s.getBytes();
DatagramPacket packet = new DatagramPacket(data, 0, data.length,
new InetSocketAddress(this.toIp, this.toPort));
socket.send(packet);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
接收方代码:
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :接收消息代码
**/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TalkReceive implements Runnable{
private DatagramSocket socket =null;
private int port;
private String mesFrom;
public TalkReceive(int port, String mesFrom) {
this.port = port;
this.mesFrom = mesFrom;
try {
socket= new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
byte[] data =packet.getData();
String s = new String(data,0,data.length);
System.out.println(mesFrom+" : "+s);
if (s.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
学生端:
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :学生端
**/
public class TalkStudent {
// 开启两个线程 学生7777发 8888收 哪个端口消息不重要,但是收的地址要是老师的收的地址
//来自端口9999的老师消息
public static void main(String[] args) {
new Thread(new TalkSend(7777,8888,"localhost")).start();//学生7777发 老师在8888端口收
new Thread(new TalkReceive(9999,"老师")).start();//老师的消息,学生在端口9999收
}
}
老师端
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :老师端
**/
public class TalkTeacher {
public static void main(String[] args) {
//老师从6666端口发消息至学生收消息的端口号9999
//老师接收学生消息的端口为8888
new Thread(new TalkSend(6666,9999,"localhost")).start();
new Thread(new TalkReceive(8888,"学生")).start();//老师接收学生消息的端口为8888
}
}
运行结果:
八、URL
1.URL
统一资源定位符(URL):用于定位互联网上某一个资源。是专为标识Internet网上资源位置而设置的一种编址方式,网址就是一种URL。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
基本URL包含模式(或称协议)、服务器名称(或IP地址)、路径和文件名,例如;"协议://授权/路径?查询"。
2.DNS
域名解析:即将域名(www.baidu.com)解析为IP地址的过程。在Internet上域名与IP地址之间是一一对应的,域名虽然便于人们记忆,但机器之间只能互相认识IP地址,它们之间的转换工作称为域名解析,域名解析需要由专门的域名解析服务器来完成,DNS就是进行域名解析的服务器 。
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :
**/
import java.net.MalformedURLException;
import java.net.URL;
public class TestURL {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/mobian/index.jsp?username=mobian&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());//参数列表
}
}
利用url路径下载网络资源测试代码:
package UDP;
/**
* @author : lkw
* @data : 2021/2/28
* @description :
**/
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class TestDownURL {
public static void main(String[] args) throws IOException {
//1、请求下载的地址
URL url = new URL("https://m701.music.126.net/20210228212436/be5a305c2154d51c5b272bdf7920ed09/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/7616317511/792d/7ba6/afcc/13818e3843e9d544f9127f762e7ae3cb.m4a");
//2、连接到这个资源HTTP
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("萱草花.m4a");
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer))!=-1){
fos.write(buffer,0,len);
}
fos.close();
inputStream.close();
urlConnection.disconnect();
}
}