CS架构(Client-Server Architecture)和BS架构(Browser-Server Architecture)是两种常见的软件架构模式,用于描述客户端和服务器之间的关系。
- CS架构是指客户端-服务器架构,也称为两层架构。
- 在CS架构中,客户端和服务器是分离的实体,彼此独立运行。
- 客户端负责用户界面和用户交互,服务器负责处理业务逻辑和数据存储。
- 客户端通过网络连接(如Socket)与服务器通信,发送请求并接收响应。
- 通常,客户端可以是桌面应用程序、移动应用程序等。
- BS架构是指浏览器-服务器架构,也称为三层架构或Web架构。
- 在BS架构中,客户端使用浏览器作为用户界面,服务器负责处理业务逻辑和数据存储。
- 客户端通过HTTP协议向服务器发送请求,并接收由服务器生成的HTML、CSS、JavaScript等Web资源。
- 服务器端通常是Web服务器(如Apache、Nginx等)和应用服务器(如Tomcat、Node.js等)的组合。
- 通常,BS架构用于Web应用程序和互联网上的服务。
- CS架构中,客户端与服务器之间的通信是通过自定义的协议进行的,而BS架构中,客户端与服务器之间的通信是通过标准的HTTP协议进行的。
- CS架构通常需要在客户端上安装专门的应用程序,而BS架构则可以直接通过浏览器访问。
- CS架构相对于BS架构来说,更加灵活,可以实现更复杂的业务逻辑和用户界面,但需要开发和部署客户端应用。
- BS架构相对于CS架构来说,更加简单、易于维护和更新,但难以实现复杂的用户界面和交互。
在实际应用中,可以根据具体需求和场景选择使用CS架构或BS架构,或者两者结合使用,以满足不同的业务需求和用户体验要求。
1. 客户端发送请求:客户端发送请求到服务器,请求可以是获取数据、执行操作或其他需要服务器处理的任务。
2. 服务器接收请求:服务器接收来自客户端的请求,并准备处理请求。
3. 服务器处理请求:服务器根据请求的类型和内容,执行相应的业务逻辑和处理操作。
4. 服务器生成响应:服务器生成响应数据,包括请求的结果、数据、状态信息或其他需要返回给客户端的内容。
5. 服务器发送响应:服务器将生成的响应数据发送给客户端。
6. 客户端接收响应:客户端接收服务器发送的响应数据。
7. 客户端处理响应:客户端根据服务器返回的响应内容进行处理,可能包括显示结果、更新界面、触发相关事件等。
1. 客户端类型:在CS架构中,客户端可以是任何类型的应用程序,例如桌面应用程序、移动应用程序等。而在BS架构中,客户端通常是Web浏览器。
2. 通信方式:在CS架构中,客户端和服务器之间的通信可以使用各种协议和通信方式,例如TCP/IP、HTTP、WebSocket等。而在BS架构中,通信通常基于HTTP协议。
3. 客户端处理能力:在CS架构中,客户端可以拥有更多的处理能力和功能,可以进行大部分的计算和业务逻辑。而在BS架构中,客户端通常只负责显示和交互,大部分的计算和业务逻辑由服务器处理。
4. 跨平台性:BS架构由于依赖Web浏览器作为客户端,具有较好的跨平台性,可以在不同的操作系统和设备上运行。而CS架构的客户端需要适配不同的操作系统和设备,对跨平台支持要求较高。
需要根据具体的应用场景和需求选择适合的架构。CS架构适用于需要较高的客户端处理能力和灵活性的应用,而BS架构适用于需要跨平台和简化客户端部署的应用。
1. 协议定义:定义一个自定义的通信协议,包括通信消息的格式、字段和编码规则等。可以使用XML、JSON、二进制等形式来定义消息格式。
2. 连接建立:客户端和服务器建立连接。可以使用底层的网络协议(如TCP/IP)建立连接,也可以使用其他技术来建立连接(如WebSocket)。
3. 请求发送:客户端发送请求消息到服务器。请求消息包括请求的类型、操作、参数等信息,按照协议定义的格式进行编码。
4. 请求处理:服务器接收到请求消息后,根据协议定义的规则进行解析和处理。服务器根据请求的类型和内容执行相应的业务逻辑和操作。
5. 响应生成:服务器处理完请求后,生成响应消息。响应消息包括响应的状态、结果、数据等信息,按照协议定义的格式进行编码。
6. 响应发送:服务器将生成的响应消息发送回客户端。响应消息经过网络传输,按照协议定义的规则进行传输。
7. 响应处理:客户端接收到服务器发送的响应消息后,按照协议定义的规则进行解析和处理。客户端根据响应的内容进行相应的操作和处理。
- 消息格式:定义请求和响应消息的结构、字段和编码方式,可以使用常见的数据格式如XML、JSON,或者使用二进制格式。
- 消息交换方式:定义消息的传输方式,可以使用底层的网络协议,如TCP/IP,或者使用其他传输方式,如WebSocket。
- 错误处理:定义错误码和错误信息的规则,使得客户端和服务器可以进行错误处理和恢复。
- 安全性:考虑通信的安全性,可以使用加密和身份验证等机制来保护通信内容的安全性。
需要根据具体的应用需求和场景来设计和实现自定义通信规则,确保通信的可靠性、安全性和灵活性。
shutdown output
是一种关闭输出流的操作。它通常用于网络编程中的Socket对象。
当我们在使用Socket进行网络通信时,可以通过调用Socket的shutdownOutput()
方法来关闭Socket的输出流。这将导致套接字的输出流被关闭,进而阻止通过该套接字发送数据。
关闭输出流的操作有以下几个特点:
需要注意的是,shutdownOutput()
方法只关闭Socket的输出流,而不会关闭整个Socket连接。如果需要关闭整个Socket连接,可以调用Socket的close()
方法。
以下是一个简单的示例代码片段,演示了如何使用shutdownOutput()
关闭Socket的输出流:
Socket socket = new Socket("localhost", 8080);
OutputStream outputStream = socket.getOutputStream();
// 向输出流中写入数据
outputStream.write("Hello, server!".getBytes());
// 关闭输出流
socket.shutdownOutput();
// 继续使用输入流接收数据
InputStream inputStream = socket.getInputStream();
// ... 进行接收数据的操作
// 关闭Socket连接
socket.close();
这段代码连接到本地的8080端口,并向服务器发送一条消息。然后,关闭了Socket的输出流,但仍然可以使用输入流来接收来自服务器的响应。
请注意,在具体的应用中,需要根据实际需求和套接字的使用情况来决定是否需要关闭输出流。
单线程的服务端和多线程的服务端是两种常见的服务器架构模式,它们在处理客户端请求和并发性方面有所不同。
- 单线程服务端使用单个线程来处理客户端请求。当有新的客户端连接时,服务端会依次处理每个客户端的请求,直到完成处理后再处理下一个客户端请求。
- 单线程服务端适用于低并发的场景,其中客户端请求的处理时间较短,不会造成服务端的阻塞。
- 多线程服务端使用多个线程来并发处理客户端请求。当有新的客户端连接时,服务端会创建一个新的线程来处理该客户端的请求,使得多个客户端可以同时得到服务端的响应。
- 多线程服务端适用于高并发的场景,其中可能存在长时间的处理、IO操作或其他阻塞任务。通过多线程,服务端可以同时处理多个客户端的请求,提高系统的并发性能。
- 如果应用程序的并发需求较低,客户端请求的处理时间较短,单线程的服务端可能足够满足需求,并且可以简化编程模型。
- 如果应用程序面临高并发,存在长时间的阻塞操作或需要处理复杂的业务逻辑,多线程的服务端可以提供更好的性能和响应能力。
需要注意的是,多线程的服务端需要考虑线程安全和资源管理等问题,例如使用线程池来管理线程、同步访问共享资源等。此外,在设计服务端时,还可以考虑其他并发模型,如事件驱动、异步IO等,以满足特定场景的需求。
package socket.first;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Create By Idea
*
* @author nigaoxian
* @version 1.0
* @description: TODO
* @ClassName Server2
* @date 2023/7/26 11:12
*/
public class Server2 {
public static void main(String[] args) throws IOException, InterruptedException {
/**
* ServerSocket 是 Java 提供的用于监听来自客户端的连接请求的类
* 创建一个ServerSocket对象,并将其绑定到端口号9999上,表示该服务器将在9999端口上监听连接请求。
*/
ServerSocket server = new ServerSocket(9999);
System.out.println("监听中》》》》》服务器启动成功");
//进入一个无限循环,一直监听客户端的连接请求。
while (true) {
/**
* 用于接受来自客户端的连接请求。当有客户端连接时,
* accept()方法会返回一个Socket对象,该对象表示与客户端的通信连接。
* 将accept()方法返回的Socket对象赋值给新创建的socket变量
*/
Socket socket = server.accept();
/**
* socket 是之前通过accept()方法返回的Socket对象,表示与客户端的通信连接。
* getInetAddress() 是Socket类的方法,用于获取远程主机的InetAddress对象。
* InetAddress对象表示一个IP地址。
*/
InetAddress inetAddress = socket.getInetAddress();
System.out.println("客户端的IP地址是:" + inetAddress);
System.out.println("客户端的端口号是:" + socket.getPort());
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//
byte[] a = new byte[1024];
int count = in.read(a);
String str = "";
if (count != -1) {
String s = new String(a, 0, count);
System.out.println("Server服务端接收到客户端的" + inetAddress + ":" + socket.getPort() + "的消息:" + s);
if ("q".equals(s)) { break; }
//if (s.contains("q")) {
// break;
//}
}
System.out.println("----------处理中-----------");
//进行一些处理(在代码中是模拟处理,休眠1秒)
//Thread.sleep(1000);
String msg = "HTTP/1.1 200 OK\r\nContent-Type:html\r\n\r\n\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" Element - The world's most popular Vue UI framework \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
"\n";
out.write(msg.getBytes());
System.out.println("结束客户端" + inetAddress + ":" + socket.getPort() + "的服务");
socket.close();
}
server.close();
}
}
Server类
package socket.second;
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try {
// 创建ServerSocket对象,监听指定端口
ServerSocket serverSocket = new ServerSocket(8888);
// 等待客户端连接
System.out.println("等待客户端连接...");
Socket socket = serverSocket.accept();
System.out.println("客户端已连接");
// 创建输入流和输出流
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
// 创建线程用于接收客户端消息
Thread receiveThread = new Thread(() -> {
try {
while (true) {
String message = reader.readLine();
System.out.println("客户端:" + message);
}
} catch (IOException e) {
e.printStackTrace();
}
});
receiveThread.start();
// 从控制台读取消息并发送给客户端
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
String message;
while ((message = consoleReader.readLine()) != null) {
writer.println(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client类
package socket.second;
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
try {
// 创建Socket对象,指定服务器IP地址和端口
Socket socket = new Socket("localhost", 8888);
// 创建输入流和输出流
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
// 创建线程用于接收服务器消息
Thread receiveThread = new Thread(() -> {
try {
while (true) {
String message = reader.readLine();
System.out.println("服务器:" + message);
}
} catch (IOException e) {
e.printStackTrace();
}
});
receiveThread.start();
// 从控制台读取消息并发送给服务器
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
String message;
while ((message = consoleReader.readLine()) != null) {
writer.println(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}