第2章 WebServer进阶

2.1 使用多线程处理多用户请求

2.1.1 多线程Socket通信

        在上一章的案例中,服务端显然只能处理一次浏览器请求,请求一次浏览器端就结束程序。如何解决这个问题呢?可以采用多线程Socket通信技术,解决多用户并发请求。

        在多线程Socket通信中,服务端会启动一个主线程用于监听客户端的连接请求,并为每个客户端连接请求创建一个新的子线程进行处理。这样可以保证服务端能够同时处理多个客户端的请求,提高系统的并发性能和稳定性。

        具体流程如下:

        1. 服务端启动主线程监听客户端的连接请求;

        2. 当有新的客户端连接请求时,主线程创建一个新的子线程来处理该客户端请求;

        3. 子线程接收客户端的请求信息,并根据请求内容进行相应的业务处理;

        4. 子线程将处理结果封装成响应报文发送给客户端;

        5. 子线程关闭连接,结束线程。

        这样,服务端就可以同时处理多个客户端请求,实现了高并发处理能力。同时,使用多线程编程也能提高代码的可维护性和可扩展性,减少代码耦合度。

2.1.2 使用多线程处理HTTP通信

        首先定义ClientHandler,作为线程处理HTTP请求和发生HTTP响应:

public class ClientHandler implements Runnable {private Socket socket;public ClientHandler(Socket clientSocket){socket = clientSocket;}@Overridepublic void run() {try {//从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。InputStream in = socket.getInputStream();StringBuilder builder= new StringBuilder();//   前一个字符  当前字符char previous = 0, current = 0;int b;while ((b=in.read())!=-1){//将读取的字节存储到当前字符, 由于请求头采用了ISO8859-1编码,// 所以可以讲字节直接转化为字符类型current = (char) b;//如果发现了 前一个字符是 \r 当前字符是 \n 就读取到了行末尾if (previous == '\r' && current == '\n'){//如果这一行是空行就结束处理了if (builder.toString().isEmpty()){break;}//输出这一行数据当前一行数据并且清空builder,为下次缓存数据做准备System.out.println(builder);builder.delete(0, builder.length());}else if (current != '\r' && current != '\n'){//当前的不是 \r \n 就是一行中的字符builder.append(current);}//最后将当前的字符作为下次的前一个字符previous = current;}OutputStream out = socket.getOutputStream();//一个简单的网页内容String html = "<html>\n" +"<head>\n" +"<title>Example</title>\n" +"</head>\n" +"<body>\n" +"<p>Hello World!</p>\n" +"</body>\n" +"</html>";byte[] body = html.getBytes(StandardCharsets.UTF_8);out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write("Content-Type: text/html; charset=utf-8".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write(("Content-Length: "+body.length).getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write('\r'); //空行out.write('\n');out.write(body);//关闭客户端连接out.close();in.close();}catch (IOException e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

        然后重构start()方法:

public class ServerBootApplication {private ServerSocket serverSocket;public void start(){try {//创建ServerSocket对象,并指定监听的端口号8088。serverSocket = new ServerSocket(8088);while (true) {//使用accept()方法等待客户端的连接请求,并获取客户端的Socket对象Socket clientSocket = serverSocket.accept();ClientHandler clientHandler = new ClientHandler(clientSocket);Thread thread = new Thread(clientHandler);thread.start();}}catch (IOException e){e.printStackTrace();}}public static void main(String[] args) {//创建ServerBoot对象ServerBootApplication application = new ServerBootApplication();//启动服务器application.start();}
}

        该代码是一个典型的多线程Socket通信的服务器端代码结构。在主线程中,创建了一个ServerSocket对象,并指定要监听的端口号8088。接着,通过一个while循环不断地使用accept()方法等待客户端的连接请求,一旦接收到请求,就会创建一个新的ClientHandler对象,将客户端的Socket对象传递给它,然后将ClientHandler对象封装成一个新的线程并启动,用于处理客户端的请求。在这个过程中,主线程一直保持监听状态,等待下一个客户端连接。

        为了处理多个客户端的并发请求,每个ClientHandler对象都运行在一个单独的线程中,这使得服务器可以同时处理多个客户端的请求,提高了系统的并发处理能力。

        经过上述重构我们的WebServer就可以处理多用户的并发请求了。

2.1.3 关于favicon.ico

        实现了多线程Web请求处理功能以后,控制台上出现了如下请求信息:

        由图可以看出:显然请求了favicon.ico文件。

        favicon.ico是一个网站上常见的文件,它是网站的图标文件,通常会显示在网站的标签页和书签上。当用户访问一个网站时,浏览器会自动请求这个文件,以便在标签页和书签上显示网站的图标。因此,在服务器的请求日志中,我们会看到很多关于 favicon.ico 的请求记录。这些请求记录是非常正常的现象,不必过于关注。

        理解这些请求信息有助于我们对网站访问进行监控和分析。通常情况下,这些请求不会对服务器性能产生重大影响,因为 favicon.ico 文件通常是相对较小的图标文件,并且浏览器会进行缓存,减少了对服务器的重复请求。

        因此,不必担心看到这些 favicon.ico 请求记录,除非你注意到在短时间内出现异常的请求量,这可能是有人在恶意攻击或者其他异常情况,需要进一步分析和处理。否则,这些请求是正常的,不需要特别处理。

2.2 解析请求行

2.2.1 解析请求行

        HTTP请求行是HTTP请求报文的第一行,包括HTTP方法、请求URL和HTTP协议版本号。例如:

GET /index.html HTTP/1.1

        其中,GET表示HTTP请求方法,/index.html表示请求的资源URL,HTTP/1.1表示使用的HTTP协议版本号。

        解析HTTP请求行可以获取请求方法、请求URL和协议版本等信息,这些信息对于服务器来说非常重要,可以根据这些信息对请求进行处理和响应。例如,根据请求URL可以确定请求的资源类型和位置,从而进行处理和响应;根据请求方法可以确定请求的类型(如GET、POST、PUT、DELETE等),从而采取相应的处理方式。因此,解析HTTP请求行是Web服务器处理HTTP请求的重要步骤之一。

        前述多线程的WebServer案例虽然能过处理用户请求,但是用户发起任何请求都会得到相同的响应结果,比如发送:http://localhost:8088/ 、http://localhost:8088/index.html和 http://localhost:8088/demo.html,都得到如下结果:

        这个结果显然不理想:不可能任何请求都返回相同的响应结果。正确情况应该是:请求index.html就显示index.html文件的内容,请求demo.index文件就显示demo.html的内容。

2.2.2 显示正确的请求内容

        如何解决这个问题呢?解决的办法就是将请求行进行解析,找出客户端发起的请求资源路径,根据请求资源的路径找到响应的资源,发送响应到客户端浏览器。这样就可以在用户请求不同资源时候,响应不同的结果:

2.2.3 读取请求行

        请求行在请求消息的第一行,请求行以\r\n为结尾,可以使用算法在读取请求头之前读取第一行作为请求行,如下代码可以读取请求的第一行:

InputStream in = socket.getInputStream();
StringBuilder builder= new StringBuilder();
//   前一个字符  当前字符
char previous = 0, current = 0;
int b;
String requestLine = null;
//解析请求行
while ((b=in.read())!=-1){current = (char) b;if (previous == '\r' && current == '\n'){requestLine = builder.toString();builder.delete(0, builder.length());break;}else if (current != '\r' && current != '\n'){builder.append(current);}previous = current;
}
System.out.println(requestLine);

        显然这个算法和读取请求头的代码是重复的,所以可以尝试将代码重构抽取一个从输入流中读取一行的方法:

public String readLine() throws IOException{InputStream in = socket.getInputStream();StringBuilder builder= new StringBuilder();//   前一个字符  当前字符char previous = 0, current = 0;int b;//解析请求行while ((b=in.read())!=-1){current = (char) b;if (previous == '\r' && current == '\n'){//遇到行结束就结束读取break;}else if (current != '\r' && current != '\n'){builder.append(current);}previous = current;}return builder.toString();
}

        这段代码的作用是从Socket的输入流中读取一行数据并返回。它通过InputStream获取Socket的输入流,然后使用一个StringBuilder对象来存储读取的数据,最终返回读取的数据。

        具体实现逻辑如下:

        1. 创建一个InputStream对象in,并将其设置为socket的输入流。

        2. 创建一个StringBuilder对象builder,用于存储读取的数据。

        3. 定义两个字符变量previous和current,用于记录前一个字符和当前字符。

        4. 定义一个int类型变量b,用于记录从输入流中读取的字节。

        5. 使用while循环从输入流中读取字节,直到读取完一行数据。

        6. 将读取到的字节转换成字符类型,并赋值给变量current。

        7. 判断当前字符是否为行结束符("\r\n"),如果是则退出循环,否则将当前字符添加到builder中。

        8. 将当前字符赋值给previous,以备下次循环使用。

        9. 循环结束后,将builder转换成字符串并返回。

        重构后的ClientHandler代码就清爽许多:

public class ClientHandler implements Runnable {private Socket socket;public ClientHandler(Socket clientSocket){socket = clientSocket;}@Overridepublic void run() {try {//从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。InputStream in = socket.getInputStream();//读取请求行String requestLine = readLine();System.out.println(requestLine);//读取请求头String requestHeader;//读取到空行就不在读取请求头了while (!(requestHeader = readLine()).isEmpty()){System.out.println(requestHeader);}OutputStream out = socket.getOutputStream();//一个简单的网页内容String html = "<html>\n" +"<head>\n" +"<title>Example</title>\n" +"</head>\n" +"<body>\n" +"<p>Hello World!</p>\n" +"</body>\n" +"</html>";byte[] body = html.getBytes(StandardCharsets.UTF_8);out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write("Content-Type: text/html; charset=utf-8".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write(("Content-Length: "+body.length).getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write('\r'); //空行out.write('\n');out.write(body);//关闭客户端连接out.close();in.close();}catch (IOException e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}/*** 这段代码的作用是从Socket的输入流中读取一行数据并返回。* @return 从Socket的输入流中读取一行数据并返回* @throws IOException 出现网络IO错误*/public String readLine() throws IOException{InputStream in = socket.getInputStream();StringBuilder builder= new StringBuilder();//   前一个字符  当前字符char previous = 0, current = 0;int b;//解析请求行while ((b=in.read())!=-1){current = (char) b;if (previous == '\r' && current == '\n'){//遇到行结束就结束读取break;}else if (current != '\r' && current != '\n'){builder.append(current);}previous = current;}return builder.toString();}
}

2.2.4 解析请求行

        上述代码实现了,读取请求行,读取后需要从请求行中解析其中的每个部分,然后可以根据请求行找到相应的本地文件资源,发送响应给浏览器,显示不同的资源内容。

        解析请求行:

String[] line = requestLine.split("\\s");
String method = line[0];
String uri = line[1];
String protocol = line[1];
System.out.println("method: "+method);
System.out.println("uri: " + uri);
System.out.println("protocol: " + protocol);

        这段代码用于解析HTTP请求报文中的请求行。首先,将请求行按照空白字符进行分割,得到一个包含请求方法、URI和协议版本三个字段的字符串数组。接着,将这三个字段分别存储到对应的变量中,并打印出来以供调试或其他用途。

        具体解释如下:

  • 使用String类的split()方法按照空白字符(包括空格、制表符和换行符)对请求行进行分割,得到一个包含请求方法、URI和协议版本三个字段的字符串数组line
  • 将line数组中的第一个元素存储到字符串变量method中,第二个元素存储到字符串变量uri中,第三个元素存储到字符串变量protocol中
  • 最后,使用System.out.println()方法打印出method、uri和protocol的值,方便调试和查看解析结果

        需要注意的是,该代码仅仅是对HTTP请求报文中的请求行进行了最基本的解析,仅适用于最简单的HTTP请求,对于复杂的HTTP请求报文,需要进行更加严谨和完整的解析。

        重新启动后服务端后,用浏览器发起 http://localhost:8088/index.html 请求,控制台信息包含如下信息:

        这个信息表示请求行解析成功。

2.3 响应静态资源

2.3.1 创建静态资源

        前述项目完成了解析请求行,从请求行中得到了请求资源的路径URI,为了能响应客户端需求,返回对应的资源,所以要建立静态文件夹存储静态资源:

        index.html 文件是一个html文件,格式类似于html,内容如下:

<!DOCTYPE html>
<html lang="cn">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>Hello World</h1>
</body>
</html>

        demo.html 文件内容如下:

<!DOCTYPE html>
<html lang="cn">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>Demo Page</h1>
</body>
</html>

        有了这了两个资源,就可以实现根据用户请求的uri,找到这两个资源,并且发送到响应到浏览器,实现根据用户请求响应不同文件的功能。

2.3.2 响应静态资源

        重构服务端代码,根据URI在resources/static文件夹中找到静态资源,并且将静态资源响应给客户端,原理为:

2.3.3 响应静态资源

        重构后的代码:

//发送响应
//根据找到静态资源
//类加载路径:target/classes
File root = new File(ClientHandler.class.getClassLoader().getResource(".").toURI()
);
//定位target/classes/static目录(SpringBoot中存放所有静态资源的目录)
File staticDir = new File(root,"static");
//定位target/classes/static目录中的文件
File file = new File(staticDir,uri);
//读取文件的全部内容
byte[] bytes = new byte[(int)file.length()];
FileInputStream fin = new FileInputStream(file);
fin.read(bytes);
fin.close();OutputStream out = socket.getOutputStream();out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write("Content-Type: text/html; charset=utf-8".getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write(("Content-Length: "+bytes.length).getBytes(StandardCharsets.ISO_8859_1));
out.write('\r');
out.write('\n');
out.write('\r'); //空行
out.write('\n');
out.write(bytes);
//关闭客户端连接
out.close();
in.close();

        这段代码是一个简单的HTTP服务器响应客户端请求的部分,主要功能是根据请求的URI定位服务器上的静态资源,并将其发送给客户端。

        具体来说,代码首先根据当前类的类加载器获取类加载路径,然后根据该路径找到服务器上的静态资源所在目录。接着,根据URI定位静态资源文件,并读取该文件的全部内容到一个字节数组中。

        然后,代码使用Java的Socket API将HTTP响应发送给客户端。响应包括HTTP响应头和响应体两部分。响应头中包含HTTP协议版本、状态码和响应内容类型等信息,而响应体则包含实际的静态资源内容。发送响应的代码使用OutputStream将响应数据写入到客户端的Socket连接中,并在最后关闭客户端连接。

        完成的ClientHandler参考如下:

public class ClientHandler implements Runnable {private Socket socket;public ClientHandler(Socket clientSocket){socket = clientSocket;}@Overridepublic void run() {try {//从客户端Socket对象中获取输入流,读取HTTP请求报文(请求消息)。InputStream in = socket.getInputStream();//读取请求行String requestLine = readLine();System.out.println(requestLine);//解析请求行String[] line = requestLine.split("\\s");String method = line[0];String uri = line[1];String protocol = line[1];System.out.println("method: "+method);System.out.println("uri: " + uri);System.out.println("protocol: " + protocol);//读取请求头String requestHeader;//读取到空行就不在读取请求头了while (!(requestHeader = readLine()).isEmpty()){System.out.println(requestHeader);}//发送响应//根据找到静态资源//类加载路径:target/classesFile root = new File(ClientHandler.class.getClassLoader().getResource(".").toURI());//定位target/classes/static目录(SpringBoot中存放所有静态资源的目录)File staticDir = new File(root,"static");//定位target/classes/static目录中的文件File file = new File(staticDir,uri);//读取文件的全部内容byte[] bytes = new byte[(int)file.length()];FileInputStream fin = new FileInputStream(file);fin.read(bytes);fin.close();OutputStream out = socket.getOutputStream();out.write("HTTP/1.1 200 OK".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write("Content-Type: text/html; charset=utf-8".getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write(("Content-Length: "+bytes.length).getBytes(StandardCharsets.ISO_8859_1));out.write('\r');out.write('\n');out.write('\r'); //空行out.write('\n');out.write(bytes);//关闭客户端连接out.close();in.close();}catch (IOException | URISyntaxException e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}/*** 这段代码的作用是从Socket的输入流中读取一行数据并返回。它通过InputStream获取Socket的输入流,* 然后使用一个StringBuilder对象来存储读取的数据,最终返回读取的数据。* @return 从Socket的输入流中读取一行数据并返回* @throws IOException 出现网络IO错误*/public String readLine() throws IOException{InputStream in = socket.getInputStream();StringBuilder builder= new StringBuilder();//   前一个字符  当前字符char previous = 0, current = 0;int b;//解析请求行while ((b=in.read())!=-1){current = (char) b;if (previous == '\r' && current == '\n'){//遇到行结束就结束读取break;}else if (current != '\r' && current != '\n'){builder.append(current);}previous = current;}return builder.toString();}
}

2.3.4 HTTP协议补充

        HTTP(Hypertext Transfer Protocol)是一种用于在计算机网络上传输超文本数据的协议。它是Web应用程序中最基本的通信协议,用于在客户端(例如浏览器)和服务器之间传输数据。

        HTTP的主要特点包括:

  • 状态无关:HTTP是一种无状态协议,即服务器不会记录客户端之前的请求信息。每个HTTP请求都是独立的,服务器不会保留客户端的状态信息,这样可以降低服务器的负担,也使得HTTP协议具有良好的扩展性。
  • 请求-响应模型:HTTP是基于请求-响应模型的协议。客户端发送HTTP请求到服务器,然后服务器返回HTTP响应。请求包括请求方法(GET、POST等)、请求头、请求体等信息,响应包括状态码、响应头、响应体等信息。
  • 可靠性:HTTP在传输过程中使用TCP协议作为传输层协议,因此具有可靠性。TCP协议会确保数据的正确传输和接收,如果数据丢失或损坏,TCP会自动重传。
  • 简单灵活:HTTP协议采用文本形式传输数据,易于阅读和调试。同时,HTTP协议也非常灵活,可以传输不同类型的数据,支持多种编码和内容类型。
  • 支持缓存:HTTP协议支持缓存机制,通过在响应中添加缓存相关的头信息,可以让浏览器在下次请求相同资源时直接从缓存中获取,提高性能和加载速度。

        HTTP协议的工作方式是客户端向服务器发送请求,服务器根据请求进行处理并返回响应。客户端和服务器通过URL(统一资源定位符)来定位资源,URL由协议类型(例如http)、服务器地址和资源路径组成。

        HTTP协议是Web开发中非常重要的基础,它使得浏览器能够请求并获取Web页面、图片、视频、文件等资源,并实现了Web应用程序的交互性。同时,HTTP也不断发展,出现了新的版本,例如HTTP/1.1和HTTP/2,以满足不断增长的Web应用需求。

2.3.5 幂等性

        在计算机科学和网络编程中,幂等性(Idempotence)是指对同一个操作进行一次或多次的操作,产生的结果是相同的。换句话说,无论对一个操作进行多少次重复,其结果都是一致的。

        幂等性在计算机系统设计和网络通信中具有重要意义,特别是在处理故障、网络延迟或重试等情况下。幂等性操作保证了系统对相同请求的重复处理不会导致副作用或错误结果。

        举个简单的例子,假设有一个用于更新用户信息的API接口。如果这个API是幂等的,那么当多个请求同时更新同一个用户信息时,无论请求执行多少次,最终用户的信息都只会更新一次,而不会因为重复的请求导致用户信息被错误地更新多次。

        在实际应用中,一些常见的幂等性操作包括:

  • GET请求:GET请求是幂等的,因为对于同一个URL的GET请求,无论请求执行多少次,都只会返回相同的响应结果,不会对服务器产生任何副作用。
  • PUT请求:PUT请求通常用于更新资源,在幂等性的设计下,对于同一个URL的PUT请求,重复执行对资源的更新操作将得到相同的结果。
  • DELETE请求:DELETE请求通常用于删除资源,在幂等性的设计下,对于同一个URL的DELETE请求,重复执行对资源的删除操作将得到相同的结果。

        幂等性的接口设计:在设计API接口时,如果接口的操作具有幂等性,可以增强系统的稳定性和可靠性。通过一些设计措施,比如生成唯一的请求标识,对于相同的请求标识只处理一次,就能实现幂等性。

        总的来说,幂等性操作对于构建健壮和可靠的系统非常重要,可以避免重复操作导致的不一致性和错误结果。在网络通信中,幂等性的操作可以增加系统的容错性,确保请求的可靠传输和正确处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/833967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从谚语:“一手交钱,一手交货来”谈谈什么是数据库事务

事务与交易 一手交钱&#xff0c;一手交货 一手交钱&#xff0c;一手交货&#xff0c;谚语&#xff0c;意思是指钱和货当场相交&#xff0c;互不拖欠。出自明朝施耐庵《水浒传》第二一回。 Transaction 意思 我们先来看一下来自于剑桥英-英词典的解释&#xff1a; transac…

matlab中interp2函数应用

interp2 函数在 MATLAB 中用于进行二维插值。当使用 nearest 选项时&#xff0c;它会执行最近邻插值&#xff0c;即对于给定的目标点&#xff0c;函数将选择网格中距离其最近的点的值作为该目标点的插值结果。 以下是 interp2 函数在 nearest 模式下的用法示例&#xff0c;以及…

Flask-HTTP请求、响应、上下文、进阶实验

本节主要目录如下&#xff1a; 一、请求响应循环 二、HTTP请求 2.1、请求报文 2.2、Request对象 2.3、在Flask中处理请求 2.4、请求钩子 三、HTTP响应 3.1、响应报文 3.2、在Flask中生成响应 3.3、响应格式 3.4、Cookie 3.5、session&#xff1a;安全的Cookie 四、…

企业车辆管理系统参考论文(论文 + 源码)

【免费】关于企业车辆管理系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89282550 企业车辆管理系统 摘 要 随着经济的日益增长,车辆作为最重要的交通工具,在企事业单位中得以普及,单位的车辆数目已经远远不止简单的几辆,与此同时就产生了车辆资源的合理…

Codeforces Round 940 (Div. 2) and CodeCraft-23 D. A BIT of an Inequality

A BIT of an Inequality 题目描述 给你一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​ 。求这样的图元&#xff08; x , y , z x, y, z x,y,z &#xff09;的个数&#xff1a; 1 ≤ x ≤ y ≤ z ≤ n 1 \leq x \leq y \leq z \leq n 1≤x≤y≤z≤…

汽车灯罩一般都是用什么材质做的?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

汽车灯罩一般都是用什么材质做的&#xff1f; 汽车灯罩一般使用的主要材质是聚碳酸酯&#xff08;PC&#xff09;和丙烯酸酯&#xff08;PMMA&#xff09;这两种塑料。这两种材料具有良好的透明性、耐候性和耐冲击性&#xff0c;因此非常适合用于汽车灯罩的制造。 聚碳酸酯&am…

小程序支付的款项流转与到账时间

商家做小程序&#xff0c;最关心的是客户通过小程序下单支付的钱&#xff0c;是怎么样的流转状态以及最终到哪里。因此&#xff0c;本文将详细解析款项最终流向何处以及多久能够到账。 一、小程序支付的款项流向 当用户在小程序内完成支付后&#xff0c;款项并不会直接到达商…

5月8日学习记录

_[FBCTF2019]RCEService&#xff08;preg_match函数的绕过&#xff09; 涉及知识点&#xff1a;preg_match函数绕过&#xff0c;json的格式&#xff0c;正则回溯 打开环境&#xff0c;要求用json的格式输入 搜索学习一下json的语法规则 数组&#xff08;Array&#xff09;用方括…

Map-Reduce是个什么东东?

MapReduce是一种用于使用并行分布式算法在集群计算机上处理大型数据集的编程模型及其相关实现。这一概念首先由Google普及&#xff0c;并随后作为Apache Hadoop项目的一部分开源发布。 MapReduce的基本工作流程&#xff1a; 映射(Mapping)&#xff1a;这是第一阶段&#xff0c…

制造版图大变革!逾10座晶圆厂蓄势待发 | 百能云芯

在全球半导体产业的激烈竞争和市场需求的复杂波动中&#xff0c;晶圆厂建设热潮正在美国兴起&#xff0c;这一波建设浪潮的核心动力之一&#xff0c;便是美国政府推出的《芯片与科学法案》所承诺的巨额补贴&#xff0c;旨在提升美国在全球半导体行业的竞争力。 当地时间4月25日…

嵌入式—模块代码(一)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 程序结构GPIO操作UART操作接收逻辑发送 以下模板代码均基于官方2023.07.17版本。 程序结构 #include "Config.h" #inc…

JSP技术讲解

目录 1、JSP简介 2、JSP体验 3、JSP运行原理 4、JSP基本语法 5、JSP指令 6、JSP内置九大对象 7、JSP标签 8、JSP配置 9、JSP排错 10、总结 在前面的Servlet学习中发现Servlet本质是一个java程序&#xff0c;因此Servlet更加擅长编写程序的业务逻辑&#xff0c;而如果要…

部署kafka后启动报错(坑):无法指定被请求的地址

启动kafka后报错&#xff1a;org.apache.kafka.common.KafkaException: Socket server failed to bind to 127.0.0.1:9092: 无法指定被请求的地址 1、编辑配置文件 vim config/server.properties 2、在listeners PLAINTEXT://your.host.name:9092下方添加服务器内外网地址配…

shpfile转GeoJSON;控制shp转GeoJSON的精度;如何获取GeoJSON;GeoJSON是什么有什么用;GeoJSON结构详解(带数据示例)

目录 一、GeoJSON是什么 二、GeoJSON的结构组成 2.1、点&#xff08;Point&#xff09;数据示例 2.2、线&#xff08;LineString&#xff09;数据示例 2.3、面&#xff08;Polygon&#xff09;数据示例 2.4、特征&#xff08;Feature&#xff09;数据示例 2.5、特征集合&…

Hass哈斯数控数据采集网络IP配置设置

机床数据采集&#xff08;MDC&#xff09;允许你使用Q和E命令通过网络接口或选项无线网络从控制系统提取数据。设置143支持该功能&#xff0c;并且指定控制器使用这个数据端口。MDC是一个需要一台附加计算机发送请求&#xff0c;解释说明和存储机床数据的软件功能。这个远程计算…

android 预加载进程

目录 一.背景 二.实现 1. 创建预加载服务类 2.清单文件中注册并制定 android:process 要预加载的进程 3.开启和停止 一.背景 做阅读器独立进程时&#xff0c;打开阅读器阅读页面所在的Activity&#xff0c;会出现白屏或黑屏 也就是说从一个进程activity跳转另一个进程的a…

【计算机毕业设计】基于SSM++jsp的电子竞技管理平台【源码+lw+部署文档+讲解】

目录 1 绪论 1.1 研究背景 1.2 目的和意义 1.3 论文结构安排 2 相关技术 2.1 SSM框架介绍 2.2 B/S结构介绍 2.3 Mysql数据库介绍 3 系统分析 3.1 系统可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 运行可行性分析 3.2 系统性能分析 3.2.1 易用性指标 3.2.2 可…

明明是工作经验越久越吃香,为什么程序员却不是?

一般3年左右经验的程序员&#xff0c;了解到了这个行业的一些上升渠道和方法&#xff0c;其实也能发现&#xff0c;程序员也能得熬资历的&#xff0c;说通俗点也是越老越值钱。 比如当下有1年经验和3年经验的程序员&#xff0c;哪怕都是小公司背景&#xff0c;会发现工作年限越…

JavaScript数字分隔符

● 如果现在我们用一个很大的数字&#xff0c;例如2300000000&#xff0c;这样真的不便于我们进行阅读&#xff0c;我们希望用千位分隔符来隔开它&#xff0c;例如230,000,000; ● 下面我们使用_当作分隔符来尝试一下 const diameter 287_266_000_000; console.log(diameter)…

负载或反向代理服务器如何配置XFF以获取终端真实IP

文章目录 XFF介绍工作原理注意事项 配置方式1. Nginx2. HAProxy3. F5 BIG-IP4. Radware注意事项 本文介绍如何在反向代理或负载中配置XFF&#xff0c;方便后端服务获取请求来源的真实IP XFF介绍 X-Forwarded-For&#xff08;简称XFF&#xff09;是一个非标准的HTTP头部字段&a…