要想实现网络通信,需要解决的三个问题:
-
问题1:如何准确确定定位网络上一台或多台主机
-
问题2:如何定位主机上的特定的应用
-
问题3:找到主机后,如何可靠、高效地进行数据传输
实现网络传输的三个要素:(对应解决三个问题)
> 使用IP地址(准确确定定位网络上一台或多台主机)
> 使用端口号(定位主机上的特定的应用)
> 规范网络通信协议(可靠、高效地进行数据传输)
通信要素1:IP地址
IP地址用来给网络中的一台计算机设备做唯一的编号
IP地址分类
> IP地址分类方式1
IPv4(占用4个字节)
IPv6(占用16个字节)
> IP地址分类方式2
公网地址(万维网使用)和 私有地址(局域网使用。以192.168开头)
本地回路地址
127.0.0.1(回环自检)
域名
便捷的记录ip地址,ip地址与域名一一对应
www.baidu.com www.atguigu.com www.bilibili.com
www.jd.com www.mi.com www.vip.com
端口号
> 可以唯一标识主机中的进程(应用程序)
> 不同的进程分配不同的端口号
> 范围:0~65535(两个字节)
通信协议
网络通信协议的目的
为了实现可靠而高效的数据传输。
网络参考模型
OSI参考模型:将网络分为7层,过于理想化,没有实施起来。
TCP/IP参考模型:将网络分为4层:应用层、传输层、网络层、物理+数据链路层。事实上使用的标准。

TCP: 可靠的连接(发送数据前,需要三次握手、四次挥手),进行大数据量的传输,效率低。
UDP: 不可靠的连接(发送前,不需要确认对方是否在)、使用数据报传输(限制在64kb以内)、效率高。
InetAddress的使用
作用
InetAddress类的一个实例就代表一个具体的ip地址。
实例化方式
InetAddress getByName(String host):获取指定ip对应的InetAddress的实例
InetAddress getLocalHost():获取本地ip对应的InetAddress的实例
常用方法
getHostName():获取域名,如果没有就获取ip地址
getHostAddress():获取ip地址
TCP
java
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Main {
public static void main(String[] args) {
try {
//1. 实例化
//getByName(String host): 获取指定ip对应的InetAddress的实例
InetAddress inet1 = InetAddress.getByName("192.168.23.31");
System.out.println(inet1);
InetAddress inet2 = InetAddress.getByName("www.atguigu.com");
System.out.println(inet2); //www.atguigu.com/122.228.95.175
//getLocalHost(): 获取本地ip对应的InetAddress的实例
InetAddress inet3 = InetAddress.getLocalHost();
System.out.println(inet3); //DESKTOP-QCP2QPI/192.168.21.107
InetAddress inet4 = InetAddress.getByName("127.0.0.1");
System.out.println(inet4);
//2. 两个常用的方法
System.out.println(inet1.getHostName()); //192.168.23.31
System.out.println(inet1.getHostAddress()); //192.168.23.31
System.out.println(inet2.getHostName()); //www.atguigu.com
System.out.println(inet2.getHostAddress()); //122.228.95.175
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
UDP
java
public void sender() throws Exception {
//1. 创建DatagramSocket的实例
DatagramSocket ds = new DatagramSocket();
//2. 将数据、目的地的ip、目的地的端口号都封装在DatagramPacket数据报中
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port = 9090;
byte[] bytes = "我是发送端".getBytes("utf-8");
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, inetAddress, port);
//3. 发送数据
ds.send(packet);
ds.close();
}
public void receiver() throws Exception {
//1. 创建DatagramSocket的实例
int port = 9090;
DatagramSocket ds = new DatagramSocket(port);
//2. 创建数据报的对象,用于接收发送端发送过来的数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//3. 接收数据
ds.receive(packet);
//4. 获取数据,并打印到控制台上
String str = new String(packet.getData(), 0, packet.getLength());
System.out.println(str);
ds.close();
}
URL(Uniform Resource Locator)
统一资源定位符 (种子)
作用
一个具体的url就对应着互联网上某一资源的地址。
URL的格式:
http://192.168.21.107:8080/example/abcd.jpg?name=Tom ---> "万事万物皆对象"
应用层协议 ip地址 端口号 资源地址 参数列表
URL类的实例化及常用方法
-
public String getProtocol() 获取该URL的协议名
-
public String getHost() 获取该URL的主机名
-
public String getPort() 获取该URL的端口号
-
public String getPath() 获取该URL的文件路径
-
public String getFile() 获取该URL的文件名
-
public String getQuery() 获取该URL的查询名
java
import java.net.URL;
public class Main {
public static void main(String[] args) {
String str = "http://192.168.21.107:8080/examples/abcd.jpg?name=Tom";
try {
URL url = new URL(str);
/*
* - public String getProtocol() 获取该URL的协议名
- public String getHost() 获取该URL的主机名
- public String getPort() 获取该URL的端口号
- public String getPath() 获取该URL的文件路径
- public String getFile() 获取该URL的文件名
- public String getQuery() 获取该URL的查询名
*/
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort());
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getQuery());
} catch (Exception e) {
e.printStackTrace();
}
}
}
下载指定的URL的资源到本地
java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String[] args) throws IOException {
// 1、获取URL实例
URL url = new URL("http://127.0.0.1:8080/examples/abcd.jpg");
// 2、建立与服务器的链接
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
// 3、获取输入流、创建输出流
InputStream is = urlConnection.getInputStream();
File file = new File("dest.jpg");
FileOutputStream fos = new FileOutputStream(file);
// 4、读写数据
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("文件下载成功");
// 5、关闭资源
fos.close();
is.close();
urlConnection.disconnect();
}
}
练习
客户端发送内容给服务端,服务端将内容打印到控制台上。
java
public void client() {
Socket socket = null;
OutputStream os = null;
try {
// 1、创建一个Socket
InetAddress inetAddress = InetAddress.getByName("192.168.21.107"); //声明对方的ip地址
int port = 8989; //声明对方的端口号
socket = new Socket(inetAddress, port);
// 2、发送数据
os = socket.getOutputStream();
os.write("你好,我是客户端,请多多关照".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3、关闭socket、关闭流
try {
if (os != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void server() {
ServerSocket serverSocket = null;
Socket socket = null; //阻塞式的方法
InputStream is = null;
try {
// 1、创建一个ServerSocket
int port = 8989;
serverSocket = new ServerSocket(port);
// 2、调用accept(),接收客户端的Socket
socket = serverSocket.accept();
System.out.println("服务器端已开启");
System.out.println("收到了来自于" + socket.getInetAddress().getHostAddress() + "的连接");
//3. 接收数据
is = socket.getInputStream();
byte[] buffer = new byte[5];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 内部维护了一个byte[]
while ((len = is.read(buffer)) != -1) {
// 错误的,可能会出现乱码。
// String str = new String(buffer, 0, len);
// System.out.print(str);
// 正确的
baos.write(buffer, 0, len);
}
System.out.println(baos.toString());
System.out.println("\n数据接收完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4、关闭Socket、ServerSocket、流
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端发送文件给服务端,服务端将文件保存在本地。
java
public void client() {
Socket socket = null;
FileInputStream fis = null;
OutputStream os = null;
try {
// 1. 创建Socket
// 指明对方(即为服务器端)的ip地址和端口号
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port = 9090;
socket = new Socket(inetAddress, port);
// 2. 创建File的实例、FileInputStream的实例
File file = new File("pic.jpg");
fis = new FileInputStream(file);
// 3. 通过Socket,获取输出流
os = socket.getOutputStream();
// 4. 读写数据
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
System.out.println("数据发送完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5. 关闭Socket和相关的流
try {
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void server() {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
try {
//1. 创建ServerSocket
int port = 9090;
serverSocket = new ServerSocket(port);
//2. 接收来自于客户端的socket:accept()
socket = serverSocket.accept();
//3. 通过Socket获取一个输入流
is = socket.getInputStream();
//4. 创建File类的实例、FileOutputStream的实例
File file = new File("pic_copy.jpg");
fos = new FileOutputStream(file);
//5. 读写过程
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("数据接收完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
//6. 关闭相关的Socket和流
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
从客户端发送文件给服务端,服务端保存到本地。并返回"发送成功"给客户端。并关闭相应的连接。
java
public void client() {
Socket socket = null;
FileInputStream fis = null;
OutputStream os = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
// 1. 创建Socket
// 指明对方(即为服务器端)的ip地址和端口号
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
int port = 9090;
socket = new Socket(inetAddress, port);
// 2. 创建File的实例、FileInputStream的实例
File file = new File("pic.jpg");
fis = new FileInputStream(file);
// 3. 通过Socket,获取输出流
os = socket.getOutputStream();
// 4. 读写数据
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
System.out.println("数据发送完毕");
// 客户端表明不再继续发送数据
socket.shutdownOutput();
//5. 接收来自于服务器端的数据
is = socket.getInputStream();
baos = new ByteArrayOutputStream();
byte[] buffer1 = new byte[5];
int len1;
while ((len1 = is.read(buffer1)) != -1) {
baos.write(buffer, 0, len1);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 6. 关闭Socket和相关的流
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void server() {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
//1. 创建ServerSocket
int port = 9090;
serverSocket = new ServerSocket(port);
//2. 接收来自于客户端的socket:accept()
socket = serverSocket.accept();
//3. 通过Socket获取一个输入流
is = socket.getInputStream();
//4. 创建File类的实例、FileOutputStream的实例
File file = new File("pic_copy.jpg");
fos = new FileOutputStream(file);
//5. 读写过程
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("数据接收完毕");
//6. 服务端发送数据给客户端
os = socket.getOutputStream();
os.write("你的图片很漂亮,我接收到了".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//7. 关闭相关的Socket和流
try {
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}