从网页连接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();
        }
    }
}
相关推荐
云飞云共享云桌面14 分钟前
东莞精密机械制造工厂如何10个SolidWorks共用一台服务器资源
java·运维·服务器·网络·数据库·电脑·制造
小此方16 分钟前
C语言自定义变量类型结构体理论:从初见到精通(上)
c语言·开发语言
毕设源码-赖学姐20 分钟前
【开题答辩全过程】以 网络药店管理系统为例,包含答辩的问题和答案
java·eclipse
努力也学不会java21 分钟前
【Java并发】揭秘Lock体系 -- 深入理解ReentrantReadWriteLock
java·开发语言·python·机器学习
埃泽漫笔34 分钟前
消息队列延迟与过期问题的实战解决
java·mq
vxtkjzxt88834 分钟前
自动化脚本矩阵运营
开发语言·php
王严培.44 分钟前
7.MATLAB疑难问题诊疗的技术
开发语言·matlab·信息可视化
花花无缺1 小时前
资源泄露问题
java·后端·http
wjs20241 小时前
PHP MySQL 使用 ORDER BY 排序查询
开发语言
爱敲代码的TOM1 小时前
深入剖析Java通信架构下的三种IO模式2
java·开发语言·架构