Java.Network01

网络编程概念

计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信。网络编程就是如何在程序中实现两台计算机的通信。

网络编程对所有开发语言都是一样的。用Java进行网络编程,就是在Java程序本身这个进程内,连接别的服务器进程的通信端口进行通信。

TCP/IP简介

为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称TCP/IP协议。

通信的时候,双方必须知道对方的标识。互联网上每个计算机的唯一标识就是IP地址,类似123.123.123.123。

IP

IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证顺序到达。

TCP

TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。

一个TCP报文除了包含要传输的数据外,还包含源IP地址和目标IP地址,源端口和目标端口。

端口有什么作用?在两台计算机通信时,只发IP地址是不够的,因为同一台计算机上跑着多个网络程序。每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。一个进程也可能同时与多个计算机建立链接,因此它会申请很多端口。

网络通信的要素

网络编程中的两大要素:

  1. 如何定位网络上的一台或多台主机?
  • 通过IP地址和端口号,就能定位到某一台计算机上的具体应用
  • IP地址
  • 端口号
  1. 找到主机之后如何通信?
  • 网络通信协议
  • TCP
  • UDP

网络编程准备

IP

Java提供了针对IP地址的类:InetAddress

  • IP:唯一定位网络上的一台计算机
  • 常见IP:
  • 127.0.0.1:本机(localhost)
  • IP地址分类
  • IPv4/IPv6
    • IPv4:如192.168.0.1,4个字节,32位,每位从0-255
    • IPv6:如2001:0db8:85a3:0042:1000:8a2e:0370:7334,8个无符号整数,128位,每位从0-255
  • 公网(互联网)-私网(局域网)

InetAddress类

InetAddress类无法实例化,因为其没有构造器,只能通过其类名调用静态方法
查询本机地址的多种方法

InetAddress ip1 =  InetAddress.getByName("127.0.0.1");
InetAddress ip2 =  InetAddress.getByName("localhost");
InetAddress ip3 =  InetAddress.getLocalHost();

查询域名的IP地址

InetAddress ip4 =  InetAddress.getByName("www.lilmoon.xyz");

InetAddress常用方法

String hostName = ip4.getHostName();        // 获取ip对应的域名
String hostAddress = ip4.getHostAddress();  // 获取对应的ip地址
byte[] Address = ip4.getAddress();          // 获取地址

端口

端口表示计算机上的一个进程:

  • 不同的进程端口号不同,用于区分不同进程
  • 端口范围:0-65535
  • 端口分为TCP端口和UDP端口,各有65536个端口,不同协议的端口号可以相同
  • 端口分类:
  • 公有端口:0-1023
  1. HTTP:80
  2. HTTPS:443
  3. FTP:21
  4. SFTP:22
  5. Telent:23
  • 程序注册端口:1024-49151,分配给用户或程序
  1. Tomcat:8080
  2. MySQL:3306
  3. Oracle:1521
  • 动态/私有端口:49152-65535

端口相关常用DOS命令:

# 查看所有端口
netstat -ano

# 查找具体的端口
netstat -ano|findstr "1024"

# Linux/Win查看指定端口的进程
tasklist|findstr "1024"
# Mac查看指定端口的进程
lsof -i :80

InetSocketAddress

InetSocketAddress类可以实例化,可以输入IP+端口号作为参数。

InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1", 80);

常用方法

System.out.println(inetSocketAddress1.getAddress());        // 获取IP地址
System.out.println(inetSocketAddress1.getHostName());       // 获取主机名
System.out.println(inetSocketAddress1.getPort());           // 获取端口

通信协议

网络通信协议涉及速率,传输码率,代码结构,传输控制等多种概念,十分复杂,所以采用了分层的思想。
TCP/IP协议簇,包含了多种协议,最要的协议有:

  • TCP:用户传输协议
  • UDP:用户数据报协议
  • IP:网络互联协议

协议分层

OSI体系结构 TCP/IP协议簇
应用层 应用层 TELENT、FTP、HTTP、SMTP、DNS等
表示层
会话层
传输层 传输层 TCP、UDP
网络层 网络层 IP、ICMP、ARP、RARP
数据链路层 网络接口层 各种物理通信网络接口
物理层

TCP、UDP对比

TCP:

  • 连接,稳定
  • 三次握手,四次挥手
  • 客户端/服务端
  • 传输完成,释放连接

UDP:

  • 不连接,不稳定
  • 客服端/服务端,无明显界限
  • 对方没准备好也可以发送

实现网络编程

TCP实现传递信息

客户端

客户端要做的工作:

  1. 提供要连接的服务端IP地址及端口号
  2. 创建Socket连接对象
  3. 发送信息(IO流)
  4. 最后关闭资源

代码实现:

// 1.提供服务端的地址及端口号
InetAddress serverIP= InetAddress.getByName("127.0.0.1");
int port = 9999;
// 2.创建socket连接
Socket socket = new Socket(serverIP, port);
// 3.发送消息 IO流
OutputStream os = socket.getOutputStream();
os.write("Hello Server!".getBytes());
// 4.关闭资源
os.close();
socket.close();

System.out.println("连接结束");

服务端

服务端要做的工作:

  1. 创建可供连接的端口
  2. 监听客户端连接
  3. 读取客户端发来的消息(通过管道流实现)
  4. 最后关闭资源

代码实现:

// 1.提供服务端地址
ServerSocket serverSocket = new ServerSocket(9999);
// 2.等待客户端连接
Socket accept = serverSocket.accept();
// 3.读取客户端消息
InputStream is = accept.getInputStream();

// 管道流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
// input stream的read方法用于将读到的内容写入buffer,直到全部读取完毕或buffer读满
// 没读到数据时,会返回-1
while ((len = is.read(buffer))!=-1) {
    baos.write(buffer, 0, len);
}
System.out.println(baos.toString());

// 4.关闭资源
baos.close();           // 输出完毕
is.close();             // 输入完毕
accept.close();         // 断开连接
serverSocket.close();   // 关闭服务端

TCP实现文件传输

客户端

客户端要做的工作:

  1. 创建socket连接
  2. 通过文件流读取文件
  3. 创建输出流
  4. 写出文件
  5. 停止输出(通知服务端已完成发送)
  6. 因为TCP为安全连接,等待收到服务端的收到确认
  7. 关闭资源

代码实现:

// 1.创建socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
// 2.文件流,读取文件
FileInputStream fis = new FileInputStream(new File("02-3.jpg"));
// 3.创建输出流
OutputStream os = socket.getOutputStream();
// 4.写出文件
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
    os.write(buffer, 0, len);
}

// TCP为安全连接,需要通知服务端已经发送完毕
socket.shutdownOutput();        // 停止输出

// TCP为安全连接,需要确认服务端接收到
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] check = new byte[1024];
int cnt;
while ((cnt = is.read(check)) != -1) {
    baos.write(check, 0, cnt);
}
if (baos.toString().equals("Received")) {
    System.out.println("Successfully sent");
}

// 5.关闭资源
baos.close();
is.close();
os.close();
fis.close();
socket.close();

服务端

服务端要做的工作:

  1. 提供连接的端口
  2. 监听客户端连接
  3. 通过文件流接收文件
    4.创建接收流,接收文件
  4. 通过文件流输出文件
  5. 因为TCP为安全连接,需要通知客户端已接收完毕
  6. 关闭资源

实现代码:

// 1.提供端口
ServerSocket serverSocket = new ServerSocket(9999);
// 2.监听连接
Socket accept = serverSocket.accept();
// 3.创建接收流,接收文件
InputStream is = accept.getInputStream();
// 4.文件输出
FileOutputStream fos = new FileOutputStream(new File("Accept_02.jpg"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
    fos.write(buffer, 0, len);
}
System.out.println("Successfully received");

// TCP为安全连接,需要告知客户端接收完毕
OutputStream os = accept.getOutputStream();
os.write("Received".getBytes());


// 5.关闭资源
fos.close();
is.close();
accept.close();
serverSocket.close();
tag(s):
show comments · back · home