Socket

理解 Socket

提到 Socket,大家一般都会想到「套接字」,这也是许多书籍以及文章中对 Socket 起的中文名字。那么「套接字」这个词又是什么意思呢?至少我是不能通过这个词直接理解 Socket 是什么东西或者是用来干什么的,要通过更加深入的学习才能知道它是用于网络通信的。

我们都知道计算机科学领域的技术基本上都是老外发明的,那么老外为什么选这么一个词来作为一个通信的技术名称呢?我们不妨查一下英文词典,看看 Socket 这个单词的解释。

socket /'sɑkɪt/
1. n. 插座
2. vt. 给...配插座

看完 socket 这个单词的解释、配图,再看一下下图中早期的电话接线员的工作。是不是忍不住想爆下粗口,哦,wō cāo,茅厕顿开啊!!!

电话接线员

Socket 通信原理

其实 Socket 的通信原理和电话很相似,客户端和服务器分别创建自己的 Socket,服务器的 Socket 就是插座,客户端的 Socket 就是插头,当插头插入插座中就可以通信了,如下图:

Socket 通信原理图

从网络分层模型的角度看,Socket 属于哪层呢?

其实 Socket 是属于传输层在代码里的具体实现。

Java 里的 Socket

我们都知道传输层的协议主要有 TCP 和 UDP 两种,在 Java 提供的类中,分别对应于 Socket(流套接字) 和 DatagramSocket(数据报套接字)。

下面通过两个请求百度首页的 Java 代码来进一步理解 Socket。

百度的首页其实就是一个标准的 html 文件,由 <head> <title> <body> 等标签组成,所以进一步说它是一段文本内容,只不过浏览器把它解释渲染成了我们见到的网页效果。

使用 Socket API 请求

我们要使用 Socket 请求这些内容,需要准备什么呢?

  • 百度服务器的域名:baidu.com
  • 服务器的端口:80
  • 请求路径:因为是首页,所以就是根路径 “/”,当然 “/index.html” 也可以
  • 使用的协议:当然是 HTTP
Socket socket = new Socket();
InetSocketAddress address = new InetSocketAddress("baidu.com", 80);.
socket.connect(address);
String requestHeader = "GET /index.html HTTP/1.1\r\n";
requestHeader += "Host: www.baidu.com\r\n";
requestHeader += "\r\n";
OutputStream outputStream = socket.getOutputStream();
outputStream.write(requestHeader.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024 * 8];
while (inputStream.read(bytes) >= 0) {
    System.out.println(new String[bytes]);
}

运行上述代码后,就会在控制台输出响应报文,内容如下:

HTTP/1.1 200 OK
Date: Sun, 28 Nov 2021 10:12:29 GMT
Server: Apache
Last-Modified: Sat, 31 Dec 2011 09:54:00 GMT
ETag: "1cdb-4b56054245e00"
Accept-Ranges: bytes
Content-Length: 7387
Cache-Control: max-age=86400
Expires: Mon, 29 Nov 2021 10:12:29 GMT
Connection: Keep-Alive
Content-Type: text/html

<!doctype html><html><head>....省略body具体内容

使用 URL 和 URLConnection

URL url = new URL("http://www.baidu.com");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
byte[] bytes = new byte[1024 * 8];
while (inputStream.read(bytes) >= 0) {
    System.out.println(new String(bytes));
}

输出结果如下:

<!DOCTYPE html>
<!--STATUS OK--><html> <head>......省略具体内容

通过对比使用 Socket 和 URL&URLConnection 可以发现,使用 Socket 我们需要自己添加请求头,自己确定服务器端口,自己解析响应报文;而使用 URL&URLConnection 的话,只需要请求地址就OK了,返回结果也直接是我们想要的内容。这也再次证明了 Socket 是属于传输层的为应用层提供服务,而 URL&URLConnection 是属于应用层的,将报文的组装与解析进行了封装,使用时无需关心。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注