几个概念
互联网软件结构:
- 客户端-服务器(Client/Server,C/S)架构:胖客户端架构,图形表现力强、安全性能简单、响应速度快,但无法跨平台、针对特定人群、维护成本高、一般采用TCP协议。
- 浏览器-服务器(Browser/Server,B/S)架构:瘦客户端架构,使用方便、能够跨平台使用、针对大众人群、一般采用更上层次的协议(如HTTP、FTP等),但跨浏览器兼容性不好,在速度、安全性和表现力上需要花费更多时间。
网络协议与架构:
- TCP/IP协议:即传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是互联网中最基本、使用最广泛的协议。IP协议定义了计算机如何连入互联网(即如何找到终端),TCP协议定义了数据如何在计算机之间进行传输(即网络连接的方式)。
- 四层架构:TCP/IP协议栈采用4(5)层结构,分别是应用层、传输层、网络层、链路层、(物理层)。
- UDP协议:即用户数据报协议(User Datagram Protocol)。数据的发送端和接收端不建立连接,也不能保证接收端能接收成功。通常用于音频、视频和普通数据的传输。
- TCP协议:是面向连接的通信协议。发送端和接收端需要建立连接才能传输数据,是可靠的、无差错的数据传输协议。每次连接的创建都需要经过“三次握手”的过程。
- IP协议:即互联网协议地址(Internet Protocol Address),作为一个网络中的计算机设备的唯一编号。
- 端口号:由应用程序占用,能够定位设备上的一个应用程序。端口号的取值范围是0~65535。其中,0~1023之间的端口号用于系统内部的使用。查看端口的方式如下: ```shell // Windows中 netstat -aon | findstr 8888 #查看占用8888端口号的进程PID TCP 0.0.0.0:8888 0.0.0.0:0 LISTENING 2696 #显示结果,找到占用8888端口号的PID taskkill /F /pid 2696 #强制关闭
// Linux中 netstat -anp | grep :8888 #查看占用8888端口号的进程PID tcp 0 0 :::8888 :::* LISTEN 3626/java #显示结果,找到占用8888端口号的PID kill -9 3626 #强制关闭
<a name="yuYfT"></a>
## TCP网络编程
TCP协议需要严格区分客户端和服务器,需要由客户端发起请求,服务器响应后,建立连接。在Java中提供了客户端和服务端的抽象——类,用于编程。
- 客户端的类:java.net.Socket
- 服务端的类:java.net.ServerSocket
通过上面两个类进行的编程,又被称为套接字编程。
```java
// 客户端
Socket socket = new Socket("127.0.0.1", 8888); // 定义ip和端口
OutputStream os = socket.getOutputStream();
// 得到网络字节输出流,用包裹数据并发送到网络
PrintWriter pw = new PrintWriter(os); // 用快速输出流包裹,方便按行输出
pw.println("ABCBoy");
pw.flush();
// os.close(); 关闭网络流同时关闭网络
socket.shutdownOutput(); // 只关闭网络流而不关闭socket
socket.close(); // 关闭socket
// 服务端
ServerSocket ss = new ServerSocket(8888); // 定义端口
Socket socket = ss.accept(); // 等待客户端发送数据
// 一直处于waiting状态直到接收到数据
/** 当客户端发送数据后,接着往下执行 **/
InputStream stream = socket.getInputStream(); // 获取客户端发送的数据
BufferedReader reader = new BufferedReader(
new InputStreamReader(stream)); // 将字节流转换为字符流,同时使用缓冲流包裹
String line = null;
while((line = reader.readLine()) != null) {
System.out.println(line); // 按行打印
}
reader.close(); // 关闭缓冲流,内部的全部流以及服务端都会被连带关闭
当客户端发送请求后,需要关闭发送流(shutdownOutput),服务器才能发送响应流到客户端,否则会出现死锁。或者,服务端关闭接收流也可以。
在实际应用中,客户端便是浏览器。浏览器访问服务器会发送一个固定格式的请求,而服务器也会发送一个固定格式的响应。详见HTTP。
UDP网络编程
UDP协议没有发送端和接收端的区分,发送时也不需要建立连接。在Java中提供了一个UDP端的类:java.net.DatagramSocket,和一个UDP发送的数据包的类:java.net.DatagramPacket。
DatagramSocket ds = new DatagramSocket(); // 构建发送端
byte[] bs = "天青色等烟雨,小狗在等你".getBytes(); // 构建byte数组
DatagramPacket packet = new DatagramPacket(bs, 0, bs.length,
InetAddress.getByName("127.0.0.1"), 8888); // 构建数据包
ds.send(packet); // 发送
ds.close(); // 关闭发送端
DatagramSocket ds = new DatagramSocket(8888); // 构建接收端
byte[] buf = new byte[1024]; // 构建接收数组
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
// 构建接收包,将接收到的数据存入buf数组中
ds.receive(packet); // 开始/等待接收
String string = new String(buf, 0, buf.length);
// 接收到后获取buf数组并转成字符串
System.out.println(string);
ds.close();
URL和URI
统一资源标识符(Uniform Resource Identifier)是用来唯一的标识一个网络资源,而统一资源定位符(uniform resource locator)则是一种具体的URI,用来标识和定位某个资源。例如,http://127.0.0.1/hello即是一个URL,而/hello则是URI。
在Java中,可以通过java.net.URL类对象获取连接,模拟一个浏览器,获取网络资源返回的内容。
URL url = new URL("https://www.jd.com");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); // 获取连接
httpConn.setRequestMethod("GET"); //设置请求方式
httpConn.setRequestProperty("User-Agent", //模拟浏览器发送的请求
"Mozilla/5.0 (Windows NT 10.0; Win64; x64;rv:79.0) Gecko/20100101 Firefox/79.0");
InputStream is = httpConn.getInputStream(); //获取连接输入流