自由学习记录(14)

unity操作问题

  1. 位置:子物体的位置是相对于父物体的。如果你移动父物体,子物体会保持相对于父物体的相对位置,跟着一起移动。

  2. 旋转:子物体的旋转也是相对于父物体的。旋转父物体会导致子物体围绕父物体的原点旋转。

  3. 缩放:对父物体的缩放操作会按照相同的比例影响其所有子物体。这意味着如果父物体缩放2倍,所有子物体也会缩放2倍。

UI没有变化,因为是拉长宽,和位置,只变化这两个

Image的fill center是sole功能,就是要不要把中间的东西挖掉,是sliced 的image type独有的挖心

inertia(伊娜莎baby)

Mask 组件的 Show Mask Graphic 属性用于控制是否在屏幕上显示蒙版的图形。具体来说:

  • 如果选中 Show Mask Graphic:蒙版的图形(如 Mask 组件的图形)会被显示出来。这通常用于调试或可视化蒙版区域,帮助开发者理解蒙版如何影响子物体的显示。

  • 如果未选中 Show Mask Graphic :蒙版的图形不会被渲染出来,只会显示其影响下的子物体内容。这通常是希望用户只看到被蒙版内容的效果,而不想看到蒙版本身的边界。

Vertical Layout Group

Reverse Arrangement

  • 这个选项决定子物体排列的顺序。如果勾选,子物体的顺序会从++最后一个元素到第一个元素进行排列,效果是垂直方向上的反转排列++。

Child Force Expand (Width/Height)

这两个默认都勾了

为了就是个协调,这个开了之后Spacing上写的就是假的了,

关了height force expand之后,

Use Child Scale (Width/Height)

  • 这两个选项控制是否在布局时考虑子物体的缩放比例(Scale
  • 就是把不把子物体自己瞎调的Scale也照样拿过来

红色的单独改了缩放因子再拉进来的,如果想整齐划一,不想让各个图带着莫名其妙的缩放进来用,默认两个都不勾就很ok

这里只是调了width的缩放因子保持,和height是分开的

勾了width之后,会根据缩放因子进行计算,使得图片变得正常有序

height动了比较怪

反正也是进行某种算法,从而符合Layout Group对顺序的安排

Vertical Layout Group放在Scroll ViewContent中时,动态创建图片或其他UI元素时,Content的范围会根据子物体的数量自动扩展。Vertical Layout Group会自动调整Content的高度或宽度,以容纳所有的子物体。

但是没有怎么回事?

可能是其中之一的原因

  • ++Content Size Fitter :确保Content对象上有Content Size Fitter组件,并且其Vertical Fit设置为Preferred Size(如果是垂直滚动),这样才能根据子物体的大小自动调整Content的高度。++

  • Layout Element :检查每个动态创建的图片(或UI元素)上有没有不小心手贱加了Layout Element然后乱改了布局属性

  • Vertical Layout Group 设置 :确保Vertical Layout GroupChild Force Expand选项适当设置。

  • Scroll View 的设置 :检查Scroll Rect组件,确保其与Content正确关联。如果Scroll Rect未关联或设置错误,滚动功能和Content的扩展可能会失效。

Content Size Fitter的选项用于控制UI元素的尺寸调整方式,具体来说:

  1. Unconstrained(无约束) :表示该维度不会被Content Size Fitter修改,大小将保持不变,或者由其他组件(如Layout Element)决定。

  2. Min Size(最小大小)Content Size Fitter会将该维度的大小调整为所有子元素所需的最小值,确保它们能够完全容纳在这个大小中,但不会超过其最小需求。

  3. Preferred Size(首选大小)Content Size Fitter会根据子元素的首选大小调整该维度。首选大小通常由子元素的内容决定,比如文本的长度或图片的尺寸。这是最常用的选项,用于动态扩展容器来适应内容。

Aspect Ratio Fitter

Aspect Ratio Fitter 是 Unity 中用于保持 UI 元素特定宽高比(Aspect Ratio)的组件。它主要用于确保某个 UI 元素(比如图片、视频或其他内容)的宽高比例在屏幕大小变化时保持一致。这样可以避免元素被拉伸、压缩或失真。

主要模式:

  1. None

    • 不会根据宽高比进行任何调整,UI 元素的宽高由其 RectTransform 控制。
  2. Width Controls Height

    • 宽度固定,高度根据宽高比进行动态调整。例如,如果宽高比是 16:9,UI 元素的宽度为 160px,那么高度将自动调整为 90px。
  3. Height Controls Width

    • 高度固定,宽度根据宽高比动态调整。例如,如果宽高比是 4:3,UI 元素的高度为 120px,那么宽度将自动调整为 160px。
  4. Fit In Parent

    • UI 元素会根据父对象的大小调整,同时保持宽高比,使其尽可能适应父对象的大小而不失真。
  5. Envelope Parent

    • UI 元素会完全覆盖父对象的大小,同时保持宽高比,但有可能某些部分超出父对象的边界。

使用场景:

  • 当你有图片、视频、或其他带有固定比例的内容,且需要在不同分辨率、屏幕大小变化时保持正确比例时非常有用。例如,处理头像图片、视频播放器窗口时,使用 Aspect Ratio Fitter 可以避免内容失真。

加了 Layout Element就可以直接修改各个布局属性

还可以直接忽略layout,66

聊天室客户端服务端部分记录

老天,我脑子溢出

​​​​​​​​​​​​​​​​​​​​​

c++的数组赋值问题

++c++里的数组所谓的"数组",指的是传入一个连续的存了数的内存空间,然后通过[]来确定这一串内存空间的切分方式, 也就是说我的int arr[10];这个arr我完全可以赋值给int [][2],只不过是换了一种方式对这一段不变的内存空间 进行切分++

cpp 复制代码
void printArray(int arr[][2], int rows) {
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < 2; ++j) {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {
    int myArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int (*ptr)[2] = (int (*)[2]) myArray; // 将一维数组的指针转换为二维数组指针
    printArray(ptr, 5); // 传入行数为 5
    return 0;
}

int arr2[][2]=myArray;可以吗 NO

int arr2[][2]=(int (*)[2])myArray;

int arr2[][2]=(int [][2])myArray; 那这样呢

通通NO

都是想强转类型,c++没带这种强转

在 C++ 中,直接将一维数组赋值给二维数组的写法 int arr2[][2] = (int (*)[2])myArray;int arr2[][2] = (int [][2])myArray; 是不合法的。这是因为数组的类型不匹配,编译器无法自动进行这样的转换。

如果你想将一维数组的内容视作一个二维数组,应该手动进行转换或使用指针。正确的方法是使用指针类型转换,且要确保内存布局的兼容性。

cpp 复制代码
  int myArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // 将一维数组转换为指向二维数组的指针
    int (*arr2)[2] = reinterpret_cast<int (*)[2]>(myArray);

    int myArray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int (*ptr)[2] = (int (*)[2]) myArray; // 将一维数组的指针转换为二维数组指针

在 C++ 中,以下的赋值方式是错误的:

  1. int (*ptr)[2] = (int [][2]) myArray;

    这种方式无法直接将 myArray 转换为 int[][2],因为 myArray 是一维数组,它的类型是 int[10]。这会导致类型不匹配。

  2. int arr2[][2] = (int (*)[2]) myArray;

    这也是不合法的,因为 arr2 需要在定义时指定大小,且类型不匹配。

一开始声明的时候不带[]里的数,因为右边里全是赋值了的数据,左边自然硬气了,可以直接数据类型猜测得出,但这也只是懒人不写,正经写法就是在里面带上具体数字,把数组声明的明明白白的,

int arr2[5][2] = (int (*)[2]) myArray; 是非法的,因为你试图将一维数组的指针转换为二维数组指针,而它们的内存布局并不兼容。

  • 数组维度myArrayint[10],而 arr2int[5][2]。这两者的内存布局不同,因此不能直接互换。

  • 指针转换 :虽然你可以将 myArray 的首地址视为指向 int[2] 的指针,但这并不改变原始数组的结构,导致访问数据时的潜在错误。

为什么不能直接赋值

虽然二维数组和一维数组在内存中都是连续存储的,但它们的类型是不同的:

  • myArray 是一个一维数组,类型是 int[10]
  • arr2 是一个二维数组,类型是 int[5][2]

当你尝试将一维数组的指针转换为二维数组指针时(如 int (*ptr)[2] = (int (*)[2]) myArray;),在访问元素时会产生问题。具体来说,二维数组的每一行都被视为一个 int[2] 类型的数组,而直接将一维数组的首地址强制转换成这样的指针是逻辑上的错误,因为编译器并不知道你在访问时如何切割这段连续的内存空间。

意思就是,二维数组的确也是按照一整段连续的内存空间存的,这点和一维数组一样,

但是二维数组为二维,这一点,导致每个下标都有xy坐标了

那么到底[][]左边和右边哪个是x哪个是y?

c++认为这种数据排列方式在这个行列的逻辑问题上,如果转成一维的访问方式,可能存在数据错位的问题

干脆就舍弃了各个维之间的转换

cpp 复制代码
    // 目标数组
    int copy[5][5];

    // 复制数组
    copyArray(grids, copy, 5, 5);

// 函数定义
void copyArray(int src[5][5], int dest[5][5], int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            dest[i][j] = src[i][j];
        }
    }
}
cpp 复制代码
// 函数定义
int** copyArray(int arr[5][5], int rows, int cols) {
    // 动态分配内存
    int** newArr = new int*[rows];
    for (int i = 0; i < rows; i++) {
        newArr[i] = new int[cols];
        for (int j = 0; j < cols; j++) {
            newArr[i][j] = arr[i][j];
        }
    }
    return newArr;
}

在 C++ 中,二维数组的函数参数需要指定第二维的大小,但可以省略第一维的大小。这样做是因为编译器在编译时能够确定数组的内存布局。

cpp 复制代码
void copyArray(int src[][5], int dest[][5], int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            dest[i][j] = src[i][j];
        }
    }
}

在这个例子中,int src[][5] 表示第一维的大小可以省略,但第二维的大小必须指定。原因是:

  • 数组在内存中是以行优先的方式存储的,编译器需要知道每行的元素数量,以正确计算元素的地址。

  • 省略第一维:编译器可以根据传递的数组推断。

  • 必须指定第二维:确保内存布局的正确性,编译器需要这个信息来正确访问元素。

  • 数组参数的定义 : 当你定义一个二维数组参数时,比如 void function(int arr[][5]),这里的 5 是必须的,因为编译器需要知道每一行有多少列来正确地计算元素的内存地址。

  • 第一个维度的灵活性 : 你可以不指定第一个维度,例如 void function(int arr[][5]),因为编译器在处理时能够++根据传入的数组大小进行推断++。

  • 传入的数组 : 当你将数组传递给函数时,编译器会根据第二个维度(这里是 5)来解析数据。例如,如果你传入一个大小为 3x5 的数组,函数会处理这 3 行、5 列的数组。

  • 长度限制 : 传入的数组的第一维(行数)是可以任意的,只要你的数组在内存中是连续的。你可以++传入任意大小的数组,但要确保第二个维度(列数)与函数参数中定义的一致++。

Java补充常用

StringBuilder

BigDecimal

SQL的多表查询

  • hire_date DATE:

    • 这个字段用于存储员工的入职日期。
    • ++数据类型为 DATE,表示它将只保存日期信息(年、月、日)++,不包含时间。
  • salary DECIMAL(10, 2):

    • 这个字段用于存储员工的薪水。
    • 数据类型为 DECIMAL,表示这个字段可以存储十进制数字。
    • (10, 2) 表示++总共有10位数字,其中2位是小数位++ 。这意味着薪水的最大值可以达到++99999999.99(即8位整数部分加上2位小数部分)++。
  • gender ENUM('M', 'F'):

    • 这个字段用于表示员工的性别。
    • 数据类型为 ENUM,表示这个字段++只能取预定义的特定值++。
    • 在这里,++ENUM('M', 'F') 表示性别可以是 'M'(男性)或 'F'(女性),其他值将被拒绝。++

创建表的巴拉巴拉

customer_id INTPRIMARY KEY AUTO_INCREMENT,

customer_name VARCHAR(50)

auto_increment自动给加入值的数据行添加行,一个一个涨的呗

-- 创建订单主表

CREATE TABLE OrderMaster (

order_id INT PRIMARY KEY AUTO_INCREMENT,

customer_id INT,

order_date DATE,

total_amount DECIMAL(10, 2),

FOREIGN KEY (customer_id) REFERENCES Customer(customer_id)

);

外键添加

foreign key(customer_id)references Customers(customer_id)

简简单单的,just like the plane finds a place to land,baby

查询顺序

在 SQL 查询中,执行的顺序与书写的顺序并不相同,主要的执行顺序如下:

  1. FROM: 首先确定查询的数据源,决定从哪个表中提取数据。
  2. JOIN: 如果查询涉及多个表,会在此步骤中进行表的连接(如 INNER JOIN、LEFT JOIN 等)。
  3. WHERE: 对数据进行过滤,只保留满足条件的行。
  4. GROUP BY: 对结果进行分组,通常与聚合函数(如 COUNT、SUM、AVG 等)一起使用。
  5. HAVING: 对分组后的结果进行进一步的过滤,保留满足条件的组。
  6. SELECT: 从结果中选择要显示的列和计算的字段。
  7. ORDER BY: 对结果集进行排序。
  8. LIMIT: 限制返回的行数。

GROUP_CONCAT

SELECT GROUP_CONCAT(employee_name) AS employees, hire_date

FROM Employee
GROUP BY hire_date
HAVING COUNT(*) > 1;

GROUP_CONCAT(employee_name) 是 MySQL 中的一个聚合函数,用于将同一组中的多个值连接成一个字符串。具体来说,它将同一组内的所有 employee_name 字段的值合并为一个用逗号(或指定分隔符)分隔的字符串。

  • GROUP_CONCAT 的结果长度有限制,最大为 1024 字符,可以通过设置 group_concat_max_len 参数来调整。
  • 如果++组内有 NULL 值,GROUP_CONCAT 会忽略这些 NULL 值++。

表的左接,不是左边的主表就是爹中之爹,如果右边接过来的表有很多条订单数据,左边的顾客表也会老老实实有多少条重复多少条,接来接去本质还是为了结合尽量多的信息

这里有四个客户,如果只有三个人一起买了10件东西,

这里客户表右接了订单表,那么因为客户表为主表,打死都有显示全里面的信息,

所以里面那个没有下单的家伙最后也可以在接起来的表里找到

而因为三个人买了10件东西,这三个人的客户表行就会在大表里反复出现,十次,每行自然是带上了各自行的订单信息

union

外部连接的回顾

在 SQL 中,外部连接用于返回符合条件的行,以及左表或右表中没有匹配的行。根据连接的不同方式,有以下几种情况:

  1. 左外连接 (LEFT JOIN):返回左表中的所有行,即使右表中没有匹配的行。
  2. 右外连接 (RIGHT JOIN):返回右表中的所有行,即使左表中没有匹配的行。
  3. 完整外部连接 (FULL OUTER JOIN) :++返回左表和右表中的所有行,匹配的行会显示在一起,不匹配的行用 NULL 填充++。

MySQL 对外部连接的支持

在 MySQL 中,完整外部连接 并不直接支持。因此,我们使用 UNION 来模拟它。

UNION 的基本用法

UNION 用于合并两个或多个查询的结果集。++合并的结果集去掉重复的行(如果想保留重复的行,可以使用 UNION ALL)。++

使用 UNION 模拟完整外部连接

当我们想要获取两个表(在这个例子中是 ProductOrderDetail)的完整外部连接时,可以分别进行左外连接和右外连接,然后使用 UNION 将两个结果合并在一起。这样,即使某个表没有匹配的行,我们也会在结果中看到它。

很明显union更加无脑,是纯1+1

group by接两个参

在 SQL 中,GROUP BY 子句用于将结果集中的行分组,从而对每个组应用聚合函数(如 SUM, COUNT, AVG 等)。++当你使用 GROUP BY 时,选择的列必须是以下之一:++

  1. ++聚合函数 :如 SUM(), COUNT(), AVG(), MAX(), MIN() 等++,表示对分组后的数据进行汇总计算。
  2. ++未被聚合的列 :这些列必须出现在 GROUP BY 子句中++,因为 SQL 需要知道如何将数据分组。

在这个例子中:

  • p.product_idp.product_name ++是未被聚合的列++ ,因此它们++需要在 GROUP BY 中列出++。
  • SUM(d.quantity)SUM(d.amount) 是++聚合函数,它们用于计算每个产品的总数量和总金额++。

排序行为

  • 在SQL中,GROUP BY 并不会隐式地对结果集进行排序。也就是说,虽然结果会按照 p.product_idp.product_name 进行分组,但不一定会按照这些列的值自动排序。
  • 如果你希望结果按照特定顺序返回,需要使用 ORDER BY 子句明确指定排序规则。

cross join

MySQL 支持交叉连接(CROSS JOIN)。在 MySQL 中,交叉连接返回两个表的笛卡尔积,也就是说,结果集中会包含第一个表的每一行与第二个表的每一行的所有组合。交叉连接的语法相对简单,你可以通过以下两种方式来实现:

使用 CROSS JOIN 语法

SELECT * FROM TableA CROSS JOIN TableB;

使用 JOIN 语法(不带条件)

你也可以使用 INNER JOINLEFT JOIN 语法,但不提供连接条件,结果将与 CROSS JOIN 相同:

SELECT * FROM TableA JOIN TableB; -- 省略 ON 条件,结果将是笛卡尔积

示例

假设有两个表 StudentsCourses

表: Students

student_id student_name
1 Alice
2 Bob

表: Courses

course_id course_name
101 Math
102 Science

如果你执行以下交叉连接:

SELECT * FROM Students CROSS JOIN Courses;

结果将是:

student_id student_name course_id course_name
1 Alice 101 Math
1 Alice 102 Science
2 Bob 101 Math
2 Bob 102 Science

现实应用

交叉连接通常用于生成组合数据,尤其在以下情况下:

  • 组合选择: 例如,如果你有多个产品和多个顾客,你可能想知道每个顾客对每个产品的反馈,交叉连接可以帮助你生成所有可能的组合。

  • 报表生成: 在生成需要所有组合的报表时,交叉连接可以有效提供所需的数据视图。

不过,使用交叉连接时要小心,因为如果表很大,结果集可能会迅速增大,从而导致性能问题。因此,在使用交叉连接时,最好确保你真的需要所有的组合数据。

TCP

TCP(Transmission Control Protocol,传输控制协议)是互联网通信中非常重要的协议,它负责保证设备之间的数据传输是可靠有序 的。TCP与IP(互联网协议)一起,构成了大家常说的"TCP/IP协议栈 "。在这个协议栈中,++IP负责寻址和路由 ,而TCP负责数据传输的可靠性++。

TCP的基础概念:

  1. 连接建立与关闭:

    • 建立连接(握手) :TCP在通信前会先通过一个三步的过程,叫做"三次握手",来确保双方已经准备好进行数据传输。
      • 第一次握手:客户端发送一个连接请求(SYN)。
      • 第二次握手:服务器收到请求,回应(SYN + ACK)。
      • 第三次握手:客户端收到回应后,确认并完成连接(ACK)。
    • 关闭连接(挥手):通信结束时,通过"四次挥手"来安全关闭连接,确保所有数据都已经传输完毕。
  2. 数据可靠传输:

    • 分片与重组 :TCP会将大数据拆分成多个小数据包(称为数据段)进行传输,并且接收方在收到这些数据包后,会重新按照顺序组合起来。
    • 确认机制:每个数据包发送后,接收方会发送一个确认信息(ACK),告知发送方该数据已经成功接收。如果发送方没有收到确认信息,就会重新发送这个数据包,确保数据不会丢失。
    • 超时重传:如果数据在一定时间内没有得到确认,TCP会重新发送数据包。
  3. 有序传输:

    • 顺序控制:TCP为每个数据包分配一个序列号,接收方可以根据序列号把数据包按正确的顺序拼接起来,即使数据包到达的顺序乱了,也能还原成正确的顺序。
  4. 流量控制:

    • 滑动窗口:TCP会根据接收方的处理能力,动态调整发送数据的速度。通过滑动窗口机制,确保不会发送太多数据让接收方处理不过来,避免网络拥塞。
  5. 拥塞控制:

    • 网络拥塞:如果网络过于拥堵,TCP会自动减少数据发送速度,防止加剧拥堵,保持网络稳定。

TCP的主要特点:

  1. 可靠性:确保数据能够完整、准确地从发送方传输到接收方。
  2. 有序性:即使数据包的顺序在传输过程中乱了,TCP仍能确保接收方能按照正确的顺序组装数据。
  3. 双向通信:TCP是一种全双工协议,允许双方同时发送和接收数据。
  4. 流量控制与拥塞控制:能根据网络状况动态调整数据发送速率,避免网络拥堵。

CS和BS

两种常见的软件架构模式

1. CS架构(Client-Server架构)

要求客户端(Client)和服务器(Server)各自具备一定的处理能力,

客户端与服务器直接通信,共同完成任务。

应用场景:
  • 传统的桌面应用程序:像早期的聊天软件、数据库管理软件等。
  • 游戏客户端:如很多在线游戏都采用了这种架构,客户端负责显示游戏画面、处理用户输入,而服务器负责管理游戏状态、同步多个玩家的操作。
优点:
  • 客户端和服务器可以分别优化性能:客户端侧更注重用户交互体验,服务器端则关注数据处理和存储的效率。
  • 可以处理复杂的任务和大数据量的请求,因为客户端和服务器都有各自的处理能力。
缺点:
  • 客户端程序需要安装,维护和更新较为复杂。
  • 客户端与服务器紧密耦合,需要定期更新或修改客户端软件,以适应服务器端的变化。

2. BS架构(Browser-Server架构)

概念:

架构的特点是浏览器(Browser)作为客户端,与服务器进行交互,通常依赖++网页技术(HTML、CSS、JavaScript)来实现用户界面和功能++。

结构:
  • 浏览器(Browser):充当客户端,负责呈现界面、获取输入并与服务器交互。用户不需要安装额外的软件,只要有浏览器即可使用。
  • 服务器(Server) :负责处理数据、执行业务逻辑,并将处理后的结果通过网络返回给浏览器。通常++使用Web服务器,如Apache、Nginx等,数据库、业务逻辑也通常在服务器端执行++。
工作方式:
  • 用户通过浏览器访问网站,++浏览器发送请求到服务器,服务器处理请求后返回页面或数据++,浏览器再将结果展示给用户。
应用场景:
  • 网页应用程序:像电子邮件、社交媒体、在线购物网站等。
  • 轻量级应用:不需要复杂的用户界面或客户端功能,用户只需通过浏览器访问即可。
优点:
  • 简化客户端的安装与维护:用户只需要一个浏览器即可使用应用,不需要安装复杂的客户端程序。
  • 跨平台性强:Windows、Mac、Linux,还是手机、平板,都能使用相同的服务。
  • 易于更新与维护 :++服务器端一旦更新,所有用户都会即时获取最新的服务++,无需对客户端进行频繁更新。
缺点:
  • 由于依赖浏览器,无法处理非常复杂的用户交互或计算任务,性能可能不如CS架构。
  • 网络依赖性较强,离线使用受限。

3. CS与BS的对比

特点 CS架构 BS架构
客户端程序 需要安装专门的客户端应用程序 通过浏览器访问,通常不需要安装软件
平台依赖性 通常与操作系统或硬件紧密结合 跨平台性强,只需有浏览器即可使用
维护成本 客户端需要定期更新和维护 服务器更新后,用户自动获得最新功能
用户体验 可提供复杂的界面和本地功能支持 受限于浏览器功能,复杂交互有限
数据处理 一部分逻辑在客户端执行 所有逻辑主要在服务器端处理
适用场景 大型应用、桌面软件、在线游戏 轻量级应用、跨平台应用、网页服务

4. BS和CS架构的选择

  • 选择BS架构 :当你希望用户通过浏览器访问你的应用程序时,比如开发一个网页应用内容管理系统(CMS)、或是需要支持多平台时,BS架构更为适合。
  • 选择CS架构 :如果你开发的应用对性能、交互有更高的要求,比如一个桌面软件高性能游戏客户端,或者需要更强的本地功能(如文件操作、设备访问),那么CS架构会更合适。
未来趋势:

随着浏览器技术云服务 的进步,很多传统的CS架构应用逐渐被转移到BS架构上,比如在线办公软件云游戏等。这使得用户体验和平台支持得到了大幅提升,同时也减少了客户端维护的负担。

总结来说,CS架构更加适合复杂任务和深度交互,而BS架构则更适合轻量、跨平台的应用。选择合适的架构取决于应用的需求、用户的使用环境和开发者的目标。

TCP,CS,BS

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习