Dalam pemrograman soket, Anda membuat soket mendengarkan dan kemudian untuk setiap klien yang terhubung, Anda mendapatkan soket aliran normal yang dapat Anda gunakan untuk menangani permintaan klien. OS mengatur antrian koneksi masuk di belakang layar.
Dua proses tidak dapat diikat ke port yang sama pada saat yang sama - bagaimanapun juga secara default.
Saya bertanya-tanya apakah ada cara (pada OS terkenal mana pun, terutama Windows) untuk meluncurkan banyak contoh proses, sehingga semuanya terikat ke soket, dan dengan demikian mereka secara efektif berbagi antrian. Setiap contoh proses kemudian bisa menjadi single threaded; itu hanya akan memblokir saat menerima koneksi baru. Ketika klien terhubung, salah satu contoh proses idle akan menerima klien itu.
Ini akan memungkinkan setiap proses memiliki implementasi single-threaded yang sangat sederhana, tidak berbagi apa-apa kecuali melalui memori bersama yang eksplisit, dan pengguna akan dapat menyesuaikan bandwidth pemrosesan dengan memulai lebih banyak instance.
Apakah fitur seperti itu ada?
Edit: Bagi mereka yang bertanya "Mengapa tidak menggunakan utas?" Jelas benang adalah pilihan. Tetapi dengan beberapa utas dalam satu proses, semua objek dapat dibagikan dan perhatian besar harus dilakukan untuk memastikan bahwa objek tidak dibagikan, atau hanya terlihat oleh satu utas pada satu waktu, atau benar-benar tidak dapat diubah, dan bahasa yang paling populer dan runtime tidak memiliki dukungan bawaan untuk mengelola kompleksitas ini.
Dengan memulai beberapa proses pekerja yang identik, Anda akan mendapatkan sistem serentak yang defaultnya adalah tanpa berbagi, membuatnya lebih mudah untuk membangun implementasi yang benar dan skalabel.
sumber
Jawaban:
Anda dapat berbagi soket antara dua (atau lebih) proses di Linux dan bahkan Windows.
Di Linux (Atau OS tipe POSIX), penggunaan
fork()
akan menyebabkan anak bercabang memiliki salinan dari semua deskriptor file induk. Apa pun yang tidak ditutupnya akan terus dibagikan, dan (misalnya dengan soket mendengarkan TCP) dapat digunakan keaccept()
soket baru untuk klien. Ini adalah berapa banyak server, termasuk Apache dalam banyak kasus, berfungsi.Pada Windows, hal yang sama pada dasarnya benar, kecuali tidak ada
fork()
pemanggilan sistem sehingga proses induk perlu menggunakanCreateProcess
atau sesuatu untuk membuat proses anak (yang tentu saja dapat menggunakan eksekusi yang sama) dan perlu meneruskannya ke pegangan yang dapat diwariskan.Menjadikan soket pendengaran sebagai pegangan yang diwariskan bukanlah aktivitas yang sepenuhnya sepele, tetapi juga tidak terlalu rumit.
DuplicateHandle()
perlu digunakan untuk membuat pegangan duplikat (namun masih dalam proses induk), yang akan memiliki set flag yang diwariskan di atasnya. Kemudian Anda dapat memberikan pegangan itu dalamSTARTUPINFO
struktur ke proses anak di CreateProcess sebagaiSTDIN
,OUT
atauERR
pegangan (dengan asumsi Anda tidak ingin menggunakannya untuk hal lain).EDIT:
Membaca pustaka MDSN, tampaknya
WSADuplicateSocket
mekanisme yang lebih tepat atau lebih baik untuk melakukan ini; Ini masih tidak sepele karena proses induk / anak perlu menyelesaikan pegangan mana yang perlu diduplikasi oleh beberapa mekanisme IPC (meskipun ini bisa sesederhana file di sistem file)KLARIFIKASI:
Sebagai jawaban atas pertanyaan awal OP, tidak, banyak proses tidak bisa
bind()
; hanya proses induk asli akan memanggilbind()
,listen()
dll, proses anak hanya akan memproses permintaan olehaccept()
,send()
,recv()
dllsumber
Kebanyakan orang lain telah memberikan alasan teknis mengapa ini berhasil. Berikut beberapa kode python yang dapat Anda jalankan untuk mendemonstrasikannya sendiri:
import socket import os def main(): serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.bind(("127.0.0.1", 8888)) serversocket.listen(0) # Child Process if os.fork() == 0: accept_conn("child", serversocket) accept_conn("parent", serversocket) def accept_conn(message, s): while True: c, addr = s.accept() print 'Got connection from in %s' % message c.send('Thank you for your connecting to %s\n' % message) c.close() if __name__ == "__main__": main()
Perhatikan bahwa memang ada dua proses id yang mendengarkan:
Berikut adalah hasil dari menjalankan telnet dan programnya:
sumber
Saya ingin menambahkan bahwa soket dapat dibagikan di Unix / Linux melalui soket AF__UNIX (soket antar-proses). Apa yang tampaknya terjadi adalah deskriptor soket baru dibuat yang agak mirip dengan alias yang asli. Deskriptor soket baru ini dikirim melalui soket AFUNIX ke proses lain. Ini sangat berguna dalam kasus di mana proses tidak dapat bercabang () untuk membagikan deskriptor file itu. Misalnya, saat menggunakan pustaka yang mencegah hal ini karena masalah threading. Anda harus membuat soket domain Unix dan menggunakan libancillary untuk mengirimkan deskriptor.
Lihat:
Untuk membuat Soket AF_UNIX:
Contoh kode:
sumber
Sepertinya pertanyaan ini telah dijawab sepenuhnya oleh MarkR dan zackthehack tetapi saya ingin menambahkan bahwa Nginx adalah contoh model pewarisan soket mendengarkan.
Ini deskripsi yang bagus:
sumber
Tidak yakin seberapa relevan ini dengan pertanyaan awal, tetapi di Linux kernel 3.9 ada tambalan yang menambahkan fitur TCP / UDP: dukungan TCP dan UDP untuk opsi soket SO_REUSEPORT; Opsi soket baru memungkinkan beberapa soket pada host yang sama untuk mengikat ke port yang sama, dan dimaksudkan untuk meningkatkan kinerja aplikasi server jaringan multithread yang berjalan di atas sistem multi inti. informasi lebih lanjut dapat ditemukan di tautan LWN LWN SO_REUSEPORT di Linux Kernel 3.9 seperti yang disebutkan di tautan referensi:
opsi SO_REUSEPORT tidak standar, tetapi tersedia dalam bentuk yang serupa di sejumlah sistem UNIX lainnya (terutama, BSD, tempat idenya berasal). Tampaknya menawarkan alternatif yang berguna untuk memeras kinerja maksimum dari aplikasi jaringan yang berjalan pada sistem multi inti, tanpa harus menggunakan pola garpu.
sumber
SO_REUSEPORT
membuat kumpulan utas, di mana setiap soket berada di utas yang berbeda tetapi hanya satu soket dalam grup yang melakukanaccept
. Dapatkah Anda mengonfirmasi semua soket di grup masing-masing mendapatkan salinan data?Dimulai dengan Linux 3.9, Anda dapat mengatur SO_REUSEPORT pada soket dan kemudian memiliki beberapa proses yang tidak terkait berbagi soket itu. Itu lebih sederhana daripada skema prefork, tidak ada lagi masalah sinyal, kebocoran fd ke proses anak, dll.
Linux 3.9 memperkenalkan cara baru menulis server soket
Opsi soket SO_REUSEPORT
sumber
Memiliki satu tugas yang tugas utamanya adalah mendengarkan koneksi masuk. Ketika koneksi diterima, itu menerima koneksi - ini membuat deskriptor soket terpisah. Soket yang diterima diteruskan ke salah satu tugas pekerja Anda yang tersedia, dan tugas utama kembali mendengarkan.
sumber
Di bawah Windows (dan Linux) dimungkinkan untuk satu proses untuk membuka soket dan kemudian meneruskan soket itu ke proses lain sehingga proses kedua juga dapat menggunakan soket itu (dan meneruskannya secara bergantian, jika ingin melakukannya) .
Panggilan fungsi penting adalah WSADuplicateSocket ().
Ini mengisi struktur dengan informasi tentang soket yang ada. Struktur ini kemudian, melalui mekanisme IPC pilihan Anda, diteruskan ke proses lain yang ada (perhatikan saya katakan ada - ketika Anda memanggil WSADuplicateSocket (), Anda harus menunjukkan proses target yang akan menerima informasi yang dipancarkan).
Proses penerimaan kemudian dapat memanggil WSASocket (), meneruskan struktur informasi ini, dan menerima pegangan ke soket yang mendasarinya.
Kedua proses sekarang memegang pegangan ke soket dasar yang sama.
sumber
Kedengarannya seperti apa yang Anda inginkan adalah satu proses mendengarkan untuk klien baru dan kemudian menyerahkan koneksi setelah Anda mendapatkan koneksi. Untuk melakukan itu lintas utas mudah dan di .Net Anda bahkan memiliki metode BeginAccept dll. Untuk mengurus banyak pipa untuk Anda. Untuk menyerahkan koneksi melintasi batas proses akan menjadi rumit dan tidak akan memiliki keunggulan kinerja.
Sebagai alternatif, Anda dapat memiliki beberapa proses terikat dan mendengarkan pada soket yang sama.
Jika Anda menjalankan dua proses, masing-masing menjalankan kode di atas, ini akan berfungsi dan proses pertama tampaknya mendapatkan semua koneksi. Jika proses pertama dihentikan, proses kedua kemudian mendapatkan koneksi. Dengan berbagi soket seperti itu, saya tidak yakin persis bagaimana Windows memutuskan proses mana yang mendapatkan koneksi baru meskipun tes cepat menunjukkan proses terlama untuk mendapatkannya terlebih dahulu. Seperti apakah itu berbagi jika proses pertama sibuk atau semacamnya saya tidak tahu.
sumber
Pendekatan lain (yang menghindari banyak detail kompleks) di Windows jika Anda menggunakan HTTP, adalah menggunakan HTTP.SYS . Ini memungkinkan banyak proses untuk mendengarkan URL yang berbeda di port yang sama. Di Server 2003/2008 / Vista / 7 ini adalah cara kerja IIS, sehingga Anda dapat berbagi port dengannya. (Di XP SP2 HTTP.SYS didukung, tetapi IIS5.1 tidak menggunakannya.)
API tingkat tinggi lainnya (termasuk WCF) menggunakan HTTP.SYS.
sumber