您的位置:首页 > 运维架构 > Linux

Linux端口被占用的解决(附Python专版)

2018-11-22 20:37 597 查看

先说一般情况的解决:

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

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: