Java 学习记录 第十七天
由于本渣渣是前端转行Java,所以编辑器的选择就直接用 webstorm 同公司的 idea
接下来的知识梳理有一部分会借鉴大佬 廖雪峰的博客
学习目标
了解 TCP \ UDP 网络协议,掌握Socket类、ServerSocket 类、InetAddress 类
学习内容
- TCP \ UDP 的区别
- 简述 Socket 编程
- 记录 ServerSocket 类的方法
- Socket 类的方法
- InetAddress 类的方法
- 编写简易的服务端服务与客户端服务
- URL 基础概念
- URL 类方法
- URLConnections 类方法
TCP \ UDP 的区别
什么是网络编程?网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
- TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
- UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。
简述 Socket 编程
套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立 TCP连接 时会出现:
- 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
- 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
- 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
- Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
- 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流
TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。
记录 ServerSocket 类的方法
服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。
ServerSocket 类有四个构造方法:
方法 | 描述 |
---|---|
public ServerSocket(int port) throws IOException | 创建绑定到特定端口的服务器套接字。 |
public ServerSocket(int port, int backlog) throws IOException | 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。 |
public ServerSocket(int port, int backlog, InetAddress address) throws IOException | 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。 |
public ServerSocket() throws IOException | 创建非绑定服务器套接字。 |
创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。
这里有一些 ServerSocket 类的常用方法:
方法 | 描述 |
---|---|
public int getLocalPort() | 返回此套接字在其上侦听的端口。 |
public Socket accept() throws IOException | 侦听并接受到此套接字的连接。 |
public void setSoTimeout(int timeout) | 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。 |
public void bind(SocketAddress host, int backlog) | 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
记录 Socket 类的方法
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。
Socket 类有五个构造方法.
方法 | 描述 |
---|---|
public Socket(String host, int port) throws UnknownHostException, IOException. | 创建一个流套接字并将其连接到指定主机上的指定端口号。 |
public Socket(InetAddress host, int port) throws IOException | 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 |
public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException. | 创建一个套接字并将其连接到指定远程主机上的指定远程端口。 |
public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException. | 创建一个套接字并将其连接到指定远程地址上的指定远程端口。 |
public Socket() | 通过系统默认类型的 SocketImpl 创建未连接套接字。 |
当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
下面列出部分方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。
方法 | 描述 |
---|---|
public void connect(SocketAddress host, int timeout) throws IOException | 将此套接字连接到服务器,并指定一个超时值。 |
public InetAddress getInetAddress() | 返回套接字连接的地址。 |
public int getPort() | 返回此套接字连接到的远程端口。 |
public int getLocalPort() | 返回此套接字绑定到的本地端口。 |
public SocketAddress getRemoteSocketAddress() | 返回此套接字连接的端点的地址,如果未连接则返回 null。 |
public InputStream getInputStream() throws IOException | 返回此套接字的输入流。 |
public OutputStream getOutputStream() throws IOException | 返回此套接字的输出流。 |
public void close() throws IOException | 关闭此套接字。 |
记录 InetAddress 类的方法
这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:
方法 | 描述 |
---|---|
static InetAddress getByAddress(byte[] addr) | 在给定原始 IP 地址的情况下,返回 InetAddress 对象。 |
static InetAddress getByAddress(String host, byte[] addr) | 根据提供的主机名和 IP 地址创建 InetAddress。 |
static InetAddress getByName(String host) | 在给定主机名的情况下确定主机的 IP 地址。 |
String getHostAddress() | 返回 IP 地址字符串(以文本表现形式)。 |
String getHostName() | 获取此 IP 地址的主机名。 |
static InetAddress getLocalHost() | 返回本地主机。 |
String toString() | 将此 IP 地址转换为 String。 |
编写简易的服务端服务与客户端服务
下面程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
class GreetingServer extends Thread {
private ServerSocket serverSocket;
public void run(){
while (true) {
try (
Socket server = serverSocket.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
) {
System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
System.out.println(in.readUTF());
out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
} catch (SocketTimeoutException e) {
System.out.println("超时报错:" + e);
break;
} catch (IOException e) {
System.out.println("io报错:" + e);
break;
}
}
}
public GreetingServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
}
public class Test2 {
public static void main(String[] args){
int port = 8088;
try {
Thread t = new GreetingServer(port);
t.run();
} catch (IOException e) {
e.printStackTrace();
}
}
}
下面是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应。
import java.io.*;
import java.net.Socket;
public class Test1 {
public static void main(String[] args) throws IOException {
String serverName = "localhost";
int port = 8088;
try (
Socket client = new Socket(serverName, port);
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
) {
System.out.println("连接主机:" + serverName + ",端口号:" + port);
System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
out.writeUTF("Hello from " + client.getLocalSocketAddress());
System.out.println("服务器响应:" + in.readUTF());
client.close();
}
}
}
Test2 是开启监听 服务端 8088 端口,Test1 则是连接开放端口并发送请求等待响应,输出结果如下:
URL 基础概念
URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者 FTP 地址。
URL 可以分为如下几个部分: protocol://host:port/path?query#fragment
protocol(协议)可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。
举个例子:https://book.qidian.com/info/1028612852?name=mingwentiandi#book
- 协议为(protocol):https
- 主机为(host:port):book.qidian.com
- 端口号为(port): https协议默认端口号为 443/tcp 443/udp ,以上URL实例并未指定端口取默认端口号。
- 文件路径为(path):/info/1028612852 后面的1028612852 是转成了Hash值
- 请求参数(query):name=mingwentiandi
- 定位位置(fragment):book,定位到网页中 id 属性为 book 的 HTML 元素位置 。
URL 类方法
在java.net包中定义了URL类,该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。
java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。
方法 | 描述 |
---|---|
public URL(String protocol, String host, int port, String file) throws MalformedURLException | 通过给定的参数(协议、主机名、端口号、文件名)创建URL。 |
public URL(String protocol, String host, String file) throws MalformedURLException | 使用指定的协议、主机名、文件名创建URL,端口使用协议的默认端口。 |
public URL(String url) throws MalformedURLException | 通过给定的URL字符串创建URL。 |
public URL(URL context, String url) throws MalformedURLException | 使用基地址和相对URL创建。 |
URL类中包含了很多方法用于访问URL的各个部分,具体方法及描述如下:
方法 | 描述 |
---|---|
public String getPath() | 返回URL路径部分。 |
public String getQuery() | 返回URL查询部分。 |
public String getAuthority() | 获取此 URL 的授权部分。 |
public int getPort() | 返回URL端口部分。 |
public int getDefaultPort() | 返回协议的默认端口号。 |
public String getProtocol() | 返回URL的协议。 |
public String getHost() | 返回URL的主机。 |
public String getFile() | 返回URL文件名部分。 |
public String getRef() | 获取此 URL 的锚点(也称为引用)。 |
public URLConnection openConnection() throws IOException | 打开一个URL连接,并运行客户端访问资源。 |
import java.io.IOException;
import java.net.URL;
public class Test3 {
public static void main(String[] args) throws IOException {
try {
URL url = new URL("https://book.qidian.com/info/1028612852?name=mingwentiandi#book");
System.out.println("URL 为:" + url.toString());
System.out.println("协议为:" + url.getProtocol());
System.out.println("验证信息为:" + url.getAuthority());
System.out.println("文件名及请求参数为:" + url.getFile());
System.out.println("主机名为:" + url.getHost());
System.out.println("路径为:" + url.getPath());
System.out.println("端口为:" + url.getPort());
System.out.println("默认端口为:" + url.getDefaultPort());
System.out.println("请求参数为:" + url.getQuery());
System.out.println("定位锚点为:" + url.getRef());
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果如下:
URLConnections 类方法
openConnection() 返回一个 java.net.URLConnection。例如:
- 如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
- 如果你连接HTTPS协议的URL, openConnection() 方法返回 HttpsURLConnection 对象。
- 如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。
URLConnection 方法列表如下:
方法 | 描述 |
---|---|
Object getContent() | 检索URL链接内容。 |
Object getContent(Class[] classes) | 检索URL链接内容。 |
String getContentEncoding() | 返回头部 content-encoding 字段值。 |
int getContentLength() | 返回头部 content-length字段值。 |
String getContentType() | 返回头部 content-type 字段值。 |
int getLastModified() | 返回头部 last-modified 字段值。 |
long getExpiration() | 返回头部 expires 字段值。 |
long getIfModifiedSince() | 返回对象的 ifModifiedSince 字段值。 |
public void setDoInput(boolean input) | URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true。 |
public void setDoOutput(boolean output) | URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false。 |
public InputStream getInputStream() throws IOException | 返回URL的输入流,用于读取资源。 |
public OutputStream getOutputStream() throws IOException | 返回URL的输出流, 用于写入资源。 |
public URL getURL() | 返回 URLConnection 对象连接的URL。 |
以下实例中URL采用了HTTPS 协议。 openConnection 返回HttpsURLConnection对象。
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class Test4 {
public static void main(String[] args) {
try {
URL url = new URL("https://book.qidian.com/info/1028612852?name=mingwentiandi#book");
URLConnection urlConnection = url.openConnection();
HttpsURLConnection connection = null;
if (urlConnection instanceof HttpsURLConnection) {
connection = (HttpsURLConnection) urlConnection;
System.out.println("HttpsURLConnection 对象:" + connection);
System.out.println("URL 链接内容:" + connection.getContent());
System.out.println("头部 content-encoding 字段值:" + connection.getContentEncoding());
System.out.println("头部 content-length 字段值:" + connection.getContentLength());
System.out.println("头部 content-type 字段值:" + connection.getContentType());
System.out.println("头部 last-modified 字段值:" + connection.getLastModified());
System.out.println("头部 expires 字段值:" + connection.getExpiration());
System.out.println("连接的 URL:" + connection.getURL());
} else {
System.out.println("请输入 URL 地址");
return;
}
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String urlString = "";
String current;
while ((current = in.readLine()) != null) {
urlString += "\n" + current;
}
System.out.println(urlString);
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果如下:
自学不易,点赞鼓励。
谢谢各位看官,如果有哪里写错的还望指出来哈,共同进步。