Saya baru mengenal pemrograman server soket Python, saya mengikuti contoh ini untuk men-setup server menggunakan kerangka socketserver. Berdasarkan komentar, menekan Ctrl-C akan menghentikan server tetapi ketika saya mencoba menjalankannya lagi, saya mendapatkan

OSError: [Errno 98] Address already in use

Yang membuat saya harus mematikan proses secara manual menggunakan terminal.

Berdasarkan pemahaman saya, KeyboardInterrupt dianggap sebagai salah satu jenis pengecualian dalam Python, dan ketika pengecualian terjadi di blok with, Python juga akan memanggil fungsi __exit__() untuk membersihkan. Saya telah mencoba membuat fungsi __exit__() di kelas penangan TCP tetapi itu sepertinya tidak memperbaiki masalah.

Adakah yang tahu cara melepaskan ikatan soket ketika pengecualian dinaikkan?

Server.py

import socketserver
from threading import Thread

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())
    
    # Self-written function to try to make Python close the server properly
    def __exit__(self):
        shutdown_thread = Thread(target=server.shutdown)
        shutdown_thread.start()
           

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        # Activate the server; this will keep running until you
        # interrupt the program with Ctrl-C
        server.serve_forever()
0
Songg Tùng 13 Mei 2021, 01:12

2 jawaban

Jawaban Terbaik

Ini bukan hal Python, ini adalah artefak dari TCP. Soket yang tampaknya tertutup sebenarnya dibiarkan dalam keadaan terbuka sebagian bahkan setelah aplikasi mati. Untuk menyiasatinya, gunakan

socketterver.TCPServer.allow_reuse_address = True

Sebelum membuat server Anda. Ini mengaktifkan opsi soket SO_REUSEADDR yang mengesampingkan perilaku ini.

1
Tim Roberts 12 Mei 2021, 22:20

Seperti yang dijelaskan @Tim Roberts bahwa itu adalah artefak TCP. Selain metodenya, Anda juga dapat meneruskan flag SO_REUSEADDR secara manual dengan menggunakan

socket.setsockopt(socket.SO_REUSEADDR)

Ini mungkin berguna ketika Anda melewati beberapa socketopt atau ketika Anda menginginkan sesuatu yang lebih akrab dengan jaringan tingkat rendah di C.

1
kinshukdua 12 Mei 2021, 22:26