网络编程
1.1 概述
地球村
信件:
计算机网络:
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来(网线),在网络操作系统(windows),网络管理软件及 网络通信协议(http、udp) 的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程的目的:
无线电台…传播交流信息,数据交换。通信
想要达到这个效果需要什么:
- 如何准确的定位网络上的一台主机 192.168.16.124:端口,定位到这个计算机上的某个资源.
- 找到了这个主机,如何传输数据呢?
javaweb:网页编程 B/S
网络编程:TCP/IP C/S
1.2 网络通信的要素
人工智能:智能汽车:工厂,人少
因为伦理问题所以无法大规模上线
如何实现网络的通信?
通信双方地址:
- ip
- 端口号
- 192.168.16.124:5900
规则:网络通信的协议
http,ftp,smtp,tcp,ucp
TCP/IP参考模型
重点:传输层 TCP,UDP
小结:
- 网络编程中有两个主要的问题
- 如何准确的定位到网络上的一台或者多台主机
- 找到主机之后如何进行通信
- 网络编程中的要素
- IP 和 端口号 IP
- 网络通信协议 udp,tcp
- 万物皆对象
1.3 IP
ip地址:InetAddress
- 唯一定位一台网络上计算机
- 127.0.0.1 : 本机 loachost
- ip地址的分类
- IP地址分类
- ipv4/ipv6
- IPV4 127.0.0.1 ,4个字节组成。0~255,42亿;
- IPV6 128位,8个无符号整数;
-2001 : 0bb2 : aaaa : 0015 : 0000 : 0000 : 1aaa : 1312
- 公网(互联网)-私网(局域网)
- 192.168.xx.xx专门给组织内部使用的 局域网
- ABCD类地址0-128-192-223-239 A类为8位,B类为16为,C类为32位,D类为多播地址。
- 域名:记忆IP问题!
- IP: www.vip.com
//测试 IP
public class TestAddress {
public static void main(String[] args) {
try {
//查看本机地址
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
InetAddress inetAddresst3 = InetAddress.getByName("localhost");
InetAddress inetAddresst4 = InetAddress.getLocalHost();
//查询网站ip地址
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress1 );
System.out.println(inetAddress2 );
System.out.println(inetAddress3 );
System.out.println(inetAddress4 );
//常用方法
System.out.println(inetAddress2.getAddress());
System.out.println(inetAddress2.getCanonicalHostName());//规范的名字
System.out.println(inetAddress2.getHostAddress());//ip
System.out.println(inetAddress2.getHostName());//域名,或者电脑的名字
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
1.4 端口
端口表示计算机上的一个程序的进程
-
不同的进程有不同的端口号;用来区分软件。
-
被规定 0~65535
-
TCP,UDP:65536 * 2 tcp:80,udp:80,单个协议下,端口号不能冲突
-
端口分类
- 公有端口:0~1023
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
- 程序注册端口:2014~49151,分配给用户或者程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有:49152~65535
netstat -ano # 查看所有的端口 netstat -ano|findstr "5900" # 查看指定端口的进程
两台电脑通信,要找到另一台电脑上的特定端口
- 公有端口:0~1023
1.5 通信协议
协议:约定,就好比我们现在写的是汉字,都能看懂。
**网络通信协议:**速率,传输码率,代码结构,传输控制…
大事化小:分层
TCP/IP协议簇:实际上是一组协议
重要:
- TCP: 用户传输协议
- UDP:用户数据报协议
出名的协议:
- TCP:
- IP:网络互连协议
TCP UDP 对比
TCP:打电话
- 连接,稳定
- 三次握手 四次挥手:详解在下方
- 客户端、服务端
- 传输完成,释放连接,效率低
UDP:发短信
- 不连接,不稳定
- 客户端,服务端:没有明确的界限
- 不管有没有准备好,都可以发给你
- 导弹
- DDOS:洪水攻击(饱和攻击)
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。小信息。
-
第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于
SYN_SENT
状态。首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。 -
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于
SYN_RCVD
的状态。在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。 -
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于
ESTABLISHED
状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。
为什么需要三次握手,两次不行吗?
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。
这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。
这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。
这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
此处三次握手四次挥手转自博主:猿人谷 完整文章
四次挥手,建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
刚开始双方都处于ESTABLISHED
状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
-
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
-
第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于
CLOSE_WAIT
状态。即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。 -
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于
LAST_ACK
的状态。即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。 -
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于
TIME_WAIT
状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
1.6 TCP
客户端
- 连接服务器 Socket
- 发送消息
// 客户端
public class TcpClientDemo01 {
public static void main(String[] args) {
int port = 0;
Socket socket = null;
InetAddress serverIp = null;
OutputStream os = null;
try {
//1.要知道服务器的地址,端口号
serverIp = InetAddress.getByName("127.0.0.1");
port = 9999;
//2.创建一个socket连接
socket = new Socket(serverIp,port);
//3.发送消息 IO流
os = socket.getOutputStream();
os.write("您好,Swae Lee".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}if (os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务器
- 建立服务的端口 ServerSocket
- 等待用户的连接 accpet
- 接收用的消息
// 服务端
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//1.我得有一个地址
serverSocket = new ServerSocket(9999);
//2.等待客户端连接
socket = serverSocket.accept();
//3.读取客户端的消息
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.err.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();
}
}
}
}
}
本篇文章根据B站up主:狂神说视频 总结