>  기사  >  웹 프론트엔드  >  웹소켓 원리에 대한 심층적인 이해

웹소켓 원리에 대한 심층적인 이해

不言
不言원래의
2018-07-28 10:52:431480검색

이 글은 Websocket의 원리에 대한 심층적인 이해를 소개하는 글로서 도움이 필요한 친구들에게 도움이 되기를 바랍니다. 

1. websocket 및 http

WebSocket은 HTML5의 사물(프로토콜)이므로 HTTP 프로토콜이 변경되지 않았거나 중요하지 않다는 뜻이지만, HTTP는 지속성을 지원하지 않습니다. (긴 연결, 순환 연결은 계산되지 않습니다.)

우선 HTTP에는 1.11.0이 있습니다. 소위 keep-alive는 여러 HTTP 요청을 하나로 병합하지만 Websocket은 실제로는 기본적으로 HTTP 프로토콜과 아무 관련이 없는 새로운 프로토콜일 뿐입니다. 기존 브라우저의 핸드셰이크 사양과의 호환성을 위해, 즉 HTTP 프로토콜을 보완한 것이며 이러한 그림을 통해 이해할 수 있습니다 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解

有交集,但是并不是全部。

另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=

再简单来说,层级不一样。

二、Websocket是什么样的协议,具体有什么优点

首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。

HTTP的生命周期通过 Request 来界定,也就是一个 Request 一个 Response ,那么在 HTTP1.0 中,这次HTTP请求就结束了。

在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

教练,你BB了这么多,跟Websocket有什么关系呢?_(:з」∠)_好吧,我正准备说Websocket呢。。

首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。

首先我们来看个典型的 Websocket 握手(借用Wikipedia的。。)

GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com

熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。我会顺便讲解下作用。

Upgrade: websocketConnection: Upgrade

这个就是Websocket的核心了,告诉 Apache 、 Nginx 等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13

首先, Sec-WebSocket-Key 是一个 Base64 encode 的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。

然后, Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~

最后, Sec-WebSocket-Version 是告诉服务器所使用的 Websocket Draft (协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~ 脱水: 服务员,我要的是13岁的噢→_→

然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat

这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~

Upgrade: websocketConnection: Upgrade

依然是固定的,告诉客户端即将升级的是 Websocket 协议,而不是mozillasocket,lurnarsocket或者shitsocket。

然后, Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key 。 服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。

后面的, Sec-WebSocket-Protocol

교차로는 있지만 전부는 아닙니다.

또한 HTML5는 일련의 새로운 API, 즉 새로운 사양과 새로운 기술을 의미합니다. Http 프로토콜 자체에는 1.0과 1.1만 있으며 Html 자체와 직접적인 관계는 없습니다. . 일반인의 관점에서 말하면 HTTP 프로토콜을 사용하여 HTML이 아닌 데이터를 전송할 수 있습니다. =

간단히 말하면 레벨이 다릅니다.

#🎜🎜# 2. 웹소켓은 어떤 프로토콜이고 구체적인 장점은 무엇인가요 #🎜🎜##🎜🎜# 우선 웹소켓은 HTTP와 같은 비영속적 프로토콜에 비해 영속적 프로토콜입니다. 간단한 예를 들어 현재 널리 사용되는 PHP 라이프사이클을 사용하여 설명하겠습니다. #🎜🎜##🎜🎜#HTTP의 수명 주기는 요청, 즉 하나의 요청과 하나의 응답으로 정의됩니다. HTTP1.0에서는 이 HTTP 요청이 끝났습니다. #🎜🎜##🎜🎜# HTTP 1.1에서는 연결 유지가 가능하도록 개선되었습니다. 즉, 하나의 HTTP 연결에서 여러 요청을 보내고 여러 응답을 받을 수 있습니다. 하지만 요청 = 응답을 기억하세요. 이는 항상 HTTP의 경우이므로 요청에는 하나의 응답만 있을 수 있습니다. 더욱이 이 반응 역시 수동적이어서 적극적으로 시작할 수 없습니다. #🎜🎜##🎜🎜#코치님, 그렇게 많은 일을 하셨는데, 그게 웹소켓과 무슨 상관이 있나요? _(:з ∠)_알겠습니다. Websocket에 대해 이야기하려고 했습니다. . #🎜🎜##🎜🎜#우선 Websocket은 HTTP 프로토콜을 기반으로 하거나 HTTP 프로토콜을 빌려 핸드셰이크의 일부를 완성합니다. #🎜🎜##🎜🎜#먼저 일반적인 Websocket 핸드셰이크를 살펴보겠습니다(위키피디아에서 빌려옴...) #🎜🎜#rrreee#🎜🎜# HTTP에 익숙한 어린이 신발이라면 눈치채셨을 겁니다. 이 단락에는 HTTP 프로토콜과 유사한 핸드셰이크 요청에 몇 가지 사항이 더 있습니다. 그런데 기능을 설명하겠습니다. #🎜🎜#rrreee#🎜🎜#이것이 Websocket의 핵심입니다. ApacheNginx와 같은 서버에 알려주세요. Websocket 프로토콜을 시작했습니다. . 이를 처리할 해당 도우미를 찾았습니다 ~ 구식 HTTP가 아닙니다. #🎜🎜#rrreee#🎜🎜#우선, Sec-WebSocket-KeyBase64 인코딩 값으로, 브라우저에서 무작위로 생성되어 서버에 다음을 알려줍니다. Peat, 속지 마세요. 당신이 정말 Websocket 도우미인지 확인하고 싶습니다. #🎜🎜##🎜🎜#그러면 Sec_WebSocket-Protocol은 동일한 URL에서 여러 서비스에 필요한 프로토콜을 구별하는 데 사용되는 사용자 정의 문자열입니다. 간단한 이해: 오늘 밤 A를 서비스하고 싶습니다. 실수하지 마세요~#🎜🎜##🎜🎜#마지막으로 Sec-WebSocket-Version은 서버에 Websocket Draft code>를 사용하라고 지시합니다. (프로토콜 버전) 초기에는 Websocket 프로토콜이 아직 <code>Draft 단계에 있었습니다. 온갖 종류의 이상한 프로토콜이 있었고, Firefox는 어떻습니까? 크롬과 같은 버전을 사용하지 않는다. 처음에는 웹소켓 프로토콜이 너무 많아서 큰 문제였다. . 그래도 괜찮아 이제 해결됐어~ 다들 쓰는거~ 탈수 : 웨이터, 13세 원해요 →_→#🎜🎜##🎜🎜#그러면 서버가 다음을 반환합니다 정보는 요청이 수락되었고 Websocket이 성공적으로 설정되었음을 나타냅니다! #🎜🎜#rrreee#🎜🎜#HTTP를 담당하는 마지막 영역입니다. 프로토콜을 성공적으로 전환했다고 클라이언트에게 알려주세요~#🎜🎜#rrreee#🎜🎜#아직 고정되어 있으며 향후 업그레이드를 클라이언트에게 알립니다. mozillasocket, lurnarsocket 또는 Shitsocket이 아닌 Websocket 프로토콜입니다. #🎜🎜##🎜🎜#그럼 Sec-WebSocket-Accept는 서버에서 확인하고 암호화한 Sec-WebSocket-Key입니다. 서버: 알겠습니다. 알겠습니다. 증명할 수 있도록 제 ID 카드를 보여드리겠습니다. . #🎜🎜##🎜🎜# 뒤의 Sec-WebSocket-Protocol은 사용된 최종 프로토콜을 나타냅니다. #🎜🎜##🎜🎜#이 시점에서 HTTP는 모든 작업을 완료했으며 다음 단계는 Websocket 프로토콜에 따라 완전히 진행하는 것입니다. 여기서는 구체적인 계약에 대해 설명하지 않습니다. #🎜🎜##🎜🎜#——————기술적 분석 부분이 완료되었습니다——————#🎜🎜##🎜🎜##🎜🎜##🎜🎜#

오랜 시간 BBBing을 해오셨는데 Websocket을 사용하면 http long poll이나 ajax polling을 통해 실시간 정보 전송이 가능합니다. http long poll ,或者ajax轮询 不都可以实现实时信息传递么。

好好好,年轻人,那我们来讲一讲Websocket有什么用。来给你吃点胡(苏)萝(丹)卜(红)

三、Websocket的作用

在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。

ajax轮询

ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。

场景再现:

客户端:啦啦啦,有没有新信息(Request)

服务端:没有(Response)

客户端:啦啦啦,有没有新信息(Request)

服务端:没有。。(Response)

客户端:啦啦啦,有没有新信息(Request)

服务端:你好烦啊,没有啊。。(Response)

客户端:啦啦啦,有没有新消息(Request)

服务端:好啦好啦,有啦给你。(Response)

客户端:啦啦啦,有没有新消息(Request)

服务端:。。。。。没。。。。没。。。没有(Response) —- loop

long poll

long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。

场景再现:

客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)

服务端:额。。 等待到有消息的时候。。来 给你(Response)

客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop

从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。

何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。

简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。

说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)

从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。

ajax轮询 需要服务器有很快的处理速度和资源。(速度)long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)

所以 ajax轮询 和 long poll

자, 젊은이 여러분, Websocket의 활용에 대해 이야기해 봅시다. 당근 좀 드릴께요(빨간색)

3. Websocket의 역할

Websocket에 대해 이야기하기 전에 먼저 long pollajax polling의 원리에 대해 말씀드리겠습니다. .

ajax 폴링

ajax 폴링의 원리는 매우 간단합니다. 이를 통해 브라우저는 몇 초마다 서버에 새로운 정보가 있는지 묻는 요청을 보낼 수 있습니다.

장면 재현:

클라이언트: 라라라, 새로운 정보 있나요(요청)?

서버: 아니요(응답)

클라이언트: 라라라, 새로운 정보 있나요(요청)

서버: 아니요. . (답변)

클라이언트: 라라라, 새로운 정보 있나요? (요청)

서버: 너무 짜증나네요, 아니. . (응답)

클라이언트: 라라라, 새로운 메시지 있나요? (요청)

서버: 알겠습니다. 알겠습니다. (응답)

클라이언트: 라라라, 새로운 메시지가 있나요? (요청)

서버:. . . . . 없이. . . . 없이. . . 아니요(응답) —- loop

long poll🎜🎜long poll 실제로 원리는 ajax 폴링과 유사하지만 둘 다 폴링을 사용합니다. (계속 전화하세요. 전화를 받지 못하더라도 끊지 마십시오.) 즉, 클라이언트가 연결을 시작한 후 메시지가 없으면 응답이 클라이언트에 반환되지 않습니다. 메시지가 있을 때까지 반환되지 않으며 클라이언트는 다시 연결을 설정하고 주기가 다시 시작됩니다. 🎜🎜현장 재현 : 🎜🎜클라이언트 : 라라라, 혹시 새로운 정보가 있나요? 아니라면, 나올 때까지 기다려서 돌려주세요(요청)🎜🎜서버 : 흠. . 소식이 있을 때까지 기다리세요. . 오세요(응답)🎜🎜클라이언트: 라라라, 새로운 정보가 있나요? 그렇지 않다면, 사용할 수 있을 때까지 기다렸다가 나에게 돌려주세요(요청) -loop🎜🎜위에서 볼 수 있듯이, 사실, 이 두 가지 방법은 모두 지속적으로 HTTP 연결을 설정한 다음 서버가 이를 처리할 때까지 기다리는 것입니다. 이는 HTTP 프로토콜의 또 다른 특성인 수동성을 반영할 수 있습니다. 🎜🎜수동성이란 무엇인가요? 실제로 서버는 클라이언트에 적극적으로 연결할 수 없으며 클라이언트에 의해서만 시작될 수 있습니다. 🎜🎜간단히 말하면 서버는 매우 게으른 냉장고입니다(농담입니다)(적극적으로 연결을 시작할 수도 없고 시작할 수도 없습니다). 하지만 사장님이 주문을 하시면 손님이 오면 어떻게든 잘 받아야 합니다. 그 사람이 얼마나 피곤한지. 🎜🎜말한 후 위의 단점에 대해 이야기해 봅시다. (말도 안 되는 얘기를 많이 해서 죄송합니다, OAQ)🎜🎜위에서 보면 쉽게 알 수 있듯이, 어쨌든 위의 두 가지는 리소스를 많이 소모합니다. 🎜🎜ajax 폴링을 위해서는 서버에 빠른 처리 속도와 리소스가 필요합니다. (속도) 롱 폴은 높은 동시성을 요구하는데, 이는 동시에 고객을 받을 수 있는 능력을 의미합니다. (장소 규모)🎜🎜그래서 ajax 폴링장기 폴링에서 이런 일이 발생할 수 있습니다. 🎜🎜클라이언트: 라라라라, 새로운 소식은 없나요? 🎜🎜서버: 월간 회선이 통화 중입니다. 나중에 다시 시도해 주세요. (503 서버 사용 불가) 🎜🎜클라이언트:. . . . 좋아요, 라라라, 새로운 정보는 없나요? 🎜🎜서버 : 월간 회선이 붐비네요 나중에 다시 시도해주세요 (503 서버 사용 불가) 🎜🎜클라이언트 : 그럼 서버가 너무 바빠서 옆에서 : 냉장고, 냉장고를 더 원해요! 더. . 더. . (내가 틀렸어... 이건 또 농담이야...) 🎜🎜Websocket에 대해 이야기해보자🎜🎜위의 예를 통해 이 두 가지 방법 중 어느 것도 최선의 방법이 아니며 많은 리소스가 필요하다는 것을 알 수 있습니다. 🎜🎜더 빠른 속도가 필요하고 더 많은 '휴대폰'이 필요합니다. 이 두 가지 모두 '휴대폰'에 대한 수요 증가로 이어질 것입니다. 🎜🎜아, 그런데 HTTP가 여전히 상태 저장 프로토콜이라는 사실을 언급하는 것을 깜빡했네요. 🎜🎜평신도의 관점에서 서버는 매일 너무 많은 고객을 처리해야 하며 전화를 끊자마자 모든 것을 잊어버리고 모든 것을 버릴 것입니다. 두 번째에는 서버에 다시 알려야 합니다. 🎜🎜그래서 이런 경우 Websocket이 등장하게 되었습니다. 그는 HTTP의 이러한 문제를 해결했습니다. 첫째, 수동성입니다. 서버가 프로토콜 업그레이드(HTTP->Websocket)를 완료한 후 서버는 클라이언트에 정보를 적극적으로 푸시할 수 있습니다. 따라서 위의 시나리오는 다음과 같이 수정될 수 있습니다. 🎜🎜클라이언트: 라라라, 웹소켓 프로토콜을 구축하고 싶습니다. 필수 서비스: 채팅, 웹소켓 프로토콜 버전: 17(HTTP 요청) 🎜🎜서버: 확인, 확인됨, 웹소켓 프로토콜로 업그레이드됨(HTTP 프로토콜 전환됨)🎜 🎜클라이언트 : 정보가 있으면 푸시해 주세요. . 🎜🎜서버: 네, 가끔 말씀드리겠습니다. 🎜🎜서버: 발라발라발라🎜🎜서버: 발라발라발라🎜

서버측: ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

서버측: 엄청 웃어요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하하

이렇게 되면 단 한번의 HTTP 요청만 필요하고 꾸준한 정보의 흐름이 전송될 수 있습니다. (프로그래밍에서는 이런 종류의 디자인을 콜백이라고 합니다. 즉, 제가 어리석게 매번 물어보는 대신 정보가 있을 때 알려주는 것입니다.)

이러한 프로토콜은 위의 동기화 지연을 해결하며 매우 유용합니다. 리소스를 소비합니다. 그렇다면 그는 왜 서버의 리소스 소비 문제를 해결합니까?

사실 우리가 사용하는 프로그램은 두 계층의 프록시를 거쳐야 합니다. 즉, HTTP 프로토콜은 Nginx와 같은 서버에서 구문 분석된 다음 처리를 위해 해당 핸들러(PHP 등)로 전송됩니다. 간단히 말해서, 해당 고객 서비스(핸들러)로 문제를 전송하는 책임을 맡은 매우 빠른 운영자(Nginx)가 있습니다. 接线员(Nginx) ,他负责把问题转交给相应的 客服(Handler) 。

本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。

这样就可以解决客服处理速度过慢的问题了。

同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输 identity info (鉴别信息),来告诉服务端你是谁。

虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。

但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。

同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了

至于怎么在不支持Websocket的客户端上使用Websocket。。答案是: 不能

但是可以通过上面说的 long poll 和 ajax 轮询

운영자 자체는 기본적으로 충분히 빠른데, 고객 서비스(Handler)에서 막힐 때마다 고객 서비스 처리 속도가 항상 너무 느립니다. , 결과적으로 고객 서비스가 부족해졌습니다. Websocket은 이러한 문제를 해결한 후 운영자와 직접 지속적인 연결을 설정할 수 있으며, 정보가 있으면 고객 서비스에서 운영자에게 알릴 방법을 찾은 다음 운영자가 이를 고객에게 전달합니다.

이렇게 하면 고객 서비스 처리 속도가 느려지는 문제를 해결할 수 있습니다.

동시에 HTTP 프로토콜은 지속적으로 확립되고 폐쇄되어야 하며 HTTP는 비상태 저장이므로 매번 ID 정보(식별 정보)를 재전송해야 합니다. 서버 당신은 누구입니까?

교환원이 매우 빠르더라도 매번 너무 많은 메시지를 들어야 하는 동시에 이 정보를 지속적으로 고객 서비스에 전송해야 하므로 고객 서비스 처리가 낭비될 뿐만 아니라 효율성도 떨어집니다. 시간을 낭비할 뿐 아니라 네트워크에서 전송하는 데에도 너무 많은 트래픽/시간이 소요됩니다.

그러나 Websocket은 하나의 HTTP 핸드셰이크만 필요하므로 전체 통신 프로세스는 하나의 연결/상태로 설정되므로 HTTP의 비상태성을 방지합니다. 서버는 요청을 닫을 때까지 항상 정보를 알고 있으므로 문제가 해결됩니다. 운영자는 HTTP 프로토콜을 반복적으로 구문 분석하고 신원 정보 정보를 확인해야 합니다.

동시에 고객이 주도적으로 요청하고 정보가 있을 때 서버(푸시)가 이를 전송합니다(물론 클라이언트는 여전히 정보가 적극적으로 전송되기를 기다립니다...). 정보도 없고 운영자(Nginx)에게 넘겨져 점유할 필요도 없다. 고객 서비스(Handler) 자체가 느리다🎜🎜웹소켓을 지원하지 않는 클라이언트에서 웹소켓을 사용하는 방법에 대해. . 대답은 다음과 같습니다. 아니요🎜🎜하지만 위에서 언급한 long pollajax polling🎜🎜을 통해 유사한 효과를 시뮬레이션할 수 있습니다. 관련 권장 사항: 🎜🎜 🎜바이두 홈페이지 HTML 모방🎜🎜🎜🎜html 페이지에서 메타의 역할과 페이지의 캐시 및 비캐싱 설정 분석🎜🎜

위 내용은 웹소켓 원리에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.