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

先說通常狀況的解決:

lsof -i:8000 查出PID,而後 kill掉程序,接着就能夠了html


軟件重啓以後綁定沒有釋放,lsof -i:8080也查不出來佔用的狀況

再來個長鏈接版Python解決法:(軟件重啓以後綁定沒有釋放,lsof -i:8080也查不出來佔用的狀況)python

OSError: [Errno 98] Address already in use

端口被佔的處理: tcp_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)服務器

通常狀況圖示:socket

解決後圖示:tcp

完整示例代碼:spa

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()

解決前:code

解決後:
server

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

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

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()
相關文章
相關標籤/搜索