Bagaimana Anda terhubung ke server dengan python?

Soket digunakan hampir di mana-mana, tetapi merupakan salah satu teknologi yang paling sering disalahpahami. Ini adalah ikhtisar soket 10.000 kaki. Ini sebenarnya bukan tutorial - Anda masih harus bekerja untuk menjalankan semuanya. Itu tidak mencakup poin-poin bagus (dan ada banyak dari mereka), tapi saya harap ini akan memberi Anda latar belakang yang cukup untuk mulai menggunakannya dengan baik.

Soket

Saya hanya akan berbicara tentang INET (mis. e. IPv4), tetapi mereka menyumbang setidaknya 99% dari soket yang digunakan. Dan saya hanya akan berbicara tentang STREAM (mis. e. TCP) soket - kecuali Anda benar-benar tahu apa yang Anda lakukan (dalam hal ini HOWTO ini bukan untuk Anda. ), Anda akan mendapatkan perilaku dan kinerja yang lebih baik dari soket STREAM daripada yang lainnya. Saya akan mencoba untuk menjernihkan misteri tentang apa itu soket, serta beberapa petunjuk tentang cara bekerja dengan soket pemblokiran dan non-pemblokiran. Tapi saya akan mulai dengan berbicara tentang memblokir soket. Anda harus mengetahui cara kerjanya sebelum berurusan dengan soket non-pemblokiran

Bagian dari masalah dalam memahami hal-hal ini adalah bahwa "soket" dapat berarti sejumlah hal yang agak berbeda, bergantung pada konteksnya. Jadi pertama-tama, mari kita bedakan antara soket "klien" - titik akhir percakapan, dan soket "server", yang lebih mirip operator switchboard. Aplikasi klien (browser Anda, misalnya) menggunakan soket "klien" secara eksklusif;

Sejarah

Dari berbagai bentuk IPC, soket adalah yang paling populer. Pada platform apa pun, kemungkinan ada bentuk IPC lain yang lebih cepat, tetapi untuk komunikasi lintas platform, soket adalah satu-satunya permainan di kota.

Mereka ditemukan di Berkeley sebagai bagian dari rasa BSD Unix. Mereka menyebar seperti api dengan internet. Dengan alasan yang bagus - kombinasi soket dengan INET membuat berbicara dengan mesin sewenang-wenang di seluruh dunia menjadi sangat mudah (setidaknya dibandingkan dengan skema lain)

Membuat Soket

Secara kasar, ketika Anda mengklik tautan yang membawa Anda ke halaman ini, browser Anda melakukan hal seperti berikut

# create an INET, STREAMing socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# now connect to the web server on port 80 - the normal http port
s.connect(("www.python.org", 80))

Ketika connect selesai, soket s dapat digunakan untuk mengirimkan permintaan teks halaman. Soket yang sama akan membaca balasannya, lalu dihancurkan. Benar, hancur. Soket klien biasanya hanya digunakan untuk satu pertukaran (atau sekumpulan kecil pertukaran berurutan)

Apa yang terjadi di server web sedikit lebih rumit. Pertama, server web membuat "soket server"

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_

Beberapa hal yang perlu diperhatikan. kami menggunakan socket.gethostname() sehingga soket akan terlihat oleh dunia luar. Jika kami telah menggunakan s.bind(('localhost', 80)) atau s.bind(('127.0.0.1', 80)) kami masih memiliki soket "server", tetapi yang hanya terlihat di dalam mesin yang sama.

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
0 menentukan bahwa soket dapat dijangkau oleh alamat apa pun yang dimiliki mesin

Hal kedua yang perlu diperhatikan. port nomor rendah biasanya disediakan untuk layanan "terkenal" (HTTP, SNMP dll). Jika Anda bermain-main, gunakan angka tinggi yang bagus (4 digit)

Akhirnya, argumen untuk

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_1 memberi tahu perpustakaan soket bahwa kami ingin mengantri sebanyak 5 permintaan koneksi (maks normal) sebelum menolak koneksi luar. Jika sisa kode ditulis dengan benar, itu pasti banyak

Sekarang kita memiliki soket "server", mendengarkan pada port 80, kita dapat memasuki mainloop dari server web

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
_

Sebenarnya ada 3 cara umum di mana loop ini dapat bekerja - mengirim utas untuk menangani

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
2, membuat proses baru untuk menangani
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
2, atau merestrukturisasi aplikasi ini untuk menggunakan soket non-pemblokiran, dan multipleks antara soket "server" kami dan
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
2 aktif . Lebih lanjut tentang itu nanti. Hal penting yang harus dipahami sekarang adalah ini. ini semua yang dilakukan soket "server". Itu tidak mengirim data apa pun. Itu tidak menerima data apa pun. Itu hanya menghasilkan soket "klien". Setiap
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_2 dibuat sebagai respons terhadap soket "klien" lain yang melakukan
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
7 ke host dan port tempat kita terikat. Segera setelah kami membuat
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
2 itu, kami kembali mendengarkan untuk koneksi lainnya. Kedua "klien" bebas untuk mengobrol - mereka menggunakan beberapa port yang dialokasikan secara dinamis yang akan didaur ulang saat percakapan berakhir

IPC

Jika Anda membutuhkan IPC cepat antara dua proses pada satu mesin, Anda harus melihat ke dalam pipa atau memori bersama. Jika Anda memutuskan untuk menggunakan soket AF_INET, ikat soket "server" ke

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
9. Pada sebagian besar platform, ini akan mengambil jalan pintas di sekitar beberapa lapisan kode jaringan dan menjadi sedikit lebih cepat

Lihat juga

IPC lintas platform terintegrasi ke dalam API tingkat yang lebih tinggi

Menggunakan Soket

Hal pertama yang perlu diperhatikan, adalah bahwa soket "klien" browser web dan soket "klien" server web adalah binatang buas yang identik. Artinya, ini adalah percakapan "peer to peer". Atau dengan kata lain, sebagai desainer, Anda harus memutuskan apa aturan etiket untuk percakapan. Biasanya, soket connect_ memulai percakapan, dengan mengirimkan permintaan, atau mungkin tanda masuk. Tapi itu keputusan desain - itu bukan aturan soket

Sekarang ada dua set kata kerja yang digunakan untuk komunikasi. Anda dapat menggunakan

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2 dan
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3, atau Anda dapat mengubah soket klien Anda menjadi binatang seperti file dan menggunakan
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
4 dan
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
5. Yang terakhir adalah cara Java menampilkan soketnya. Saya tidak akan membicarakannya di sini, kecuali untuk memperingatkan Anda bahwa Anda perlu menggunakan
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
6 pada soket. Ini adalah "file" buffer, dan kesalahan umum adalah
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
5 sesuatu, lalu
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
4 untuk balasan. Tanpa
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
6 di sana, Anda mungkin menunggu selamanya untuk balasan, karena permintaan mungkin masih ada di buffer output Anda

Sekarang kita sampai pada batu sandungan utama soket -

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2 dan
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 beroperasi pada buffer jaringan. Mereka tidak perlu menangani semua byte yang Anda berikan (atau harapkan dari mereka), karena fokus utama mereka adalah menangani buffer jaringan. Secara umum, mereka kembali ketika buffer jaringan terkait telah diisi (
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2) atau dikosongkan (
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3). Mereka kemudian memberi tahu Anda berapa banyak byte yang mereka tangani. Merupakan tanggung jawab Anda untuk menelepon mereka lagi sampai pesan Anda benar-benar ditangani

Ketika

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
_3 mengembalikan 0 byte, itu berarti pihak lain telah menutup (atau sedang dalam proses penutupan) koneksi. Anda tidak akan menerima data lagi pada sambungan ini. Pernah. Anda mungkin berhasil mengirim data;

Protokol seperti HTTP menggunakan soket hanya untuk satu transfer. Klien mengirim permintaan, lalu membaca balasan. Itu dia. Soket dibuang. Ini berarti klien dapat mendeteksi akhir balasan dengan menerima 0 byte

Tetapi jika Anda berencana menggunakan kembali soket Anda untuk transfer lebih lanjut, Anda perlu menyadari bahwa tidak ada EOT pada soket. saya ulangi. jika soket

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2 atau
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 kembali setelah menangani 0 byte, koneksi telah terputus. Jika koneksi belum terputus, Anda dapat menunggu di
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 selamanya, karena soket tidak akan memberi tahu Anda bahwa tidak ada lagi yang perlu dibaca (untuk saat ini). Sekarang jika Anda memikirkannya sedikit, Anda akan menyadari kebenaran mendasar tentang soket. pesan harus memiliki panjang tetap (yuck), atau dibatasi (mengangkat bahu), atau menunjukkan berapa panjangnya (jauh lebih baik), atau diakhiri dengan mematikan koneksi. Pilihan sepenuhnya ada di tangan Anda, (tetapi beberapa cara lebih benar dari yang lain)

Dengan asumsi Anda tidak ingin mengakhiri koneksi, solusi paling sederhana adalah pesan dengan panjang tetap

class MySocket:
    """demonstration class only
      - coded for clarity, not efficiency
    """

    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(
                            socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock

    def connect(self, host, port):
        self.sock.connect((host, port))

    def mysend(self, msg):
        totalsent = 0
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent

    def myreceive(self):
        chunks = []
        bytes_recd = 0
        while bytes_recd < MSGLEN:
            chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
            if chunk == b'':
                raise RuntimeError("socket connection broken")
            chunks.append(chunk)
            bytes_recd = bytes_recd + len(chunk)
        return b''.join(chunks)

Kode pengiriman di sini dapat digunakan untuk hampir semua skema perpesanan - dengan Python Anda mengirim string, dan Anda dapat menggunakan

class MySocket:
    """demonstration class only
      - coded for clarity, not efficiency
    """

    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(
                            socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock

    def connect(self, host, port):
        self.sock.connect((host, port))

    def mysend(self, msg):
        totalsent = 0
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent

    def myreceive(self):
        chunks = []
        bytes_recd = 0
        while bytes_recd < MSGLEN:
            chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
            if chunk == b'':
                raise RuntimeError("socket connection broken")
            chunks.append(chunk)
            bytes_recd = bytes_recd + len(chunk)
        return b''.join(chunks)
8 untuk menentukan panjangnya (meskipun telah menyematkan
class MySocket:
    """demonstration class only
      - coded for clarity, not efficiency
    """

    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(
                            socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock

    def connect(self, host, port):
        self.sock.connect((host, port))

    def mysend(self, msg):
        totalsent = 0
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent

    def myreceive(self):
        chunks = []
        bytes_recd = 0
        while bytes_recd < MSGLEN:
            chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
            if chunk == b'':
                raise RuntimeError("socket connection broken")
            chunks.append(chunk)
            bytes_recd = bytes_recd + len(chunk)
        return b''.join(chunks)
9 karakter). Sebagian besar kode penerima yang menjadi lebih kompleks. (Dan di C, itu tidak jauh lebih buruk, kecuali Anda tidak dapat menggunakan
ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)
0 jika pesan telah menyematkan
class MySocket:
    """demonstration class only
      - coded for clarity, not efficiency
    """

    def __init__(self, sock=None):
        if sock is None:
            self.sock = socket.socket(
                            socket.AF_INET, socket.SOCK_STREAM)
        else:
            self.sock = sock

    def connect(self, host, port):
        self.sock.connect((host, port))

    def mysend(self, msg):
        totalsent = 0
        while totalsent < MSGLEN:
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent

    def myreceive(self):
        chunks = []
        bytes_recd = 0
        while bytes_recd < MSGLEN:
            chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
            if chunk == b'':
                raise RuntimeError("socket connection broken")
            chunks.append(chunk)
            bytes_recd = bytes_recd + len(chunk)
        return b''.join(chunks)
9s. )

Penyempurnaan yang paling mudah adalah menjadikan karakter pertama pesan sebagai indikator jenis pesan, dan jenisnya menentukan panjangnya. Sekarang Anda memiliki dua

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 - yang pertama untuk mendapatkan (setidaknya) karakter pertama sehingga Anda dapat mencari panjangnya, dan yang kedua dalam satu lingkaran untuk mendapatkan sisanya. Jika Anda memutuskan untuk menggunakan rute yang dibatasi, Anda akan menerima beberapa ukuran potongan acak, (4096 atau 8192 sering cocok untuk ukuran buffer jaringan), dan memindai apa yang telah Anda terima untuk pembatas

Satu komplikasi yang harus diperhatikan. jika protokol percakapan Anda memungkinkan beberapa pesan untuk dikirim kembali ke belakang (tanpa semacam balasan), dan Anda memberikan

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 ukuran potongan yang sewenang-wenang, Anda mungkin akan membaca awal dari pesan berikut. Anda harus mengesampingkannya dan mempertahankannya, sampai dibutuhkan

Mengawali pesan dengan panjangnya (misalnya, 5 karakter numerik) menjadi lebih rumit, karena (percaya atau tidak), Anda mungkin tidak mendapatkan semua 5 karakter dalam satu

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3. Dalam bermain-main, Anda akan lolos begitu saja; . Menjijikan. Ini juga saat Anda akan menemukan bahwa
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2 tidak selalu berhasil menyingkirkan semuanya sekaligus. Dan meskipun telah membaca ini, pada akhirnya Anda akan digigit olehnya

Demi kepentingan ruang, membangun karakter Anda, (dan mempertahankan posisi kompetitif saya), penyempurnaan ini dibiarkan sebagai latihan bagi pembaca. Mari kita beralih ke pembersihan

Data Biner

Sangat mungkin untuk mengirim data biner melalui soket. Masalah utamanya adalah tidak semua mesin menggunakan format yang sama untuk data biner. Misalnya, adalah big-endian, dengan byte paling signifikan terlebih dahulu, jadi integer 16 bit dengan nilai

ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)
7 akan menjadi dua byte hex
ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)
8. Namun, sebagian besar prosesor umum (x86/AMD64, ARM, RISC-V), adalah little-endian, dengan byte paling signifikan terlebih dahulu -
ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)
7 yang sama akan menjadi connect0

Pustaka soket memiliki panggilan untuk mengonversi bilangan bulat 16 dan 32 bit - connect1 di mana "n" berarti jaringan dan "h" berarti host, "s" berarti pendek dan "l" berarti panjang. Di mana urutan jaringan adalah urutan host, ini tidak melakukan apa-apa, tetapi jika mesin dibalik byte, ini menukar byte dengan tepat

Pada hari-hari mesin 64-bit ini, representasi data biner ASCII seringkali lebih kecil daripada representasi biner. Itu karena jumlah waktu yang mengejutkan, sebagian besar bilangan bulat memiliki nilai 0, atau mungkin 1. String connect2 akan menjadi dua byte, sedangkan integer 64-bit penuh akan menjadi 8. Tentu saja, ini tidak cocok dengan pesan dengan panjang tetap. Keputusan, keputusan

Memutuskan

Sebenarnya, Anda seharusnya menggunakan connect3 pada soket sebelum Anda connect4 itu. connect_3 adalah penasehat untuk soket di ujung lainnya. Bergantung pada argumen yang Anda berikan, itu bisa berarti "Saya tidak akan mengirim lagi, tetapi saya akan tetap mendengarkan", atau "Saya tidak mendengarkan, selamat tinggal. ”. Namun, sebagian besar pustaka soket begitu terbiasa dengan pemrogram yang lalai menggunakan etiket ini sehingga biasanya connect4 sama dengan connect7. Jadi dalam kebanyakan situasi, connect3 eksplisit tidak diperlukan

Salah satu cara untuk menggunakan connect_3 secara efektif adalah dalam pertukaran mirip HTTP. Klien mengirimkan permintaan dan kemudian melakukan s0. Ini memberi tahu server “Klien ini telah selesai mengirim, tetapi masih dapat menerima. ” Server dapat mendeteksi "EOF" dengan menerima 0 byte. Dapat diasumsikan memiliki permintaan lengkap. Server mengirim balasan. Jika

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
_2 selesai dengan sukses maka, memang, klien masih menerima

Python mengambil shutdown otomatis selangkah lebih maju, dan mengatakan bahwa ketika soket dikumpulkan sampah, itu akan secara otomatis melakukan connect4 jika diperlukan. Tetapi mengandalkan ini adalah kebiasaan yang sangat buruk. Jika soket Anda hilang begitu saja tanpa melakukan connect4, soket di ujung lainnya mungkin menggantung tanpa batas waktu, mengira Anda hanya lambat. Harap connect_4 soket Anda setelah selesai

Ketika Soket Mati

Mungkin hal terburuk tentang menggunakan soket pemblokiran adalah apa yang terjadi ketika pihak lain turun dengan keras (tanpa melakukan connect4). Soket Anda kemungkinan akan hang. TCP adalah protokol yang andal, dan akan menunggu sangat lama sebelum menyerah pada koneksi. Jika Anda menggunakan utas, seluruh utas pada dasarnya sudah mati. Tidak banyak yang dapat Anda lakukan tentang itu. Selama Anda tidak melakukan sesuatu yang bodoh, seperti menahan kunci saat membaca pemblokiran, utas tidak terlalu menghabiskan banyak sumber daya. Jangan mencoba mematikan utas - salah satu alasan utas lebih efisien daripada proses adalah karena utas menghindari overhead yang terkait dengan daur ulang otomatis sumber daya. Dengan kata lain, jika Anda berhasil mematikan utas, seluruh proses Anda kemungkinan besar akan kacau

Soket Tanpa Pemblokiran

Jika Anda sudah memahami sebelumnya, Anda sudah tahu sebagian besar dari apa yang perlu Anda ketahui tentang mekanisme penggunaan soket. Anda masih akan menggunakan panggilan yang sama, dengan cara yang hampir sama. Hanya saja, jika Anda melakukannya dengan benar, aplikasi Anda akan hampir habis-habisan

Di Python, Anda menggunakan s_6 untuk membuatnya tidak memblokir. Di C, ini lebih kompleks, (untuk satu hal, Anda harus memilih antara rasa BSD s7 dan rasa POSIX yang hampir tidak dapat dibedakan s8, yang sama sekali berbeda dari s9), tetapi idenya sama persis. Anda melakukan ini setelah membuat soket, tetapi sebelum menggunakannya. (Sebenarnya, jika Anda gila, Anda bisa bolak-balik. )

Perbedaan mekanis utama adalah bahwa

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
2,
while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3, connect dan socket.gethostname()3 dapat kembali tanpa melakukan apa pun. Anda memiliki (tentu saja) sejumlah pilihan. Anda dapat memeriksa kode pengembalian dan kode kesalahan dan umumnya membuat diri Anda gila. Jika Anda tidak mempercayai saya, cobalah kapan-kapan. Aplikasi Anda akan tumbuh besar, bermasalah, dan menyedot CPU. Jadi mari kita lewati solusi mati otak dan lakukan dengan benar

Gunakan

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_5

Di C, pengkodean

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_5 cukup rumit. Di Python, ini sangat mudah, tetapi cukup mirip dengan versi C sehingga jika Anda memahami
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
5 dengan Python, Anda akan mengalami sedikit masalah dengannya di C

ready_to_read, ready_to_write, in_error = \
               select.select(
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout)

Anda melewati

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_5 tiga daftar. yang pertama berisi semua soket yang mungkin ingin Anda coba baca; . Anda harus mencatat bahwa soket dapat masuk ke lebih dari satu daftar. Panggilan
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
5 memblokir, tetapi Anda dapat memberikan waktu tunggu. Ini umumnya adalah hal yang masuk akal untuk dilakukan - berikan waktu tunggu yang lama (katakanlah sebentar) kecuali Anda memiliki alasan yang kuat untuk melakukan sebaliknya

Sebagai imbalannya, Anda akan mendapatkan tiga daftar. Mereka berisi soket yang sebenarnya dapat dibaca, dapat ditulis, dan dalam kesalahan. Masing-masing daftar ini adalah subset (kemungkinan kosong) dari daftar terkait yang Anda berikan

Jika soket ada dalam daftar keluaran yang dapat dibaca, Anda dapat sedekat mungkin dengan yang pernah kami dapatkan dalam bisnis ini bahwa

while True:
    # accept connections from outside
    (clientsocket, address) = serversocket.accept()
    # now do something with the clientsocket
    # in this case, we'll pretend this is a threaded server
    ct = client_thread(clientsocket)
    ct.run()
3 pada soket itu akan mengembalikan sesuatu. Ide yang sama untuk daftar yang dapat ditulis. Anda akan dapat mengirim sesuatu. Mungkin tidak semua yang Anda inginkan, tetapi ada sesuatu yang lebih baik daripada tidak sama sekali. (Sebenarnya, setiap soket yang cukup sehat akan kembali sebagai dapat ditulisi - itu hanya berarti tersedia ruang buffer jaringan keluar. )

Jika Anda memiliki soket "server", masukkan ke dalam daftar potential_readers. Jika muncul dalam daftar yang dapat dibaca, socket.gethostname()3 Anda (hampir pasti) akan berfungsi. Jika Anda telah membuat soket baru untuk connect ke orang lain, masukkan ke dalam daftar penulis_potensial. Jika itu muncul dalam daftar yang dapat ditulisi, Anda memiliki peluang yang layak untuk terhubung

Sebenarnya,

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_5 dapat berguna bahkan dengan soket pemblokiran. Ini adalah salah satu cara untuk menentukan apakah Anda akan memblokir - soket kembali dapat dibaca ketika ada sesuatu di buffer. Namun, ini masih tidak membantu dengan masalah menentukan apakah ujung yang lain sudah selesai, atau hanya sibuk dengan hal lain

Peringatan portabilitas. Di Unix,

# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
5 berfungsi baik dengan soket maupun file. Jangan coba ini di Windows. Di Windows,
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)
_5 hanya berfungsi dengan soket. Perhatikan juga bahwa di C, banyak opsi soket yang lebih canggih dilakukan secara berbeda di Windows. Faktanya, di Windows saya biasanya menggunakan utas (yang bekerja sangat, sangat baik) dengan soket saya

Bagaimana cara saya terhubung ke server dengan python?

Server Sederhana . Selanjutnya, panggil metode accept dari objek yang dikembalikan. Metode ini menunggu hingga klien terhubung ke port yang Anda tentukan, lalu mengembalikan objek koneksi yang mewakili koneksi ke klien tersebut. call bind(hostname, port) function to specify a port for your service on the given host. Next, call the accept method of the returned object. This method waits until a client connects to the port you specified, and then returns a connection object that represents the connection to that client.

Bagaimana cara menghubungkan server ke klien dengan python?

Langkah pertama adalah mengimpor modul soket dan kemudian membuat soket seperti yang Anda lakukan saat membuat server. Kemudian, untuk membuat koneksi antara server-klien, Anda perlu menggunakan metode connect() dengan menentukan (host, port) .

Bagaimana cara saya mendengarkan server python?

Server memiliki metode bind() yang mengikatnya ke IP dan port tertentu sehingga dapat mendengarkan permintaan masuk pada IP dan port tersebut. Server memiliki metode listen() yang menempatkan server ke mode mendengarkan . Hal ini memungkinkan server untuk mendengarkan koneksi masuk. Dan terakhir server memiliki metode accept() dan close().

Apa yang dilakukan connect () dengan python?

Itu. fungsi connect() adalah menghubungkan soket TCP ke server jarak jauh, yang memungkinkan data dikirim ke dan diterima dari server . Dalam kasus Anda, Anda menggunakan soket TCP untuk mengirim perintah HTTP, dan menerima respons HTTP yang sesuai.