lsof -i:8000 查出PID,而後 kill掉程序,接着就能夠了html
再來個長鏈接版Python解決法:(軟件重啓以後綁定沒有釋放,lsof -i:8080也查不出來佔用的狀況)python
端口被佔的處理: 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()