一、基础
-
计算机网络:计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
-
网络通信的要素:
-
通信双方的地址:IP和端口号
-
网络通信协议:OSI参考模型 和 TCP/IP参考模型(协议)
-
二、IP
获取IP地址:InetAddress类
-
唯一定位一台网络上的计算机
-
127.0.0.1:指代本机(localhost)
-
IP地址的分类:
-
IPV4/IPV6:
IPV4:例如127.0.0.1:由4个字节组成,每个字节0~255,总计约42亿个,2011年就用尽了
IPV6:例如fe80::d8e8:3f1a:5ab0:8904%7:128位,8个无符号整数
-
公网(互联网)/私网(局域网)
ABCD类IP地址
192.168.XXX.XXX:专门给组织内部使用的
-
package com.bravo.demo.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInetAddress {
public static void main(String[] args) {
try {
//查询本机地址
InetAddress address1 = InetAddress.getByName("127.0.0.1");
InetAddress address2 = InetAddress.getByName("localhost");
InetAddress address3 = InetAddress.getLocalHost();
System.out.println("address1:"+address1);
System.out.println("address2:"+address2);
System.out.println("address3:"+address3);
//查询网站地址
InetAddress address4 = InetAddress.getByName("www.baidu.com");
System.out.println("address4:"+address4);
//常用方法
System.out.println("---------------------------");
System.out.println(address4.getAddress());
System.out.println(address4.getCanonicalHostName());//获取规范的名字
System.out.println(address4.getHostAddress());//获取IP
System.out.println(address4.getHostName());//获取域名或者本机名称
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
控制台输出结果:
address1:/127.0.0.1
address2:localhost/127.0.0.1
address3:LAPTOP-NIVLBH1R/192.168.0.7
address4:www.baidu.com/110.242.68.3
---------------------------
[B@7530d0a
110.242.68.3
110.242.68.3
www.baidu.com
三、端口
端口是指计算机上一个程序的进程:
-
不同的进程有不同的端口号,用来区分软件
-
端口号只有整数,范围为0~65535
-
按对应的协议类型,端口有TCP端口和UDP端口两种。由于TCP协议和UDP协议是相互独立的,因此各自的端口号也相互独立,比如TCP有80端口,UDP也可以有80端口,两者并不冲突。
-
端口分类:
-
公有端口:0~1023
比如:HTTP默认端口:80
HTTPS默认端口:443
FTP默认端口:21
SSH默认端口:22
等等。
-
程序注册端口:1024~49151,分配给用户或者程序
比如:MYSQL默认端口:3306
Redis默认端口:6379
Tomcat默认端口:8080
Nginx默认端口:8888
Oracle默认端口:1521
等等。
-
动态(私有)端口:49152~65535
-
-
常见的DOS命令:
- 查看所有端口命令:netstat -ano
- 查看指定的端口:netstat -ano|findstr “XXX” (XXX代表端口号)
- 查看指定端口的进程:tasklist|findstr “XXX” (XXX代表端口号)
package com.bravo.demo.network;
import java.net.InetSocketAddress;
public class TestInetSocketAddress {
public static void main(String[] args) {
InetSocketAddress address1 = new InetSocketAddress("127.0.0.1", 8080);
InetSocketAddress address2 = new InetSocketAddress("localhost", 8080);
System.out.println("address1:"+address1);
System.out.println("address2:"+address2);
System.out.println(address2.getHostName());
System.out.println(address2.getHostString());
System.out.println(address2.getPort());
}
}
控制台输出结果:
address1:/127.0.0.1:8080
address2:localhost/127.0.0.1:8080
localhost
localhost
8080
四、通信协议
TCP/IP协议是网络相关各类协议簇的总称,包括TCP,UDP,IP,FTP,HTTP,ICMP,SMTP等
TCP:用户传输协议
UDP:用户数据报协议
IP:网络互联协议
- TCP和UDP对比:
区别点 | TCP | UDP |
---|---|---|
是否连接 | 面向连接 | 无连接 |
是否可靠 | 可靠传输,使用流量控制和拥塞控制 | 不可靠传输,不使用流量控制和拥塞控制 |
连接对象个数 | 只能是一对一通信 | 支持一对一,一对多,多对一和多对多交互通信 |
传输方式 | 面向字节流 | 面向报文 |
首部开销 | 首部最小20字节,最大60字节 | 首部开销小,仅8字节 |
适用场景 | 适用于要求可靠传输的应用,例如文件传输 | 适用于实时应用(IP电话、视频会议、直播等) |
TCP可理解为打电话(需要双方连接),UDP可理解为发短信(只需要一方发送,对方是否接受成功不知道)
-
TCP三次握手(比喻):
客户端:我准备建立连接了 服务端:知道了 客户端:好的
-
TCP四次挥手(比喻):
客户端:我准备断开连接了 服务端:知道了,还没处理完先等一下 服务端:我处理好了,可以断开连接 服务端:好的
五、TCP实现会话
客户端:1. 连接服务端Socket;2. 发送消息
package com.bravo.demo.network;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* 客户端
*/
public class TcpClientDemo1 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
try {
//需要知道服务端地址(IP)
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
//端口号
int port=9999;
//创建一个socket连接
socket = new Socket(serverIP,port);
//发送消息,IO流
os = socket.getOutputStream();
os.write("Hello,world!".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. 接受客户端消息
package com.bravo.demo.network;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
*/
public class TcpServerDemo1 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//需要有一个自己的地址(IP)
serverSocket = new ServerSocket(9999);
//等待客户端连接
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();
}
}
}
}
}
先启动服务端,再启动客户端,服务端就会收到一条“Hello,world!”的消息
六、TCP实现文件传输
- 客户端:
package com.bravo.demo.network;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
* 客户端
*/
public class TcpClientDemo2 {
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("1.jpg"));//1.jpg为在项目根目录下的图片文件
//4.写出文件
byte[] buffer = new byte[1024];
int len;
while((len=fis.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务端,已经传输完毕
socket.shutdownOutput();
//确定服务端接受完毕才能断开连接
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[2014];
int len2;
while((len2=is.read(buffer2))!=-1){
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
//5.关闭资源
fis.close();
os.close();
socket.close();
}
}
- 服务端
package com.bravo.demo.network;
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 TcpServerDemo2 {
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.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//通知客户端接受完毕
OutputStream os = socket.getOutputStream();
os.write("服务端接受完毕了,客户端可以断开连接了".getBytes());
//关闭资源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
先启动服务端,再启动客户端,客户端会输出“服务端接受完毕了,客户端可以断开连接了”,项目根目录出现一张名为receive.jpg的图片
七、UDP发送消息
-
发送端:
package com.bravo.demo.network; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /** * UDP发送端 */ public class UdpClientDemo1 { 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构造参数分别代表发送的数据、数据起始、终止、接受IP、接受端口 DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); //3.发送包 socket.send(packet); //4.关闭资源 socket.close(); } }
-
接收端:
package com.bravo.demo.network; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * UDP接收端 */ public class UdpServerDemo1 { public static void main(String[] args) throws Exception{ //1.开放端口 DatagramSocket socket = new DatagramSocket(9090); //2.接受数据包 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())); //3.关闭连接 socket.close(); } }
UDP不需要在发送端和接收端直接建立连接
八、UDP循环发送消息
-
发送端
package com.bravo.demo.network; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /** * 发送端 */ public class UdpSendDemo1 { 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, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发送“bye”时终止程序 if("bye".equals(data)){ break; } } socket.close(); } }
-
接收端
package com.bravo.demo.network; import java.net.DatagramPacket; import java.net.DatagramSocket; /** * 接收端 */ public class UdpReceiveDemo1 { public static void main(String[] args) throws Exception{ DatagramSocket socket = new DatagramSocket(6666); while(true){ byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length); socket.receive(packet);//阻塞式接收包裹 byte[] data = packet.getData(); String receiveData=new String(data,0,data.length); System.out.println("收到发送端消息:"+receiveData); //接收“bye”时终止程序 if("bye".equals(receiveData.trim())){ break; } } socket.close(); } }
九、UDP多线程相互发送消息
-
发送端线程
package com.bravo.demo.network; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; /** * 发送端 */ public class TalkSend implements Runnable{ DatagramSocket socket = null; BufferedReader reader = null; private int fromPort; private String toIP; private int toPort; public TalkSend(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, InetAddress.getByName(this.toIP), this.toPort); socket.send(packet); if("bye".equals(data)){ break; } } catch (Exception e) { e.printStackTrace(); } } socket.close(); } }
-
接收端线程
package com.bravo.demo.network; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; /** * 接收端 */ public class TalkReceive implements Runnable{ DatagramSocket socket = null; private int port; private String msgFrom; public TalkReceive(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[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length); socket.receive(packet);//阻塞式接收包裹 byte[] data = packet.getData(); String receiveData=new String(data,0,data.length); System.out.println(msgFrom+":"+receiveData); if("bye".equals(receiveData.trim())){ break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
-
开启两个线程
package com.bravo.demo.network; public class TalkStudent { public static void main(String[] args) { //开启两个线程 new Thread(new TalkSend(7777,"localhost",9999)).start(); new Thread(new TalkReceive(8888,"老师")).start(); } }
package com.bravo.demo.network; public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend(5555,"localhost",8888)).start(); new Thread(new TalkReceive(9999,"学生")).start(); } }
十、URL
URL(统一资源定位符):定位互联网上的某一个资源
URL常见格式:协议名://IP地址:端口号/项目名/资源
DNS域名解析:将域名解析为IP地址
- URL类:
package com.bravo.demo.network;
import java.net.MalformedURLException;
import java.net.URL;
public class URLDemo1 {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=admin&password=111111");
System.out.println(url.getProtocol());//获取此 URL的协议名称
System.out.println(url.getHost());//获取此 URL的主机名
System.out.println(url.getPort());//获取此 URL的端口号
System.out.println(url.getPath());//获取此 URL的路径部分
System.out.println(url.getFile());//获取此 URL的文件名
System.out.println(url.getQuery());//获取此 URL的查询部分
}
}
输出结果:
http
localhost
8080
/helloworld/index.jsp
/helloworld/index.jsp?username=admin&password=111111
username=admin&password=111111
- URL建立连接,获取资源:
package com.bravo.demo.network;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class URLDemo2 {
public static void main(String[] args) throws Exception {
URL url = new URL("http://music.163.com/song/media/outer/url?id=853708.mp3");
URLConnection connection = url.openConnection();
InputStream is = connection.getInputStream();
FileOutputStream fos =new FileOutputStream("download.mp3");
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,buffer.length);
}
System.out.println("下载资源成功!");
}
}