Linux 커널 소스 코드에 대한 심층 분석 및 운영 체제의 본질 탐색

WBOY
풀어 주다: 2024-08-08 09:33:08
원래의
936명이 탐색했습니다.

深入解析 Linux 内核源码,探索操作系统本质

1. 커널 소스코드에 대한 나의 의견

Linux 커널 코드의 엄청난 크기는 많은 사람들을 "위축"하게 만듭니다. 바로 이 때문에 Linux에 대한 사람들의 이해가 일반적인 수준에 불과합니다. 리눅스를 분석하고 운영체제의 본질을 파헤치고 싶다면 커널 소스코드를 읽는 것이 가장 효과적인 방법이다. 훌륭한 프로그래머가 되려면Linux 커널 소스 코드 분석이 되기 위해서는 많은 연습과 코드 컴파일이 필요하다는 것을 우리 모두 알고 있습니다. 프로그래밍은 여전히 중요하며, 프로그래밍만 하는 사람들은 쉽게 자신의 지식 영역으로 자신을 제한할 수 있습니다. 지식의 폭을 넓히고 싶다면 다른 사람이 작성한 코드, 특히 우리보다 더 발전된 사람들이 작성한 코드에 더 많이 노출되어야 합니다. 이러한 방법을 통해 우리는 자신의 지식 서클에서 벗어나 다른 사람의 지식 서클에 들어갈 수 있으며, 일반적으로 단기적으로 이해하기 어려운 정보에 대해 더 많이 배울 수 있습니다. Linux 커널은 오픈 소스 커뮤니티의 수많은 "마스터"에 의해 신중하게 유지 관리됩니다. 이러한 사람들은 최고의 코드 전문가라고 할 수 있습니다. 리눅스 커널 코드를 읽음으로써 우리는 커널에 관한 지식을 배울 수 있을 뿐만 아니라, 그들의 프로그래밍 방법과 컴퓨터에 대한 이해를 배우고 느끼는 것이 더 가치 있다고 생각합니다.

저도 프로젝트를 통해 리눅스 커널 소스코드 분석을 접하게 되었고, 소스코드 분석을 통해 많은 유익을 얻었습니다. 관련 커널 지식을 얻었을 뿐만 아니라 커널 코드에 대한 과거의 이해도 바뀌었습니다.

1. 커널 소스 코드 분석은 "손이 닿지 않는" 것이 아닙니다. 커널 소스코드 분석의 어려움은 소스코드 자체에 있는 것이 아니라, 코드를 분석하기 위해 보다 적절한 방법과 방법을 사용하는 방법에 있습니다. 커널의 복잡성은 일반적인 데모 프로그램을 분석하는 것처럼 주요 기능부터 시작하여 단계별로 분석할 수 없다는 것을 의미하며, 커널 소스 코드를 하나씩 "돌파"하기 위해 중간부터 개입하는 방법이 필요합니다. 이러한 "주문형" 형식을 사용하면 특정 세부 사항에 너무 얽매이지 않고 소스 코드의 기본 스레드를 파악할 수 있습니다.

2. 코어 디자인이 이쁘네요. 커널의 특별한 상태는 커널의 실행 효율성이 현재 컴퓨터 응용 프로그램의 실시간 요구 사항에 대응할 만큼 높아야 함을 결정합니다. 따라서 Linux 커널은 C 언어와 어셈블리의 하이브리드 프로그래밍을 사용합니다. 그리고 우리 모두는 소프트웨어 실행 효율성과 소프트웨어 유지 관리성이 많은 경우 서로 상반된다는 것을 알고 있습니다. 커널의 효율성을 보장하면서 커널의 유지 관리성을 향상시키는 방법은 커널의 이러한 "아름다운" 디자인에 달려 있습니다.

3. 놀라운 프로그래밍 방법. 일반 응용 소프트웨어 설계 분야에서는 개발자들이 소프트웨어의 좋은 설계에 더 많은 관심을 기울이고 코딩은 단지 구현 수단의 문제일 뿐이므로 코딩의 상태는 아무리 강조해도 지나치지 않을 수 있습니다. 생각이 너무 많아요. 그리고 이는 커널에 확립되어 있지 않습니다. 좋은 코딩 디자인은 유지 관리성을 향상시킬 뿐만 아니라 코드 성능도 향상시킵니다.

커널에 대한 이해는 사람마다 다를 것입니다. 커널에 대한 이해가 깊어질수록 우리는 커널의 설계와 구현에 대해 더 많은 생각과 감정을 갖게 될 것입니다. 따라서 이 글은 리눅스 커널룸 밖에서 방황하는 더 많은 사람들을 리눅스의 세계로 안내하여 커널의 마법과 위대함을 직접 경험할 수 있기를 바랍니다. 그리고 나는 커널 소스 코드의 전문가는 아니지만 소스 코드 분석에 대한 내 경험과 통찰력을 공유하고 이를 필요로 하는 사람들에게 참조와 도움을 제공하고 싶습니다. 특히 컴퓨터 업계에서는 운영 체제 커널에 대한 적당한 노력을 기울였습니다. 더 이상 고민하지 않고(이미 너무 길어서 당황스럽네요~) 저만의 Linux 커널 소스 코드 분석 방법을 공유하겠습니다.

2. 커널 소스코드를 소스로 얻기가 어렵나요?

本質的に、Linux カーネル コードを分析することは、他の人のコードを見ることと何ら変わりません。目の前にあるコードは通常、自分で書いたコードではないからです。まず簡単な例を見てみましょう。見知らぬ人があなたにランダムにプログラムを渡し、ソースコードを読んでそのプログラムの機能設計を説明してくださいと言われたら、自分のプログラミングスキルは大丈夫だと思っている人の多くは、これは何でもないと思うに違いありません。 、彼のコードを最初から最後まで辛抱強く読んでいる限り、間違いなく答えを見つけることができますが、これは実際に当てはまります。さて、仮定を変えてみましょう。この人が Linus で、彼があなたに提供したものが Linux カーネルのモジュールのコードだったとしても、それはまだそれほど簡単だと思いますか?躊躇する人も多いかもしれません。同じ見知らぬ人から与えられたコードに対して、私たちはなぜこれほど異なる感情を抱くのでしょうか (Linus があなたのことを知っているかどうかは考慮しません、笑~)。以下のような理由があると思います

1. Linux カーネル コードは、「外の世界」にとってはやや謎めいたものですが、非常に大きいため、目の前に置かれても使い始めるのが難しいかもしれません。たとえば、メイン関数が見つからないという非常に小さな理由から問題が始まる可能性があります。単純なデモ プログラムの場合、コードの意味を最初から最後まで解析できますが、カーネル コードを解析する方法はまったく効果がありません。なぜなら、誰も Linux コードを最初から最後まで読むことができないからです (実際には必要ないからです) 、そして使用するときは、それを見てください)。

2.小規模なソフトウェアのコードに触れる人もたくさんいますが、そのほとんどはアプリケーション プロジェクトであり、コードの形式と意味は、頻繁に触れるビジネス ロジックに関連しています。カーネル コードは異なります。カーネル コードが処理する情報のほとんどは、コンピューターの最下層と密接に関連しています。たとえば、オペレーティング システム、コンパイラ、アセンブリ、アーキテクチャなどに関する関連知識が不足している場合も、カーネル コードを読むことが難しくなります。

3.カーネル コードを分析する方法は十分に合理的ではありません。大量の複雑なカーネル コードに直面する場合、グローバルな観点から Linux Mint を使い始めないと、コード詳細の泥沼にはまりやすくなります。結局のところ、カーネル コードは巨大であり、その設計原則とアーキテクチャも存在します。そうでないと、カーネル コードを保守するのは誰にとっても悪夢になるでしょう。コードモジュールの全体的な設計思想を明確にしてから、コードの実装を分析すると、ソースコードの分析が簡単で楽しくなるかもしれません。

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

これはこれらの問題に対する私の個人的な理解です。これまで小規模なソフトウェア プロジェクトに携わったことがない場合、Linux カーネル コードを分析することは、小規模なプロジェクトでの経験を積む良い機会になるかもしれません (実際、Linux コードは、私がこれまでに経験した最大のプロジェクトです!)。コンピューターの基礎的な側面を十分に理解していない場合は、分析と学習を同時に行うことで基礎的な知識を蓄積することを選択できます。最初はコードの分析の進みが少し遅いかもしれませんが、知識が蓄積されていくと、Linux カーネルの「ビジネス ロジック」に対する理解が徐々に明確になっていきます。最後のポイントは、グローバルな視点から分析のソースコードを使いこなす方法です。これも私が皆さんと共有したい経験です。

3. カーネルソースコードの解析方法

ステップ 1: データ収集

人が新しいものを理解するという観点から見ると、物事の本質を探る前に、新しいものを理解するプロセスが必要であり、このプロセスによって新しいものの予備的な概念が形成されます。例えば、ギターを習いたい場合、まずギターを弾くには基本的な視唱、簡略記法、五線などの基礎知識が必要であることを理解し、次に二胡の演奏方法や運指を学び、ようやくギターを始める必要があります。ギターの練習中。

カーネルコードの分析にも同じことが当てはまります。まず、分析対象のコードに含まれるコンテンツを特定する必要があります。プロセスの同期とスケジューリングのコード、ビデオ メモリ管理のコード、デバイス管理のコード、システム起動のコードなどですか。カーネルの複雑さにより、すべてのカーネル コードを一度に分析することはできないため、合理的な分業を行う必要があります。アルゴリズム設計が示すように、大きな問題を解決するには、まずそれに含まれる部分的な問題を解決する必要があります。

분석할 코드 범위를 찾은 후에는 모든 리소스를 사용하여 코드의 이 부분의 전체 구조와 일반 기능을 최대한 포괄적으로 이해할 수 있습니다.

源码

여기에 언급된 모든 리소스는 Baidu, Google 소규모 온라인 검색 엔진, 운영체제 원리 교과서 및 전문 서적, 또는 타인이 제공한 경험과 정보, 심지어 Linux 소스 코드에서 제공하는 문서, 의견 및 소스 코드를 의미합니다. (코드의 식별자 이름을 과소평가하지 마십시오. 때로는 핵심 정보를 제공할 수도 있습니다.) 실제로 여기의 모든 리소스는 여러분이 생각할 수 있는 모든 사용 가능한 리소스를 의미합니다. 사실, 이러한 정보 수집 방법을 통해 우리가 원하는 모든 정보를 얻을 수 있을 것 같지 않습니다. 정보가 더 포괄적으로 수집될수록 코드를 분석하는 과정에서 더 많은 정보를 사용할 수 있고 분석 과정의 난이도도 낮아집니다.

여기에 간단한 반례가 있습니다. Linux의 주파수 변환 메커니즘으로 구현된 코드를 분석한다고 가정해 보겠습니다. 지금까지 우리는 이 용어를 문자 그대로의 의미로만 보면 CPU의 주파수 조정과 관련이 있다고 대략적으로 추론할 수 있습니다. 정보 수집을 통해 우리는 다음과 같은 관련 정보를 얻을 수 있습니다:

1. CPUFreq 메커니즘.

2. 성능, 절전, 사용자 공간, 주문형, 보수적인 주파수 조절 전략.

3. /드라이버/cpufreq/.

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

4. /문서/cpufreq.

5. P상태와 C상태.

리눅스 커널 코드를 분석할 때 이런 정보를 수집할 수 있다면 매우 "운이 좋다"고 해야 할 것입니다. Linux 커널에 대한 정보는 실제로 .NET 및 JQuery만큼 풍부하지는 않지만 강력한 검색 엔진도 없고 관련 연구 자료도 없었던 10년 전과 비교하면 "큰 수확" 시대라고 불러야 합니다! 간단한 "검색"(1~7일이 걸릴 수 있음)을 통해 우리는 코드의 이 부분이 있는 소스 코드 파일 디렉터리까지 찾았습니다. 이런 종류의 정보는 단순히 "귀중한" 것입니다!

2단계: 소스 코드 위치

데이터 수집에서 우리는 소스 코드와 관련된 소스 코드 디렉터리를 "운이 좋게" 찾았습니다. 이는 우리가 실제로 이 디렉터리의 소스 코드를 분석한다는 의미는 아닙니다. 때로는 우리가 찾는 디렉토리가 흩어져 있을 수도 있고, 때로는 우리가 찾는 디렉토리에 특정 기계와 관련된 코드가 많이 포함되어 있을 수도 있으며, 우리는 기계와 관련된 특수 코드보다는 분석 대상 코드의 주요 메커니즘에 더 관심을 갖습니다( 이는 커널의 특성을 더 잘 이해하는 데 도움이 됩니다. 이를 위해서는 정보 중 코드 파일이 포함된 정보를 신중하게 선택해야 합니다. 실제로 이 단계는 한 번에 완료될 가능성이 낮으며 분석할 모든 소스 코드 파일을 한 번에 선택할 수 있고 그 중 하나도 누락되지 않을 것이라고 누구도 보장할 수 없습니다. 그리고 대부분의 모듈과 관련된 핵심 소스 파일을 파악할 수 있다면 나중에 코드를 자세히 분석하면 자연스럽게 모두 찾을 수 있기 때문에 두려워할 필요가 없습니다.

위의 예로 돌아가서 /documention/cpufreq 아래의 문서를 주의 깊게 읽어보세요. 현재 Linux 소스 코드는 소스 코드 디렉토리의 문서 폴더에 모듈 관련 문서를 저장합니다. 분석할 모듈에 문서가 없는 경우 주요 소스 코드 파일을 찾는 어려움이 어느 정도 줄어들고 분석하려는 소스 코드를 찾을 수 없습니다. 문서를 읽으면 최소한 소스 파일 /driver/cpufreq/cpufreq.c에 주의를 기울일 수 있습니다. 이전에 수집된 주파수 변조 전략과 결합된 이 소스 파일 문서를 통해 우리는 5개의 소스 파일 cpufreq_performance.c, cpufreq_powersave.c, cpufreq_userspace.c, cpufreq_ondemand 및 cpufreq_conservative.c에 쉽게 주의를 기울일 수 있습니다. 관련 문서는 모두 찾았나요? 두려워하지 말고 분석을 시작하면 조만간 다른 소스 파일을 찾을 수 있을 것입니다. Windows에서 sourceinsight를 사용하여 커널 소스 코드를 읽으면 코드 분석과 결합된 함수 호출 및 기호 참조 검색과 같은 기능을 통해 freq_table.c, cpufreq_stats.c 및 /include/linux/cpufreq 다른 파일을 쉽게 찾을 수 있습니다. 시간.

검색된 정보 흐름 방향에 따라 분석해야 할 소스 코드 파일을 완벽하게 찾을 수 있습니다. 소스 코드를 찾는 단계는 그다지 중요하지 않습니다. 모든 소스 코드 파일을 찾을 필요가 없고 작업의 일부를 코드 분석 프로세스로 미룰 수 있기 때문입니다. 소스 코드 위치도 중요합니다. 소스 코드 파일의 일부를 찾는 것은 소스 코드 분석의 기초입니다.

3단계: 간단한 댓글

찾은 소스 코드 파일에서 각 변수, 매크로, 함수, 구조 및 기타 코드 요소의 일반적인 의미와 기능을 분석합니다. 이것을 단순 주석이라고 부르는 이유는 이 부분의 주석 작업이 매우 단순하다는 뜻이 아니라, 이 부분의 주석이 해당 주석의 의미를 대략적으로 설명하는 한, 너무 자세할 필요는 없다는 뜻입니다. 관련 코드 요소. 반대로, 여기에서의 작업은 물론 전체 분석 과정에서 가장 어려운 단계입니다. 커널 코드에 대해 깊이 파고드는 것이 처음이기 때문에, 특히 커널 소스 코드를 처음 분석하는 분들에게는 생소한 GNU C 문장 패턴과 압도적인 매크로 정의가 너무 많아 매우 실망스러울 것입니다. 이때, 진정하고 각각의 주요 어려움을 이해하는 한, 앞으로 비슷한 어려움에 직면할 때 후퇴하지 않을 것을 보장할 수 있습니다. 게다가 커널과 관련된 다른 지식도 나무처럼 계속해서 확장될 것입니다.

예를 들어 "DEFINE_PER_CPU" 매크로의 사용은 cpufreq.c 파일 시작 부분에 표시됩니다. 정보를 참조하면 기본적으로 이 매크로의 의미와 기능을 이해할 수 있습니다. 여기서 사용된 방법은 기본적으로 이전에 데이터를 수집하는 데 사용된 방법과 동일합니다. 또한 전송 정의 및 sourceinsight에서 제공하는 기타 기능을 사용하여 해당 정의를 보거나 LKML(LinuxKernelMailList)을 사용하여 확인할 수도 있습니다. 작동하지 않으면 답변을 얻기 위해 질문을 할 수도 있습니다. (LKML과 stackoverflow가 무엇인지 알고 싶으십니까? 정보를 수집하십시오!) 실제로, 가능한 모든 수단을 사용하여 우리는 항상 이 매크로의 의미를 얻을 수 있습니다. 즉, 각 CPU에 대해 독립적으로 사용되는 변수를 정의합니다.

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

저희는 코멘트를 한 번에 정확하게 설명할 수 있다고 고집하지 않고(각 기능의 구체적인 구현 과정을 파악할 필요도 없고 일반적인 기능적 의미만 파악하면 됩니다), 수집된 정보와 위 코드 분석 주석의 의미를 지속적으로 확립합니다(여기서는 원본 주석과 소스 코드의 식별자 이름 지정이 매우 유용합니다). 지속적인 주석, 정보에 대한 지속적인 참조, 주석 의미의 지속적인 변화를 통해.

源码

관련된 모든 소스 코드 파일에 주석을 추가하면 다음과 같은 효과를 얻을 수 있습니다.

1. 기본적으로 소스 코드의 코드 요소의 의미를 이해합니다.

2. 기본적으로 이 모듈과 관련된 주요 소스코드 파일은 모두 찾았습니다.

기존에 수집된 정보 및 데이터를 기반으로 분석 대상 코드의 전체적 또는 구조적 설명과 결합하여 분석 결과를 데이터와 비교하여 코드에 대한 이해를 판단하고 수정할 수 있습니다. 이렇게 간단한 코멘트를 통해 소스코드 모듈의 주요 구조를 전체적으로 파악할 수 있습니다. 이는 또한 간단한 주석의 기본 목적을 달성합니다.

4단계: 세부 사항 메모

간단한 코드 주석을 완성하고 나면 모듈 분석이 반쯤 끝났다는 느낌을 받을 수 있고, 남은 내용은 코드에 대한 심층적인 분석과 철저한 이해입니다. 간단한 주석은 코드 요소의 특정 의미를 항상 매우 정확하게 설명할 수 없으므로 자세한 주석이 매우 필요합니다. 이 단계에서는 다음 사항을 명확히 해야 합니다.

1. 변수 정의가 사용되는 경우.

2. 매크로에 의해 정의된 코드가 사용되는 경우.

3. 함수 매개변수와 반환값의 의미.

4. 함수의 실행 흐름과 호출 관계.

5. 구조체 배열의 구체적인 의미와 사용 조건.

함수 외부의 코드 요소의 의미는 기본적으로 간단한 주석으로 명확하기 때문에 이 단계를 세부 함수 주석이라고 부를 수도 있습니다. 함수 자체의 실행 흐름과 알고리즘이 이 주석 및 분석 부분의 주요 작업입니다.

예를 들어, (dbs_check_cpu 함수에서) cpufreq_ondemand 정책의 구현 알고리즘이 구현되는 방법입니다. 알고리즘의 내용을 이해하기 위해서는 함수에서 사용하는 변수와 호출되는 함수를 점진적으로 분석해야 합니다. 최상의 결과를 얻으려면 가장 직관적인 표현 형태인 이 복잡한 함수의 실행 흐름도와 함수 호출 관계 다이어그램이 필요합니다.

源码

이 단계의 주석을 통해 기본적으로 분석할 코드의 전반적인 구현 메커니즘을 완전히 파악할 수 있습니다. 그리고 모든 분석작업이 80% 완성된 느낌을 받을 수 있습니다. 이 단계는 분석할 코드의 내부 모듈 정의를 더 잘 이해할 수 있도록 주석 정보를 충분히 정확하게 작성해야 합니다. 실제로 Linux 커널은 매크로 문장 패턴 "module_init" 및 "module_exit"를 사용하여 모듈 파일을 선언하고, 모듈의 내부 하위 기능에 대한 정의는 모듈 기능에 대한 완전한 이해를 기반으로 합니다. 모듈이 올바르게 정의되어 있는 한, 모듈이 제공하는 외부 함수와 변수가 무엇인지 알아낼 수 있습니다(EXPORT_SYMBOL_GPL 또는 EXPORT_SYMBOL로 가져온 기호를 사용하여). 모듈 내의 식별자 종속성을 분석하는 다음 단계로 진행할 수 있습니다.

5단계: 모듈 내부 식별자 종속성

네 번째 단계에서 코드 모듈을 정의하면 모듈을 하나씩 "쉽게" 분석할 수 있습니다. 일반적으로 파일 상단에 있는 모듈 진입 및 종료 함수에서 시작할 수 있습니다("module_init" 및 "module_exit"에 의해 선언된 함수는 일반적으로 파일 끝에 있습니다).Linux 커널 소스 코드 분석에 따르면 그들이 호출하는 함수(자체 정의 또는 기타 모듈의 함수)와 사용된 주요 변수(이 파일의 전역 변수 또는 다른 모듈의 외부 변수)는 "함수-변수-함수" 종속성 다이어그램을 그립니다. 이를 식별자라고 부릅니다. 종속성 다이어그램.

실제로 모듈 내의 식별자 종속 관계는 단순한 트리 구조가 아니라, 복잡한 네트워크 관계인 경우가 많습니다. 이때 코드에 대한 자세한 설명의 역할이 분명해집니다. 함수 자체의 의미에 따라 모듈의 하위 기능을 정의하고, 각 하위 기능의 식별자 종속성 트리를 추출합니다.

源码

通过标示符依赖关系剖析,可以很清晰的展示模块定义的函数调用了这些函数,使用了什么变量,以及模块子功能之间的依赖关系——公用了什么函数和变量等。

第六步:模块间互相依赖关系

一旦将所有的模块内部标示符依赖关系图整理完毕,按照模块使用的其他模块的变量或函数,可以很容易得到模块之间的依赖关系。

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

源码

cpufreq代码的模块依赖关系可以表示为如下关系。

源码

第七步:模块构架图

透过模块间的依赖关系图,可以很清楚的抒发模块在整个待剖析代码中的地位和功能。基于此,我们可以将模块分类,整理出代码的构架关系。

源码

如cpufreq的模块依赖关系图所示,我们可以很清楚的看见所有的调频策略模块都是依赖于核心模块cpufreq、cpufreq_stats和freq_table的。假如我们把被依赖的三个模块具象为代码的核心框架的话,那些调频策略模块都是构建在这个框架之上的,它们负责和用户层交互。而核心模块cpufreq提供了驱动等相关的插口负责与系统底层交互。因而,我们可以得到如下的模块构架图。

源码

其实,构架图并非模块的无机拼接,我们还须要结合查阅的资料去丰富构架图的含意。因而,这儿的构架图的细节会随着不同的人的理解有所误差。并且构架图主体的含意很基本一致的。至此,我们完成了待剖析的内核代码的所有剖析工作。

四、总结

正如文章开始所说,我们不可能对全部的内核代码进行剖析。因而,通过对待剖析的代码进行信息收集,之后根据上述的流程剖析出代码的原先始末是了解内核本质的有效手段。这些根据具体须要剖析内核代码的形式,为快速步入Linux内核的世界提供了可能。通过这些方法,不断的对内核的其他模块剖析,最后综合得到自己对Linux内核的理解,也就达到了我们学习Linux内核的目的。

最后向你们推荐两本学习内核的参考书。一本是《Linux内核的设计与实现》,该书为读者快速精简的介绍了Linux内核的主要功能和实现。但不会把读者带入Linux内核代码的深渊中,是了解内核构架和入门Linux内核代码的特别好的参考书,同时该书会增强读者对内核代码的兴趣。另一本是《深入理解Linux内核》,该书的精典我何必多说。我只是建议,若果想更好的学习本书,最好是结合着内核代码一起阅读。因为这本书对内核代码描述的非常详尽,所以结合代码进行阅读可以帮助我们更好的理解内核代码。同时,在剖析内核代码的过程中,也可以在本书中找到具有参考价值的资料。最后,愿你们尽快步入内核的世界,体验Linux带给我们的惊喜!

위 내용은 Linux 커널 소스 코드에 대한 심층 분석 및 운영 체제의 본질 탐색의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:itcool.net
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!