计算机网络
计算机网络就是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来。根据网络覆盖的范围不同,对网络进行分类:局域网、城域网、广域网。
局域网:覆盖范围最小,覆盖一个机房或者一个教室等
城域网:覆盖范围较大,可以覆盖一整个城市。
广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代表。
网络相关概念
IP地址
IP地址是用于唯一标识网络中的每台计算机
查看ip地址可以通过cmd进入dos用 ipconfig来查看IP地址
IP地址的表示形式是点分十进制 即XX.XX.XX.XX每个十进制数的范围为0-255。
ip地址的组成为网络地址和主机地址
目前大部分使用的都是IPV4协议(4个字节32位),但IPV4协议已经不足以满足人类对网络的需求了,因此互联网工程任务组设计了IPV6替代IPV4,IPV6(16个字节128位)地址数量号称可以为全世界每一粒沙子编上地址。(你电脑中的IPV6地址,目前使用IPV6替代IPV4仍需过渡)。
IPV4地址分类
InetSocketAddress类
该类表示互联网协议地址即IP地址、该类无构造方法
常用方法有:
byte[] getAddress()
返回此 InetAddress 对象的原始 IP 地址。
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。
public static void main(String[] args) throws UnknownHostException {
//获取本机IP
InetAddress IP = InetAddress.getLocalHost();
System.out.println(IP);
//获得主机名
System.out.println(IP.getHostName());
//获得IP地址
System.out.println(IP.getHostAddress());
InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
//获取此IP地址的主机名和地址(以文本表现)
System.out.println(inetAddress.getHostName() + inetAddress.getHostAddress());
}
域名和端口号
举例www.baidu.com就是百度的域名,域名的好处是方便记忆,避免了记ip的困难
端口号是用于标识计算机某个特定的网络程序,端口号表示形式是整数形式,范围为0-65535,通常来说0-1024已经被占用,
常用的网络程序端口号:
tomcat:8080、mysql:3306、oracle:1521、sqlserver:1433
DOS命令查看端口命令:
netstat -ano 查看所有端口
netstat -ano|findstr “端口号” 查看指定端口
tasklist|findstr “端口号” 查看指定端口的进程
InetSocketAddress类
该类实现IP套接字地址(IP地址 + 端口号)
构造方法包括
InetSocketAddress(InetAddress addr, int port)
根据 IP 地址和端口号创建套接字地址。
InetSocketAddress(int port)
创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
InetSocketAddress(String hostname, int port)
根据主机名和端口号创建套接字地址。
常用方法有
int getPort() 获取端口号
String getHostName() 获取hostname
InetAddress getAddress() 获取InetAddress
InetSocketAddress inetSocketAddress = new InetSocketAddress(IP.getHostAddress(),3600);
System.out.println(inetSocketAddress);
//返回主机名
System.out.println(inetSocketAddress.getHostName());
//获得端口
System.out.println(inetSocketAddress.getPort());
//返回一个IP对象
System.out.println(inetSocketAddress.getAddress());
网络通信协议(TCP/UDP)
TCP
- 传输控制协议
- TCP是面向连接的通信协议,在传输数据之前,在发送端和接收端建立逻辑链接,然后在传输数据,两台计算机可以毫无差错的数据传输
- TCP连接的建立要经过“三次握手”
- TCP客户端和服务器端断开连接需要四次挥手
三次握手
即在TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,保证连接的可靠。三次握手具体指的是:
- 客户端向服务器端发出连接请求,等待服务器确认
- 服务器端向客户端回应,通知客户端已经收到了连接请求
- 客户端再次向服务器端发送确认信息,确认连接
三次握手完成,客户端和服务器端成功建立连接,可以开始传输数据。
四次挥手
- 客户端打算关闭连接,会发送一个FIN 报文(信号1)给服务器端,然后客户端进入一个FIN_WAIT_1 状态
- 服务器端收到信号后回送给客户端一个ACK 应答报文,然后进入CLOSED_WAIT 状态
- 客户端收到应答信号后进入 FIN_WAIT_2 状态
- 服务器端处理完数据后也向客户端发送FIN 报文(信号1)之后服务器端进入 LAST_ACK 状态
- 客户端收到FIN报文(信号1)后回一个ACK 应答报文,进入TIME_WAIT状态
- 服务器收到了ACK 应答报文进入CLOSE,到这里服务器端完成连接的关闭
- 客户端经过2MSL时间后,自动进入CLOSE状态,到这里客户端完成连接的关闭
主动关闭连接才会有TIME_WAIT 状态。
个人理解: 小明(客户端) 小红(服务器端)
三次握手: 小明告诉小红我要来了,小红说我知道你要来了,小明说那我来了。
四次挥手:小明说我们分开吧,小红说真的分开吗,小红伤心了很久(处理数据结束)说你确定要分开吗,小明说是的。
不难发现四次挥手比三次握手多了一次其实就是服务器端需要处理未处理完的数据,导致比三次握手多了一次。
UDP
- 用户数据报协议(User Datagram Protocol)
- 数据报即网络传输的基本单位
- UDP是无连接的通信协议,即在数据传输时无需建立连接,就是“流氓传输”,数据发送端不会管接收端是否存在就会发出数据,接收端收到数据也不会反馈给发送端是否收到数据。(因此UDP不能保证数据的完整性,传输重要数据不建议使用UDP协议)
- UDP资源消耗小,通信效率高,通常用于音频、视频和普通数据传输,视频会议一般都会使用UDP协议
- UDP特点:数据被限制在64kb以内,超出这个范围就不能发送。
TCP网络编程
TCP能实现两台计算机之间的数据交互,两端要区分客户端(Client)和服务器端(Server)
通信步骤:
服务器端必须先启动,等待客户端的连接(不然小明和小红都不认识,小明不知道发给谁)
客户端主动连接服务器端,连接成功后通信,服务器端不能主动连接客户端
Java中提供了两个类用于实现TCP通讯程序
客户端:Socket类表示,创建Socket对象,向服务器端发出连接请求,服务器端相应请求,两者建立连接开始通信
服务端:ServerSocket表示,创建ServerSocket对象,等待客户端连接
Socket类
构造器
Socket socket = new Socket(InetAddress.getLocalHost(), 2103);
该参数可以是一个字符串形式的IP地址,博主自己一台电脑,因此就获取了本地的IP地址
常用方法
getInputStream() 返回此套接字的输入流
如果此Scoket具有相关联的通道,则生成的InputStream的所有操作也关联该通道
关闭生成的InputStream也将关闭相关的Socket
getOutputStream()返回此套接字的输出流
如果此Socket具有相关通道,则生成的OutputStream所有操作也关联该通道
关闭生成的OutputStream也将关闭相关Socket
close() 关闭此套接字
一旦一个Socket被关闭,则不可被使用,并关闭相关的流
shutdownOutput() 禁用此套接字的输出流
任何之前写出的数据被发送随后终止输出流。
ServerSocket类
这个类实现了服务器套接字,该对象等待通过网络的请求
构造器
public ServerSocket(int port) 使用该构造器在创建ServerSocket对象时,可以将其绑定到一个指定的端口号上,参数就是端口号
ServerSocket serverSocket = new ServerSocket(2103);
常用方法
accept()方法,侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信功能,该方法会一直阻塞直至连接建立
//服务器端
public static void main(String[] args) throws IOException {
//服务器端启动等待客户端发送链接
ServerSocket serverSocket = new ServerSocket(2103);
System.out.println("服务端正在2103端口监听,等待连接。。。");
//侦听并接收连接,返回一个新Socket对象
Socket socket = serverSocket.accept();
System.out.println("服务端 socket =" + socket.getClass() );
//建立输入流
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
//对客户端发送的数据进行读取
while ((readLen = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,readLen));
}
//建立输出流,向客户端发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello client".getBytes());
//调用shutdownOutput方法禁用输出流,表示服务器端发送数据结束,
// 保证服务器端能够正确的处理客户端发送的数据,并释放相关资源
socket.shutdownOutput();
//释放相关资源
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
//客户端
public static void main(String[] args) throws IOException {
//客户端向服务器端发送链接等待服务器确认
Socket socket = new Socket(InetAddress.getLocalHost(), 2103);
System.out.println("客户端收到,返回" + socket.getClass());
//建立输出流来向服务器端发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello Server".getBytes());
//调用shutdownOutput方法禁用输出流,表示客户端发送数据结束,
// 保证客户端能够正确的处理服务器端发送的数据,并释放相关资源
socket.shutdownOutput();
//建立输入流来读取客户端发送的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int readlen = 0;
while ((readlen = inputStream.read(bytes)) != -1){
System.out.println(new String(bytes,0,readlen));
}
//关闭相关资源
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
UDP网络编程
UDP与TCP不同,UDP不区分Server和Client,对于UDP,不存在Server和Client
JAVA提供了两个类DatagramSocket(此类用于发送和接收数据报的套接字)和DatagramPacket(该类表示数据报的数据包)
DatagramSocket
构造器
protected DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口。
protected DatagramSocket(int port) 构造数据报套接字并将其绑定到本地主机上的指定端口。
protected DatagramSocket(int port, InetAddress laddr) 创建一个数据报套接字,绑定到指定的本地地址。
DatagramPacket
构造器
DatagramPacket(byte[] buf, int offset, int length) 构造一个 DatagramPacket用于接收指定长度的数据报包到缓冲区中。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造用于发送指定长度的数据报包到指定主机的指定端口号上。
(2)常用方法摘要
byte[] getData() 返回数据报包中的数据。
InetAddress getAddress() 返回该数据报发送或接收数据报的计算机的IP地址。
int getLength() 返回要发送的数据的长度或接收到的数据的长度。
//发送方
public static void main(String[] args) throws IOException {
//创建一个socket对象
DatagramSocket socket = new DatagramSocket();
InetAddress inetAddress = InetAddress.getLocalHost();
String message = "你好啊你好啊你好不好";
byte[] buf = message.getBytes(StandardCharsets.UTF_8);
//创建一个包
DatagramPacket packet = new DatagramPacket(buf,0,buf.length,inetAddress,2013);
//发送包
socket.send(packet);
//释放资源
socket.close();
}
//接收方
public static void main(String[] args) throws IOException {
//创建socket对象 打开端口
DatagramSocket socket = new DatagramSocket(2013);
byte[] buf = new byte[1024];
//创建一个包接收数据
DatagramPacket packet = new DatagramPacket(buf,0,buf.length);
//接收数据,一直阻塞直至接收
socket.receive(packet);
//将数据包转为字符串输出
String message = new String(packet.getData(),0,packet.getLength());
System.out.println(message);
//释放资源
socket.close();
}