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

 

posted @ 2018-11-22 20:37  鲲逸鹏  阅读(999)  评论(0编辑  收藏