国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Rumah php教程 PHP開發(fā) GIT 傳輸協(xié)議實(shí)現(xiàn)

GIT 傳輸協(xié)議實(shí)現(xiàn)

Nov 23, 2016 pm 02:18 PM

GIT 傳輸協(xié)議實(shí)現(xiàn)

在 GIT 的三種主流傳輸協(xié)議 HTTP SSH GIT 中,GIT 協(xié)議是最少被使用的協(xié)議(也就是 URL 以?git://?開始的協(xié)議)。 這是由于 git 協(xié)議的權(quán)限控制幾乎沒有,要么全部可讀,要么全部可寫,要么全部可讀寫。所以對(duì)于代碼托管平臺(tái)來說, git 協(xié)議的目的僅僅是為了支持 公開項(xiàng)目的只讀訪問。

在 git 的各種傳輸協(xié)議中,git 協(xié)議無疑是最高效的,HTTP 受限于 HTTP 的特性,傳輸過程需要構(gòu)造 HTTP 請(qǐng)求和響應(yīng)。 如果是 HTTPS 還涉及到加密解密。另外 HTTP 的超時(shí)設(shè)置,以及包體大小限制都會(huì)影響用戶體驗(yàn)。

而 SSH 協(xié)議的性能問題主要集中在加密解密上。當(dāng)然相對(duì)于用戶的信息安全來說,這些代價(jià)都是可以接受。

git 協(xié)議實(shí)際上相當(dāng)于 SSH 無加密無驗(yàn)證,也就無從談起權(quán)限控制,但實(shí)際上代碼托管平臺(tái)內(nèi)部的一些同步服務(wù),如果使用 git 協(xié)議實(shí)現(xiàn),將會(huì)得到很大的性能提升。

傳輸協(xié)議規(guī)范

git 協(xié)議的技術(shù)文檔可以從 git 源碼目錄的?Documentation/technical?找到,即?Packfile transfer protocols?創(chuàng)建 TCP 連接后,git 客戶端率先發(fā)送請(qǐng)求體,請(qǐng)求格式基于 BNF 的描述如下:

git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
request-command   = "git-upload-pack" / "git-receive-pack" / "git-upload-archive"   ; case sensitive
pathname          = *( %x01-ff ) ; exclude NUL
host-parameter    = "host=" hostname [ ":" port ]

一個(gè)例子如下:

0033git-upload-pack /project.git\0host=myserver.com\0

在 git 的協(xié)議中,pkt-line 是非常有意思的設(shè)計(jì),行前 4 個(gè)字節(jié)表示整個(gè)行長(zhǎng),長(zhǎng)度包括其前 4 字節(jié), 但是有個(gè)特例,0000 其代表行長(zhǎng)為 0,但其自身長(zhǎng)度是 4。

下面是一個(gè)關(guān)于請(qǐng)求的結(jié)構(gòu)體:

struct GitRequest{
    std::string command;
    std::string path;
    std::string host;
};

git 有自帶的 git-daemon 實(shí)現(xiàn),這個(gè)服務(wù)程序監(jiān)聽 9418 端口,在接收到客戶端的請(qǐng)求后,先要判斷 command 是 否是被允許的,git 協(xié)議中有 fetch 和 push 以及 archive 之類的操作,分別對(duì)應(yīng)的服務(wù)器上的命令是 git-upload-pack git-receive-pack git-upload-archive。HTTP 只會(huì)支持前兩種,SSH 會(huì)支持三種,而 代碼托管平臺(tái)的 git 通常支持的 是 git-upload-pack git-upload-archive。

當(dāng)不允許的命令被接入時(shí)需要發(fā)送錯(cuò)誤信息給客戶端,這個(gè)信息在不同的 git-daemon 實(shí)現(xiàn)中也不一樣,大體 如下所示。

001bERR service not enabled

git-daemon 將對(duì)請(qǐng)求路徑進(jìn)行轉(zhuǎn)換,以期得到在服務(wù)器上的絕對(duì)路徑,同時(shí)可以判斷路徑是否存在,不存在時(shí) 可以給客戶端發(fā)送 Repository Not Found。而 host 可能時(shí)域名也可能時(shí) ip 地址,當(dāng)然也可以包括端口。 服務(wù)器可以在這里做進(jìn)一步的限制,出于安全考慮應(yīng)當(dāng)考慮到請(qǐng)求是可以被偽造的。

客戶端發(fā)送請(qǐng)求過去后,服務(wù)器將啟動(dòng)相應(yīng)的命令,將命令標(biāo)準(zhǔn)錯(cuò)誤和標(biāo)準(zhǔn)輸出的內(nèi)容發(fā)送給客戶端,將客戶端 傳輸過來的數(shù)據(jù)寫入到命令的標(biāo)準(zhǔn)輸入中來。

在請(qǐng)求體中,命令為 git-upload-pack /project.git 在服務(wù)器上運(yùn)行時(shí),就會(huì)類似

git-upload-pack ${RepositoriesRoot}/project.git

出于限制連接的目的,一般還會(huì)添加 --timeout=60 這樣的參數(shù)。timeout 并不是整個(gè)操作過程的超時(shí)。

與 HTTP 不同的是,git 協(xié)議的命令中沒有參數(shù) --stateless-rpc 和 --advertise-refs ,在 HTTP 中,兩個(gè)參數(shù)都存在時(shí), 只輸出存儲(chǔ)庫的引用列表與 capabilities,與之對(duì)于的是 GET /repository.git/info/refs?service=git-upload(receive)-pack , 當(dāng)只有 --stateless-rpc 時(shí),等待客戶端的數(shù)據(jù),然后解析發(fā)送數(shù)據(jù)給客戶端,,與之對(duì)應(yīng)的是 POST /repository.git/git-upload(receive)-pack。

進(jìn)程輸入輸出的讀寫

在 C 語言中,有 popen 函數(shù),可以創(chuàng)建一個(gè)進(jìn)程,并將進(jìn)程的標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)輸入創(chuàng)建成一個(gè)文件指針,即 FILE*其他可以使用 C 函數(shù)的語言很多也提供了類似的實(shí)現(xiàn),比如 Ruby,基于 Ruby 的 git HTTP 服務(wù)器 grack 正是使用 的 popen,相比與其他語言改造的 popen,C 語言中 popen 存在了一些缺陷,比如無法同時(shí)讀寫,如果要輸出標(biāo)準(zhǔn) 錯(cuò)誤,需要在命令參數(shù)中額外的將標(biāo)準(zhǔn)錯(cuò)誤重定向到標(biāo)準(zhǔn)輸出。

在 musl libc 的中,popen 的實(shí)現(xiàn)如下:

FILE *popen(const char *cmd, const char *mode)
{
    int p[2], op, e;
    pid_t pid;
    FILE *f;
    posix_spawn_file_actions_t fa;

    if (*mode == 'r') {
        op = 0;
    } else if (*mode == 'w') {
        op = 1;
    } else {
        errno = EINVAL;
        return 0;
    }

    if (pipe2(p, O_CLOEXEC)) return NULL;
    f = fdopen(p[op], mode);
    if (!f) {
        __syscall(SYS_close, p[0]);
        __syscall(SYS_close, p[1]);
        return NULL;
    }
    FLOCK(f);

    /* If the child's end of the pipe happens to already be on the final
     * fd number to which it will be assigned (either 0 or 1), it must
     * be moved to a different fd. Otherwise, there is no safe way to
     * remove the close-on-exec flag in the child without also creating
     * a file descriptor leak race condition in the parent. */
    if (p[1-op] == 1-op) {
        int tmp = fcntl(1-op, F_DUPFD_CLOEXEC, 0);
        if (tmp < 0) {
            e = errno;
            goto fail;
        }
        __syscall(SYS_close, p[1-op]);
        p[1-op] = tmp;
    }

    e = ENOMEM;
    if (!posix_spawn_file_actions_init(&fa)) {
        if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) {
            if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0,
                (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ))) {
                posix_spawn_file_actions_destroy(&fa);
                f->pipe_pid = pid;
                if (!strchr(mode, &#39;e&#39;))
                    fcntl(p[op], F_SETFD, 0);
                __syscall(SYS_close, p[1-op]);
                FUNLOCK(f);
                return f;
            }
        }
        posix_spawn_file_actions_destroy(&fa);
    }
fail:
    fclose(f);
    __syscall(SYS_close, p[1-op]);

    errno = e;
    return 0;
}

在 Windows Visual C++ 中,popen 源碼在?C:\Program Files (x86)\Windows Kits\10\Source\${SDKVersion}\ucrt\conio\popen.cpp?, 按照 MSDN 文檔說明,Windows 32 GUI 程序,即 subsystem 是 Windows 的程序,使用 popen 可能導(dǎo)致程序無限失去響應(yīng)。

所以在筆者實(shí)現(xiàn) git-daemon 及其他 git 服務(wù)器時(shí),都不會(huì)使用 popen 這個(gè)函數(shù)。

為了支持跨平臺(tái)和簡(jiǎn)化編程,筆者在實(shí)現(xiàn) svn 代理服務(wù)器時(shí)就使用了 Boost Asio 庫,后來也用 Asio 實(shí)現(xiàn)過一個(gè) git 遠(yuǎn)程命令服務(wù), 每一個(gè)客戶端與服務(wù)器連接后,服務(wù)器啟動(dòng)程序,需要?jiǎng)?chuàng)建 3 條管道,分別是 子進(jìn)程的標(biāo)準(zhǔn)輸入 輸出 錯(cuò)誤,即 stdout stdin stderr, 然后注冊(cè)讀寫異步事件,將子進(jìn)程的輸出與錯(cuò)誤寫入到 socket 發(fā)送出去,讀取 socket 寫入到子進(jìn)程的標(biāo)準(zhǔn)輸入中。

在 POSIX 系統(tǒng)中,boost 有一個(gè)文件描述符類?boost::asio::posix::stream_descriptor?這個(gè)類不能是常規(guī)文件,以前用 go 做 HTTP 前端 沒注意就 coredump 掉。

在 Windows 系統(tǒng)中,boost 有文件句柄類?boost::asio::windows::stream_handle?此處的文件應(yīng)當(dāng)支持隨機(jī)讀取,比如命名管道(當(dāng)然 在 Windows 系統(tǒng)的,匿名管道實(shí)際上也是命名管道的一種特例實(shí)現(xiàn))。

以上兩種類都支持?async_read?async_write?,所以可以很方便的實(shí)現(xiàn)異步的讀取。

上面的做法,唯一的缺陷是性能并不是非常高,代碼邏輯也比較復(fù)雜,當(dāng)然好處是,錯(cuò)誤異??煽匾恍?/p>

在 Linux 網(wǎng)絡(luò)通信中,類似與 git 協(xié)議這樣讀取子進(jìn)程輸入輸出的服務(wù)程序的傳統(tǒng)做法是,將 子進(jìn)程的 IO 重定向到 socket, 值得注意的是 boost 中 socket 是異步非阻塞的,然而,git 命令的標(biāo)準(zhǔn)輸入標(biāo)準(zhǔn)錯(cuò)誤標(biāo)準(zhǔn)輸出都是同步的,所以在 fork 子進(jìn)程之 前,需要將 socket 設(shè)置為同步阻塞,當(dāng) fork 失敗時(shí),要設(shè)置回來。

socket_.native_non_blocking(false);

另外,為了記錄子進(jìn)程是否異常退出,需要注冊(cè)信號(hào) SIGCHLD 并且使用 waitpid 函數(shù)去等待,boost 就有?boost::asio::signal_set::async_wait?當(dāng)然,如果你開發(fā)這樣一個(gè)服務(wù),會(huì)發(fā)現(xiàn),頻繁的啟動(dòng)子進(jìn)程,響應(yīng)信號(hào),管理連接,這些操作才是性能的短板。

一般而言,Windows 平臺(tái)的 IO 并不能重定向到 socket,實(shí)際上,你如果使用 IOCP 也可以達(dá)到相應(yīng)的效率。還有,Windows 的 socket API WSASocket WSADuplicateSocket 復(fù)制句柄 DuplicateHandle ,這些可以好好利用。

其他

對(duì)于非代碼托管平臺(tái)的從業(yè)者來說,上面的相關(guān)內(nèi)容可能顯得無足輕重,不過,網(wǎng)絡(luò)編程都是殊途同歸,最后核心理念都是類似的。關(guān)于 git-daemon 如果筆者有時(shí)間會(huì)實(shí)現(xiàn)一個(gè)跨平臺(tái)的簡(jiǎn)易版并開源。


Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial PHP
1502
276