Socket网络编程阶段学习与拓展

一、CS架构和BS架构

CS架构(Client-Server Architecture)和BS架构(Browser-Server Architecture)是两种常见的软件架构模式,用于描述客户端和服务器之间的关系。


CS架构


- CS架构是指客户端-服务器架构,也称为两层架构。
- 在CS架构中,客户端和服务器是分离的实体,彼此独立运行。
- 客户端负责用户界面和用户交互,服务器负责处理业务逻辑和数据存储。
- 客户端通过网络连接(如Socket)与服务器通信,发送请求并接收响应。
- 通常,客户端可以是桌面应用程序、移动应用程序等。


BS架构


- 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架构,或者两者结合使用,以满足不同的业务需求和用户体验要求。

二、在CS(Client-Server)和BS(Browser-Server)架构中,客户端和服务器之间的通信通常遵循以下顺序和有一些区别。


通信顺序


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。
- 错误处理:定义错误码和错误信息的规则,使得客户端和服务器可以进行错误处理和恢复。
- 安全性:考虑通信的安全性,可以使用加密和身份验证等机制来保护通信内容的安全性。
需要根据具体的应用需求和场景来设计和实现自定义通信规则,确保通信的可靠性、安全性和灵活性。

四、什么是shutdownOut()

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的输出流,但仍然可以使用输入流来接收来自服务器的响应。

请注意,在具体的应用中,需要根据实际需求和套接字的使用情况来决定是否需要关闭输出流。

五、什么是单线程服务端与多线程服务端以及区别?

单线程的服务端多线程的服务端是两种常见的服务器架构模式,它们在处理客户端请求和并发性方面有所不同。


1. 单线程的服务端


   - 单线程服务端使用单个线程来处理客户端请求。当有新的客户端连接时,服务端会依次处理每个客户端的请求,直到完成处理后再处理下一个客户端请求。
   - 单线程服务端适用于低并发的场景,其中客户端请求的处理时间较短,不会造成服务端的阻塞。


2. 多线程的服务端


   - 多线程服务端使用多个线程来并发处理客户端请求。当有新的客户端连接时,服务端会创建一个新的线程来处理该客户端的请求,使得多个客户端可以同时得到服务端的响应。
   - 多线程服务端适用于高并发的场景,其中可能存在长时间的处理、IO操作或其他阻塞任务。通过多线程,服务端可以同时处理多个客户端的请求,提高系统的并发性能。


3.选择单线程或多线程的服务端取决于应用程序的需求和场景


- 如果应用程序的并发需求较低,客户端请求的处理时间较短,单线程的服务端可能足够满足需求,并且可以简化编程模型。
- 如果应用程序面临高并发,存在长时间的阻塞操作或需要处理复杂的业务逻辑,多线程的服务端可以提供更好的性能和响应能力。
需要注意的是,多线程的服务端需要考虑线程安全和资源管理等问题,例如使用线程池来管理线程、同步访问共享资源等。此外,在设计服务端时,还可以考虑其他并发模型,如事件驱动、异步IO等,以满足特定场景的需求。

六、HTTP协议:如何让服务端和浏览器端直接通信?

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(); } }

七、用Socket实现聊天室,双方能够同时收发消息。

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();
        }
    }
}

你可能感兴趣的:(Java,网络编程)