网络协议 TCP\UDP、Socket 编程、Java 怎么处理 URL?(Java 从自学到就业 第17天)

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 则是连接开放端口并发送请求等待响应,输出结果如下:

java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
Exception in thread "main" java.net.ConnectException: Connection refused: connect

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();
        }
    }
}

输出结果如下:
AutoCloseable

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();
        }
    }
}

输出结果如下:

阅文集团——起点中文网



自学不易,点赞鼓励。

谢谢各位看官,如果有哪里写错的还望指出来哈,共同进步。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Only Double J

自学不易,希望鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值