Java 网络编程基础学习
学习过程是看毕向东老师的视频。
1.网络模型
OSI参考模型 |
---|
应用层 |
表示层 |
会话层 |
传输层 |
网络层 |
数据链路层 |
物理层 |
面试的时候,技术总监最后和我说到这里时,我表示一脸蒙蔽,说不出这7层名字都是啥。
TCP/IP 参考模型 |
---|
应用层 |
传输层 |
网络层 |
主机至网络层 |
根据我目前的了解,我是在最上层应用层开发。
网络通讯要素:
- IP地址
- 端口号
- 传输协议
2 TCP与UDP
- TCP(Transmission Control Protocol 传输控制协议)
在OSI中属于第四层传输层的协议。是一种面向连接的,可靠的,基于字节流的的传输层协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。
TCP三次握手应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
TCP三次握手的过程如下:
- 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
- 服务器端收到SYN报文,回应一个SYN(SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
- 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
- UDP(User Datagram Protocol用户数据报协议)
同TCP协议同层,UDP也是第四层传输层的协议。是无连接的,不可靠的,协议。
UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
以上主要摘抄百度百科。
3.TCP和UDP的特点
TCP特点
- 建立连接,形成传输数据的通道
- 在连接中进行大量的数据传输
- 三次握手,可靠
- 由于必须建立连接,效率稍低
UDP特点
- 将数据、源和目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64k
- 不可靠,可能丢包
- 由于不需要建立连接,所以速度快
常见的使用场景
UDP:聊天,视频会议
TCP:下载文件
4.Socket
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。两个Socket间通信主通过IO。Socket进行通信所需要的协议不只有TCP/IP,在Java中主要就是TCP/IP协议。
TCP/IP协议
Transmission ControlProtocol/InternetProtocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。
TCP通信需要Socket
和ServerSocket
两个类。
客户端对应Socket
,服务端对应ServerSocket
。
TCP建立两个Socket的过程:
当客户端有Socket试图连接服务端某个目标端口时,监听这个服务端目标端口的ServerSocket就会接受(accept)这个客户端的Socket请求,ServerSocket并在服务端建立一个Socket来与客户端进行通信。这时,客户端和服务端便各有了一个Socket。
UDP客户端和服务端的两个Socket进行通信,需要DatagramSocket
和DatagramPacket
这两个封装好的类。
DatagramSocket
This class represents a socket for sending and receiving datagram packets.
DatagramPacket
This class represents a datagram packet.
感觉英文反而容易理解一些。
DatagramPacket
:把数据进行封装的数据报包。作用是用来实现无连接的包投递服务。
DatagramSocket
:负责发送和接受数据报包。
5.UDP简单实例
客户端向服务端发送Hello World!
客户端代码:
public class UdpSend {
public static void main(String[] args) {
String info = "Hello World";
int port = 10888;
boolean b = sendMessage(info, port);
if (b) {
System.out.println("ok!!!");
}
}
private static boolean sendMessage(String info, int port) {
try {
// 1 创建DatagragmSocket对象
int me = 10887;
DatagramSocket ds = new DatagramSocket(me);
// 2 创建DatagramPacket对象
byte[] buf = info.getBytes();// byte[]
InetAddress address = InetAddress.getByName("192.168.0.103");// IP
DatagramPacket dp = new DatagramPacket(buf, buf.length, address, port);
// 3 发送数据
ds.send(dp);
// 4 关闭连接
ds.close();
return true;
} catch (Exception e) {
return false;
}
}
}
在客户端代码中,客户端端口号为10887,服务端端口号为10888.
DatagramSocket
构造方法中的端口号为自己的端口号10887。
DatagramPacket
构造方法中也需要一个端口号,但这个端口号为服务端,接收DatagramPacket
这个数据报包的DatagramSocket
的端口号10888。
服务端代码:
public class UdpReceiver {
public static void main(String[] args) {
int port = 10888;
receString(port);
}
private static void receString(int port) {
try {
// 1 创建DatagramSocket对象 确定端口
DatagramSocket ds = new DatagramSocket(port);
// 2 创建DatagramPacket
byte[] buf = new byte[1024 * 8];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3 将接收到的数据放入DatagramPacket中
ds.receive(dp);
// 4 利用DatagramPacket的方法拿到具体的数据
String ip = dp.getAddress().getHostAddress();
int p = dp.getPort();
19行: String info = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "\n" + info + "\n" + p);
// 关闭连接
ds.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
需要注意的是19行中,拿String数据时,通过dp.getLength()
这个方法,根据DatagramPacket
中数据的时机大小来确定。因为定义的buf
的大小为1024 * 8
。
还有就是记得关闭连接。
6.TCP简单实例
客户端代码:
public class TcpClient {
public static void main(String[] args) {
String info = "Hello world!";
boolean b = sendMessage(info);
if (b) {
System.out.println("ok");
}
}
private static boolean sendMessage(String info) {
int port = 10902;
try {
InetAddress address = InetAddress.getByName("192.168.0.103");
// 1 建立Socket
Socket socket = new Socket(address, port);
// 2 拿到输出流
OutputStream outputStream = socket.getOutputStream();
// 3 写入数据
outputStream.write(info.getBytes());
// 4 关闭Socket
socket.close();
return true;
} catch (Exception e) {
return false;
}
}
}
服务端代码:
public class TcpServer {
public static void main(String[] args) {
receInfo();
}
private static void receInfo() {
try {
// 1 建立ServerSocket
ServerSocket serverSocket = new ServerSocket(10902);
// 2 通过accept()拿到Socket
Socket socket = serverSocket.accept();
// 打印IP
System.out.println(socket.getInetAddress().getHostAddress());
// 3 通过Socket拿到输入流
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int len;
// 4 读取数据
while ((len = inputStream.read(buf)) != -1) {
String info = new String(buf, 0, len);
System.out.println(info);
}
// 5 关闭Socket和ServerSocket
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端Socket
和服务端ServerSocket
的端口号为一个。ServerSocket
就是通过端口号和客户端的Socket
通过accept()
建立联系。
7.最后
UDP通信依赖DatagramSocket
和DatagramPacket
。
TCP通信依赖Socket
和ServerSocket
。
Java Socket网络编程最基础的部分有了一点了解,还有很多东西就需要以后继续深入学习。有错误希望可以指出。: )
共勉。