Linux端口被占用的解決(附Python專版)


先說一般情況的解決:

lsof -i:8000 查出PID,然后 kill掉程序,接着就可以了


軟件重啟之后綁定沒有釋放,lsof -i:8080也查不出來占用的情況

再來個長連接版Python解決法:(軟件重啟之后綁定沒有釋放,lsof -i:8080也查不出來占用的情況)

OSError: [Errno 98] Address already in use

端口被占的處理: tcp_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

一般情況圖示:

解決后圖示:

完整示例代碼:

from socket import socket, SOL_SOCKET, SO_REUSEADDR

def main():
    with socket() as tcp_socket:
        # 防止端口占用
        tcp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        # 綁定端口
        tcp_socket.bind(('', 8080))
        # 監聽
        tcp_socket.listen()
        # 等待
        client_socket, address = tcp_socket.accept()
        # 收發消息
        with client_socket:
            print(f"[來自{address}的消息:\n")
            msg = client_socket.recv(2048)
            if msg:
                print(msg.decode("utf-8"))
            client_socket.send(
                """HTTP/1.1 200 ok\r\nContent-Type: text/html;charset=utf-8\r\n\r\n<h1>哈哈哈</h1>"""
                .encode("utf-8"))

if __name__ == "__main__":
    main()

服務器版解決

from socket import SOL_SOCKET, SO_REUSEADDR
from socketserver import ThreadingTCPServer, BaseRequestHandler

class MyHandler(BaseRequestHandler):
    def handle(self):
        print(f"[來自{self.client_address}的消息:]")
        data = self.request.recv(2048)
        print(data)
        self.request.send(
            "HTTP/1.1 200 ok\r\nContent-Type: text/html;charset=utf-8\r\n\r\n<h1>小明,晚上吃魚湯嗎?</h1>"
            .encode("utf-8"))

def main():
    # bind_and_activate=False 手動綁定和激活
    with ThreadingTCPServer(('', 8080), MyHandler, False) as server:
        # 防止端口占用
        server.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        server.server_bind()  # 自己綁定
        server.server_activate()  # 自己激活
        server.serve_forever()

if __name__ == "__main__":
    main()

解決前:

解決后:

這個就涉及到`TCP4次握手`相關的內容了,如果不是長連接,你先斷開客戶端,再斷開服務端就不會遇到這個問題了,具體問題下次繼續探討~

有時候會這樣簡化寫(雖然簡化了,但有時候也會出現端口占用的情況)

from socket import SOL_SOCKET, SO_REUSEADDR
from socketserver import ThreadingTCPServer, BaseRequestHandler

class MyHandler(BaseRequestHandler):
    def handle(self):
        print(f"[來自{self.client_address}的消息:]")
        data = self.request.recv(2048)
        print(data)
        self.request.send(
            "HTTP/1.1 200 ok\r\nContent-Type: text/html;charset=utf-8\r\n\r\n<h1>小明,晚上吃魚湯嗎?</h1>"
            .encode("utf-8"))

def main():
    # 防止端口占用
    ThreadingTCPServer.allow_reuse_address = True
    with ThreadingTCPServer(('', 8080), MyHandler) as server:
        server.serve_forever()

if __name__ == "__main__":
    main()

源碼比較簡單,一看就懂:

def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
    BaseServer.__init__(self, server_address, RequestHandlerClass)
    self.socket = socket.socket(self.address_family,
                                self.socket_type)
    if bind_and_activate:
        try:
            # 看這
            self.server_bind()
            self.server_activate()
        except:
            self.server_close()
            raise

def server_bind(self):
    # 看這
    if self.allow_reuse_address:
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    self.socket.bind(self.server_address)
    self.server_address = self.socket.getsockname()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM