GIT ?? ???? ??
GIT? ? ?? ?? ?? ????? HTTP SSH GIT ??? GIT ????? ?? ?? ???? ????(?, URL? git://?? ???? ????)???. ?? git ?????? ?? ??? ?? ?? ??? ?? ?? ? ??? ?? ? ? ??? ?? ?? ? ? ?? ?????. ??? ?? ??? ???? ?? git ????? ??? ?? ????? ?? ?? ?? ???? ???? ????.
git? ??? ?? ???? ??? ??? ???? ?? ???? ????? git ???????. HTTP? HTTP? ???? ?? ???? ?? ?????? HTTP ?? ? ?? ??? ?????. HTTPS? ?? ??? ? ?? ??? ?????. ?? HTTP ?? ?? ?? ? ??? ?? ??? ??? ??? ??? ????.
SSH ????? ?? ??? ?? ??? ? ???? ??? ???. ??, ??? ??? ???? ?? ??? ??? ??? ? ?? ?????.
git ????? ??? ???? ??? ??? SSH? ????? ?? ??? ?? ?? ??? ????. ??? ??? ?? ??? ??? ?? ?? ??? ???? ???? ???? ?? ?????. Git ????? ??? ???????.
?? ???? ??
git ????? ?? ??? git ?? ?? ????? Documentation/technical, ? Packfile ?? ?????? ?? ? ????. TCP ??? ??? ? git? ?????? ?? ??? ?? ??? ????? ?????. 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 ]
?? ??? ????.
0033git-upload-pack /project. ??
在 C 語言中,有 popen 函數(shù),可以創(chuàng)建一個進程,并將進程的標準輸出或標準輸入創(chuàng)建成一個文件指針,即 FILE*其他可以使用 C 函數(shù)的語言很多也提供了類似的實現(xiàn),比如 Ruby,基于 Ruby 的 git HTTP 服務器 grack 正是使用 的 popen,相比與其他語言改造的 popen,C 語言中 popen 存在了一些缺陷,比如無法同時讀寫,如果要輸出標準 錯誤,需要在命令參數(shù)中額外的將標準錯誤重定向到標準輸出。
在 musl libc 的中,popen 的實現(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, 'e')) 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 可能導致程序無限失去響應。
所以在筆者實現(xiàn) git-daemon 及其他 git 服務器時,都不會使用 popen 這個函數(shù)。
為了支持跨平臺和簡化編程,筆者在實現(xiàn) svn 代理服務器時就使用了 Boost Asio 庫,后來也用 Asio 實現(xiàn)過一個 git 遠程命令服務, 每一個客戶端與服務器連接后,服務器啟動程序,需要創(chuàng)建 3 條管道,分別是 子進程的標準輸入 輸出 錯誤,即 stdout stdin stderr, 然后注冊讀寫異步事件,將子進程的輸出與錯誤寫入到 socket 發(fā)送出去,讀取 socket 寫入到子進程的標準輸入中。
在 POSIX 系統(tǒng)中,boost 有一個文件描述符類?boost::asio::posix::stream_descriptor?這個類不能是常規(guī)文件,以前用 go 做 HTTP 前端 沒注意就 coredump 掉。
在 Windows 系統(tǒng)中,boost 有文件句柄類?boost::asio::windows::stream_handle?此處的文件應當支持隨機讀取,比如命名管道(當然 在 Windows 系統(tǒng)的,匿名管道實際上也是命名管道的一種特例實現(xiàn))。
以上兩種類都支持?async_read?async_write?,所以可以很方便的實現(xiàn)異步的讀取。
上面的做法,唯一的缺陷是性能并不是非常高,代碼邏輯也比較復雜,當然好處是,錯誤異常可控一些。
在 Linux 網(wǎng)絡通信中,類似與 git 協(xié)議這樣讀取子進程輸入輸出的服務程序的傳統(tǒng)做法是,將 子進程的 IO 重定向到 socket, 值得注意的是 boost 中 socket 是異步非阻塞的,然而,git 命令的標準輸入標準錯誤標準輸出都是同步的,所以在 fork 子進程之 前,需要將 socket 設置為同步阻塞,當 fork 失敗時,要設置回來。
socket_.native_non_blocking(false);
另外,為了記錄子進程是否異常退出,需要注冊信號 SIGCHLD 并且使用 waitpid 函數(shù)去等待,boost 就有?boost::asio::signal_set::async_wait?當然,如果你開發(fā)這樣一個服務,會發(fā)現(xiàn),頻繁的啟動子進程,響應信號,管理連接,這些操作才是性能的短板。
一般而言,Windows 平臺的 IO 并不能重定向到 socket,實際上,你如果使用 IOCP 也可以達到相應的效率。還有,Windows 的 socket API WSASocket WSADuplicateSocket 復制句柄 DuplicateHandle ,這些可以好好利用。
其他
對于非代碼托管平臺的從業(yè)者來說,上面的相關內(nèi)容可能顯得無足輕重,不過,網(wǎng)絡編程都是殊途同歸,最后核心理念都是類似的。關于 git-daemon 如果筆者有時間會實現(xiàn)一個跨平臺的簡易版并開源。

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)