从网页连接socket服务器和I/O

1.i/o

InputStreamInputStreamReader是Java I/O类库中的两个关键类,用于处理字节流。它们的主要区别在于它们处理数据的方式。

InputStream:

  • InputStream是用于读取字节流的抽象类。它是所有字节输入流类的父类。
  • InputStream的子类可以从不同的数据源读取字节,例如文件、网络连接、内存等。
  • 它提供了基本的字节读取方法,如read(),用于读取单个字节,以及read(byte[] b),用于读取一组字节。
java 复制代码
InputStream inputStream = new FileInputStream("example.txt");
int data = inputStream.read(); // 读取单个字节
byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer); // 读取一组字节

FileInputStream

FileInputStreamInputStream 类的一种具体实现,它专门用于从文件中读取字节。下面是 FileInputStreamInputStream 的主要区别:

  1. 特定用途:

    • InputStream 是一个抽象类,用于表示字节输入流的基本接口,但它本身不能直接实例化。它有多个具体的实现类,包括 FileInputStream。(所以InputStream inputStream = new FileInputStream("example.txt");是多态的体现)
    • FileInputStreamInputStream 的一个具体实现,它通过文件系统读取字节流。
  2. 用法:

    • InputStream 可以用于从各种来源读取字节,例如文件、网络连接、字节数组等。
    • FileInputStream 专门用于从文件中读取字节。你需要提供文件路径或文件对象作为构造函数的参数。
  3. 构造方法:

    • FileInputStream 的构造方法需要一个表示文件路径的字符串或者一个 File 对象。例如:new FileInputStream("example.txt")new FileInputStream(new File("example.txt"))
    • InputStream 本身不能直接实例化,因为它是一个抽象类。你需要使用其具体实现类之一来创建对象。
  4. 异常处理:

    • FileInputStream 的构造方法和读取方法都可能抛出 IOException,因此在使用时需要进行异常处理。
    • InputStream 的一些方法也可能抛出 IOException

InputStreamReader:

  • InputStreamReaderReader类的子类,它是用于读取字符流的桥梁,将字节流转换为字符流。
  • 它接受一个InputStream作为参数,将字节流转换为字符流,并提供了字符读取方法,如read()read(char[] cbuf)
  • InputStreamReader处理字符的方式是根据指定的字符编码将字节转换为字符。
java 复制代码
InputStream inputStream = new FileInputStream("example.txt");
Reader reader = new InputStreamReader(inputStream, "UTF-8");
int charData = reader.read(); // 读取单个字符
char[] charBuffer = new char[1024];
int charsRead = reader.read(charBuffer); // 读取一组字符

BufferedReader:

  • BufferedReaderReader类的装饰器,用于缓冲字符输入。它提供了缓冲功能,可以一次读取多个字符,以提高读取性能。
  • BufferedReader通常用于包装其他Reader,例如FileReaderInputStreamReader,以提供缓冲的字符读取。
java 复制代码
InputStream inputStream = new FileInputStream("example.txt");
Reader reader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(reader);

OutputStreamWriter :

OutputStreamWriter是Java I/O类库中的一个类,用于将字符流转换为字节流。它是Writer类的子类,允许你按字符而不是字节写入数据到输出流中,并且可以指定字符编码。

主要特点:

  1. 字符到字节的转换: OutputStreamWriter将字符数据转换为字节数据,然后将字节写入底层的输出流。

  2. 字符编码: 你可以在创建OutputStreamWriter时指定字符编码。这是非常重要的,特别是在处理文本数据时,因为它影响了字符到字节的映射。

java 复制代码
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class OutputStreamWriterExample {
    public static void main(String[] args) {
        try {
            // 创建一个字节输出流
            FileOutputStream fileOutputStream = new FileOutputStream("output.txt");

            // 创建OutputStreamWriter并指定字符编码
            Writer writer = new OutputStreamWriter(fileOutputStream, "UTF-8");

            // 写入字符数据
            writer.write("Hello, OutputStreamWriter!");

            // 关闭流
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.从网页连接socket服务器和I/O

之前我们都是通过自己写的client类连接server的,现在我们通过浏览器来连接server。

连接时,在浏览器里输入http://localhost:8080

当我们从浏览器访问自己写的服务器时,浏览器(也就是客户端)会向服务器发送请求,我们可以通过socket的输入流来接受并打印这些请求的内容:

java 复制代码
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            String line;
            //如果读到的字符串不为空,就打印。为空,则跳出循环
            while(!((line=bufferedReader.readLine()).isEmpty())){
                System.out.println(line);
            }

line里的内容就是请求的内容:

GET / HTTP/1.1

Host: localhost:8080

Connection: keep-alive

Cache-Control: max-age=0

sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"

sec-ch-ua-mobile: ?0

sec-ch-ua-platform: "Windows"

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Sec-Fetch-Site: none

Sec-Fetch-Mode: navigate

Sec-Fetch-User: ?1

Sec-Fetch-Dest: document

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5

然后我们还可以向客户端返回数据:

java 复制代码
OutputStreamWriter writer=new OutputStreamWriter(socket1.getOutputStream()); 
writer.write("HTTP/1.1 200 Accepted\r\n");

            //在响应头写完后一定要再换行才能写我们的响应体(在浏览器上展示的部分)
            writer.write("\r\n");
            //响应的内容
            writer.write("lyjnb");
            writer.flush();
            socket1.close();

其中,

复制代码
"HTTP/1.1 200 Accepted\r\n" 是 HTTP 协议中的响应头。
"HTTP/1.1" 表示使用的是 HTTP 1.1 版本。
"200" 是响应状态码,表示请求被成功处理。
"Accepted" 是状态码的描述,表示请求已被接受。
最后的 "\r\n" 是回车和换行符,表示行结束符,HTTP 协议要求在头部信息的每一行末尾使用这个组合。

最后我们得到的效果:

java 复制代码
package socket3_browser_to_socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String args[]){
        try(ServerSocket socket=new ServerSocket(8080)){
            System.out.println("waiting for client...");
            Socket socket1=socket.accept();
            System.out.println("already connected, ip address:"+socket1.getInetAddress().getHostAddress());
            InputStream inputStream=socket1.getInputStream();
            System.out.println("data received:");

            //BufferedReader是Reader类的装饰器,用于缓冲字符输入。它提供了缓冲功能,可以一次读取多个字符,以提高读取性能。
            //InputStreamReader是Reader类的子类,它是用于读取字符流的桥梁,将字节流转换为字符流。
            //InputStream是用于读取字节流的抽象类。它是所有字节输入流类的父类。
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            String line;
            //如果读到的字符串不为空,就打印。为空,则跳出循环
            while(!((line=bufferedReader.readLine()).isEmpty())){
                System.out.println(line);
            }
            OutputStreamWriter writer=new OutputStreamWriter(socket1.getOutputStream());

            //"HTTP/1.1 200 Accepted\r\n" 是 HTTP 协议中的响应头。
            //"HTTP/1.1" 表示使用的是 HTTP 1.1 版本。
            //"200" 是响应状态码,表示请求被成功处理。
            //"Accepted" 是状态码的描述,表示请求已被接受。
            //最后的 "\r\n" 是回车和换行符,表示行结束符,HTTP 协议要求在头部信息的每一行末尾使用这个组合。
            writer.write("HTTP/1.1 200 Accepted\r\n");

            //在响应头写完后一定要再换行才能写我们的响应体(在浏览器上展示的部分)
            writer.write("\r\n");
            //响应的内容
            writer.write("lyjnb");
            writer.flush();
            socket1.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
相关推荐
芊寻(嵌入式)13 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
WaaTong15 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484415 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries17 分钟前
Java字节码增强库ByteBuddy
java·后端
一颗松鼠22 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_24 分钟前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
海阔天空_201329 分钟前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
天下皆白_唯我独黑36 分钟前
php 使用qrcode制作二维码图片
开发语言·php
小灰灰__37 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭40 分钟前
Java中的动态代理
java·开发语言·aop·动态代理