基本概念
网络
- 多台计算机组成,使用物理线路连接
- 交换数据,共享资源
网络编程三要素
- IP地址:唯一标识网络上每一台计算机,
两台计算机间通信必备要素ipconfig
查看 - 端口号:计算机中应用程序的编号
有效端口0~65536
系统使用或保留端口0~1024 - 通信协议:通信的规则 TCP UDP
国际通用协议TCP/IP协议
网络分层模型
网络模型一:
OSI开发系统互联参考模型
网络模型二:
TCP/IP参考模型:Transfer Control Protocol/Internet Protocol传输控制/网际协议
IP地址表示方法:
IP地址一共32位。
IP地址 = 网络IP + 主机IP
- 网络ID:标识计算机或网络设备所在网段
- 主机ID:标识特定主机或网络设备
特殊的IP地址
0.0.0.0:本机 更多是阻断和外网的通信
127.0.0.1:本机回环地址,用于本机测试 localhost 可以通信
255.255.255.255:当前子网,一般用于向当前子网广播信息
IP地址所对应的对象–>InetAddress
Java提供了一个对ip地址的访问类java.net.InetAddress
。无构造方法。
InetAddressDemo.java
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost); // 主机名+IP地址
// 自己局域网内(同一网段内)的主机名才能拿到ip地址
InetAddress inetAdd = InetAddress.getByName("LAPTOP-8VFER8KN");
System.out.println(inetAdd);
//拿到百度的ip地址
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println(baidu);
System.out.println(baidu.getHostAddress());
System.out.println(baidu.getHostName());
}
}
端口:port
端口是虚拟概念,并不是主机上真的有若干端口。通过端口可以在一个主机上运行多个网络应用程序。
传输协议
UDP:
- 相当于发短信(有字数限制),不需要建立连接,效率较高但容易丢包
- 数据报大小限制在64k内
TCP: - 相当于打电话,需要建立连接,效率较低但数据传输安全。
- 三次握手和四次分手。
为什么要三次握手?
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
为什么要四次分手?
A、B通信,如果三次分手可能会造成:A端已经释放了资源,但B端的资源没有释放。这就会造成我们对应资源的一种浪费。
视频是用UDP还是TCP?
可以先用TCP建立连接,再用UDP传输数据。视频掉帧影响不大
Socket套接字
- 网络上两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端(接收数据的地方,接收IO请求的,可以读写数据的地方)称为一个Socket。
- 比如两台计算机互联,需要个接口,那么这个网线就是socket。两个程序互连,存在网络上,所以是一个逻辑上的概念,相当于虚拟接口。
- Socket是Java中定义好的一个类,Java中使用Socket完成TCP程序的开发,使用它可以方便地建立可靠、双向、持续性(消息没发完不可能断)、点对点的通讯连接。
- 在Socket的程序开发中,服务器端使用ServerSocket等待客户端的连接(ServerSocket相当于是硬件设备)
基于TCP协议的Socket编程
进行网络通信时,Socket需要借助数据流来完成数据的传输工作。
- 通信双方需要建立连接
- 连接建立时双方存在主次之分。(先服务端再客户端)
Socket类java.net.Socket
双端通信:
客户端向服务端发送数据
- 先启动服务端,如果先启动客户端会报拒绝连接的错误
- 如果启动两次服务端也会报错(地址被占用),因为端口只能绑定一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//Client.java
// 创建客户端的套接字
Socket client = new Socket("127.0.0.1",10000);
//-------------向外进行输出----------------
// 获取输出流对象
OutputStream outputStream = client.getOutputStream();
// 数据输出
outputStream.write("hello java".getBytes());
/**
* 或者:
* // 将输出流对象进行包装
* DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
* // 传输数据
* dataOutputStream.writeUTF("hello,你好");
*/
//--------------接受服务器端返回的消息----------------------
InputStream inputStream = client.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("服务端的响应数据是:"+new String(buf,0,length));
//关闭流操作
inputStream.close();
outputStream.close();
client.close();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// Server.java
// 创建servertsocket对象
ServerSocket serverSocket = new ServerSocket(10000);
// 获取服务器的套接字对象
Socket server = serverSocket.accept();
//-------------接受客户端的输入----------------
// 获取输入流对象
InputStream inputStream = server.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("客户端传输的数据是:" +new String(buf,0,length));
/**
* 或者:
* // 对输入流做包装,包装成DataInputStream
* DataInputStream dataInputStream = new DataInputStream*(inputStream);
* // 读取对应的数据
* String s = dataInputStream.readUTF();
* System.out.println(s);
*/
//-------------向进客户端进行输出----------------
OutputStream outputStream = server.getOutputStream();
// 数据输出
outputStream.write("hello from server".getBytes());
// 关闭流对象
outputStream.close();
inputStream.close();
server.close();
serverSocket.close();
注:
- 不能自动关闭流,必须手动进行关闭
- 当数据比较大的时候,需要添加输入输出流完成的标志
shutdownOutput()或者shutdownInput() - 如果传输的是对象,需要用到
ObjectOutputStream
,序列化
IDEA 实现
Serializable
接口时,自动生成UID值的方法。
File –> Settings –> Editor –> Inspections –> Java –> Serialization issues –> 勾选“Serializable class without ‘serialVersionUID’”
之后选择类名,按”alt + enter”,可以随机生成数字作为UID
基于UDP的网络编程(用的少)
- 通信双方不需要建立连接
- 通信双方完全平等
同样需要用到套接字,只不过变成了DatagramSocket
(此类表示用于发送和接收数据报数据包的套接字)
DatagramPacket
:该类表示数据报包。用于实现无连接传送服务。
UDPClient.java
/**
* 客户端向服务端传送消息
* 先后启动无顺序
*/
public class UDPClient {
public static void main(String[] args) throws Exception {
// 创建UDP通信的socket 自己对应的端口
DatagramSocket datagramSocket = new DatagramSocket(10000);
// 从控制台读取数据
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
// 远程的地址和端口
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("localhost"),10001);
// 发送数据
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
UDPServer.java
public class UDPServer {
public static void main(String[] args) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket(10001);
//--------接收数据----------
byte[] buf = new byte[1024];
// 用来接收传输过来的数据
DatagramPacket datagramPacket = new DatagramPacket(buf,buf.length);
// 利用创建好的数据报包来接收数据
datagramSocket.receive(datagramPacket);
// 打印输出信息
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
datagramSocket.close();
}
}