实现 B/S 服务器

先看一个简单例子:



package demo.net.bs_demo;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class BaseDemo {
	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(8000);
		Socket socket = server.accept();
		InputStream in = socket.getInputStream();
		byte[] bytes = new byte[1024];
		int len = in.read(bytes);
		System.out.println(new String(bytes,0,len));
		socket.close();
		server.close();
	}
}



在浏览器访问: http://localhost:8000/ 后,服务器端输出如下:



GET / HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.1778445080.1563089064; csrftoken=ZnWKg5ZuuSYd3dwts5iqnfjQvSnp21n9OiuFZAKz11WdGZuXENLhAxYckiLHFTsI



接下来是一个处理浏览器的访问请求,并返回请求页面的服务器端代码

页面放在和 src 同级的目录 webDemo 下



package demo.net.bs_demo;

import java.io.IOException;
import java.net.*;
import java.io.*;

public class BrowserServer {
	public static void main(String[] args) throws IOException {
		//创建一个服务器ServerSocket,和系统要指定的端口号
		ServerSocket server = new ServerSocket(8080);
		//使用accept方法获取到请求的客户端对象(浏览器)
		Socket socket = server.accept();
		//使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
		InputStream is = socket.getInputStream();
		//使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
		/*byte[] bytes = new byte[1024];
		int len = 0;
		while((len = is.read(bytes))!=-1){
			System.out.println(new String(bytes,0,len));
		}*/

		//把is网络字节输入流对象,转换为字符缓冲输入流,使用缓冲流更快
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		//把客户端请求信息的第一行读取出来 "GET /webDemo/index.html HTTP/1.1"
		String line = br.readLine();
		//System.out.println(line);
		//把读取的信息进行切割,只要中间部分 "/webDemo/index.html"
		String[] arr = line.split(" ");
		//把路径前边的/去掉,进行截取 "webDemo/index.html"
		String htmlpath = arr[1].substring(1);
		//System.out.println(htmlpath);
		//创建一个本地字节输入流,构造方法中绑定要读取的html路径
		FileInputStream fis = new FileInputStream(htmlpath);
		//使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
		OutputStream os = socket.getOutputStream();

		// 写入HTTP协议响应头,固定写法
		os.write("HTTP/1.1 200 OKrn".getBytes());
		os.write("Content-Type:text/htmlrn".getBytes());
		// 必须要写入空行,否则浏览器不解析
		os.write("rn".getBytes());

		//一读一写复制文件,把服务读取的html文件回写到客户端
		int len = 0;
		byte[] bytes = new byte[1024];
		while((len = fis.read(bytes))!=-1){
			os.write(bytes,0,len);
		}

		//释放资源
		fis.close();
		socket.close();
		server.close();
	}
}



在浏览器访问:http://localhost:8080/webDemo/index.html,会出现相应的页面,但页面中的图片显示不正常



发现浏览器中出现很多的叉子,说明浏览器没有读取到图片信息导致。
浏览器工作原理是遇到图片会开启一个线程进行单独的访问,因此在服务器端加入线程技术。





java socket read 数据末尾无法接收 java socket read time out_截取某服务器的请求


优化后的服务器端代码如下:


package demo.net.bs_demo;

import java.io.*;
import java.net.*;

public class BrowserServerThread {
	public static void main(String[] args) throws IOException {
		//创建一个服务器ServerSocket,和系统要指定的端口号
		ServerSocket server = new ServerSocket(8080);
		System.out.println("服务器启动 ...");
		/*
			浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
			我们就的让服务器一直处于监听状态,客户端请求一次,服务器就回写一次
		 */
		while(true){
			//使用accept方法获取到请求的客户端对象(浏览器)
			Socket socket = server.accept();
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						//使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
						InputStream is = socket.getInputStream();
						//使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
						/*byte[] bytes = new byte[1024];
						int len = 0;
						while((len = is.read(bytes))!=-1){
							System.out.println(new String(bytes,0,len));
						}*/

						//把is网络字节输入流对象,转换为字符缓冲输入流,使用缓冲流更快
						BufferedReader br = new BufferedReader(new InputStreamReader(is));
						//把客户端请求信息的第一行读取出来 "GET /webDemo/index.html HTTP/1.1"
						String line = br.readLine();
						//System.out.println(line);
						//把读取的信息进行切割,只要中间部分 "/webDemo/index.html"
						String[] arr = line.split(" ");
						//把路径前边的/去掉,进行截取 "webDemo/index.html"
						String htmlpath = arr[1].substring(1);
						//System.out.println(htmlpath);
						//创建一个本地字节输入流,构造方法中绑定要读取的html路径
						FileInputStream fis = new FileInputStream(htmlpath);
						//使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
						OutputStream os = socket.getOutputStream();

						// 写入HTTP协议响应头,固定写法
						os.write("HTTP/1.1 200 OKrn".getBytes());
						os.write("Content-Type:text/htmlrn".getBytes());
						// 必须要写入空行,否则浏览器不解析
						os.write("rn".getBytes());

						//一读一写复制文件,把服务读取的html文件回写到客户端
						int len = 0;
						byte[] bytes = new byte[1024];
						while((len = fis.read(bytes))!=-1){
							os.write(bytes,0,len);
						}

						//释放资源
						fis.close();
						socket.close();
					}catch (IOException e){
						e.printStackTrace();
					}
				}
			}).start();


		}


		//server.close();
	}
}


再次在浏览器访问:http://localhost:8080/webDemo/index.html,会出现相应的页面,并且页面中的图片显示正常


java socket read 数据末尾无法接收 java socket read time out_html_02


如果觉得文章报错的话,麻烦动动小手点赞哟

中秋假期结束,明天继续上班、学习、睡觉、地铁、吃饭的无限循环

2019.09.15 23:55

假期终于把之前学习的知识全部整理完了

以下是在公司内网本部分的学习记录,无奈网络隔离,只能上图片了


java socket read 数据末尾无法接收 java socket read time out_输入流_03


java socket read 数据末尾无法接收 java socket read time out_输入流_04


java socket read 数据末尾无法接收 java socket read time out_输入流_05


java socket read 数据末尾无法接收 java socket read time out_html_06


java socket read 数据末尾无法接收 java socket read time out_截取某服务器的请求_07