如何解决python socket server重启后端口被占用的问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何解决python socket server重启后端口被占用的问题相关的知识,希望对你有一定的参考价值。
本文介绍下,在solaris 系统下,python socket server重启后,提示端口被占用,telnet端口失败。这里给出一个解决方法,有需要的朋友参考下。在solaris 系统下,socket server被重启后,提示端口被占用,telnet端口又是不成功的,说明服务已被关闭。
通过netstat可以看到端口还处于于fin_wait_2状态,solaris要4分钟才能关闭。
遇到这个问题时,可以采用如下的方法解决,以减少等待时间。
1,加上s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)。
代码:
复制代码代码示例:
self.host=socket.gethostbyname(socket.gethostname())
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((self.host,self.port))
s.listen(5)
2,修改系统fin_wait,time_wait的时间设置。这个时间改短,也利于系统系能。
修改方法
查看或设置:
使用get命令来确定当前时间间隔,并使用set命令将时间间隔指定为30秒。
例如:
复制代码代码示例:
ndd -get /dev/tcp tcp_time_wait_interval
ndd -set /dev/tcp tcp_time_wait_interval 30000
缺省值:对于 Solaris 操作系统,缺省等待时间间隔为 240000 毫秒(即 4 分钟)。
建议值:60000 毫秒。
Solaris TCP_FIN_WAIT_2_FLUSH_INTERVAL
描述:
指定禁止处于FIN_WAIT_2状态的连接保持该状态的计时器时间间隔。
当连接比率较高时,这将累积大量的TCP/IP连接,从而导致服务器性能下降。在高峰时间段,服务器会发 生延迟。
如果服务器延迟,netstat命令显示对HTTP Server打开的许多套接字处于CLOSE_WAIT或FIN_WAIT_2状态。
明显的延迟可能会长达4分钟,其间服务器无法发送任何响应,但是CPU利用率保持很高,所有活动都在系统进程中。
查看和设置:
使用get命令来确定当前时间间隔,并使用set命令将时间间隔指定为67.5秒。
例如:
复制代码代码示例:
ndd -get /dev/tcp tcp_fin_wait_2_flush_interval
ndd -set /dev/tcp tcp_fin_wait_2_flush_interval 67500
缺省值:675000 毫秒
建议值:67500 毫秒
Solaris TCP_KEEPALIVE_INTERVAL
描述:
“保持活动”包确保连接保持活动和已建立状态。
查看或设置:
使用ndd命令来确定当前值或设置该值。
例如:
复制代码代码示例:
ndd -set /dev/tcp tcp_keepalive_interval 300000
缺省值:7200000 毫秒
建议值:15000 毫秒 参考技术A
可以使用socketserver模块
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
"""
self.request=======conn
:return:
"""
while 1:
try:
data = self.request.recv(1024).decode("utf8") # 阻塞函数
print("data", data)
# 针对linux,ios系统
if len(data) == 0 or data == "q":
break
res = input("回复>>>").encode("utf8")
self.request.sendall(res)
# 针对window系统
except Exception as e:
break
self.request.close()
server=socketserver.ThreadingTCPServer(("127.0.0.1",8008),MyServer)
server.serve_forever()
Python网络编程03/ low版解决粘包问题
目录
Python网络编程03/ low版解决粘包问题
1.操作系统的缓存区
1.为什么存在缓冲区
1. 暂时存储一些数据.
2. 缓冲区存在如果你的网络波动,保证数据的收发稳定,匀速.
缺点: 造成了粘包现象之一.
2.基于TCP协议的socket循环通信
2.1 服务端(server)
# import socket
#
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen()
# listen: 允许5个人链接我,剩下的链接也可以链接,等待.
#
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# print(f'链接来了: conn,addr')
#
# while 1:
# try:
# from_client_data = conn.recv(1024) # 最多接受1024字节
#
# if from_client_data.upper() == b'Q':
# print('客户端正常退出聊天了')
# break
#
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
# to_client_data = input('>>>').strip().encode('utf-8')
# conn.send(to_client_data)
# except ConnectionResetError:
# print('客户端链接中断了')
# break
# conn.close()
# phone.close()
2.2客户端(client)
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
# while 1:
# to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
# if not to_server_data:
# # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
# print('发送内容不能为空')
# continue
# phone.send(to_server_data)
# if to_server_data.upper() == b'Q':
# break
# from_server_data = phone.recv(1024) # 最多接受1024字节
# print(f'来自服务端消息:from_server_data.decode("utf-8")')
#
# phone.close()
#
# # s1 = 'q'
# # s2 = b'q'
# # s3 = '中国'
# # print(s3.encode('utf-8'))
# # print(type(s1),type(s2))
#
# # s1 = 'q'
# # print(s1.encode('utf-8'))
#
# # bytes类型:
# # ASCII字符: 在字符串前面b''
# # 非ASCII字符: encode 转化成 bytes类型
3.基于TCP协议的socket链接+循环 通信
3.1服务端(server)
# import socket
#
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(2)
# # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
#
# while 1:
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# print(f'链接来了: conn,addr')
#
# while 1:
# try:
# from_client_data = conn.recv(1024) # 最多接受1024字节
#
# if from_client_data.upper() == b'Q':
# print('客户端正常退出聊天了')
# break
#
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
# to_client_data = input('>>>').strip().encode('utf-8')
# conn.send(to_client_data)
# except ConnectionResetError:
# print('客户端链接中断了')
# break
# conn.close()
# phone.close()
3.2 客户端(client)
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
# while 1:
# to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
# if not to_server_data:
# # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
# print('发送内容不能为空')
# continue
# phone.send(to_server_data)
# if to_server_data.upper() == b'Q':
# break
# from_server_data = phone.recv(1024) # 最多接受1024字节
# print(f'来自服务端消息:from_server_data.decode("utf-8")')
#
# phone.close()
4.基于TCP协议的socket应用实例:执行远程命令
4.1服务端(server)
# import socket
# import subprocess
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(2)
# # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
#
# while 1:
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# print(f'链接来了: conn,addr')
#
# while 1:
# try:
#
# from_client_data = conn.recv(1024) # 最多接受1024字节
#
#
# if from_client_data.upper() == b'Q':
# print('客户端正常退出聊天了')
# break
#
# obj = subprocess.Popen(from_client_data.decode('utf-8'),
# shell=True,
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE,
#
# )
# result = obj.stdout.read() + obj.stderr.read()
#
# conn.send(result)
# except ConnectionResetError:
# print('客户端链接中断了')
# break
# conn.close()
# phone.close()
#
#
#
#
# # shell: 命令解释器,相当于调用cmd 执行指定的命令。
# # stdout:正确结果丢到管道中。
# # stderr:错了丢到另一个管道中。
# # windows操作系统的默认编码是gbk编码。
#
4.2客户端(client)
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
# while 1:
# to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
# if not to_server_data:
# # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
# print('发送内容不能为空')
# continue
# phone.send(to_server_data)
# if to_server_data.upper() == b'Q':
# break
# from_server_data = phone.recv(1024) # 最多接受1024字节
# print(f'from_server_data.decode("gbk")')
#
# phone.close()
5.粘包现象
5.1服务端(server)
# 1. 粘包第一种: send的数据过大,大于对方recv的上限时,对方第二次recv时,会接收上一次没有recv完的剩余的数据。
# import socket
# import subprocess
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(2)
# # listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
#
# while 1:
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# # print(f'链接来了: conn,addr')
#
# while 1:
# try:
#
# from_client_data = conn.recv(1024) # 最多接受1024字节
#
#
# if from_client_data.upper() == b'Q':
# print('客户端正常退出聊天了')
# break
#
# obj = subprocess.Popen(from_client_data.decode('utf-8'),
# shell=True,
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE,
#
# )
# result = obj.stdout.read() + obj.stderr.read()
# print(f'总字节数:len(result)')
# conn.send(result)
# except ConnectionResetError:
# print('客户端链接中断了')
# break
# conn.close()
# phone.close()
# s1 = '太白jx'
# # print(len(s1))
# b1 = s1.encode('utf-8')
# # print(b1)
# print(len(b1))
'''
客户端 服务端
第一次: ipconfig 317字节
300个字节 17个字节
客户端 服务端
第二次: dir 376字节
17字节 376字节
'''
# 2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去.
# import socket
#
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(5)
#
#
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
#
# from_client_data = conn.recv(1024) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
# conn.close()
# phone.close()
# 展示一些收发的问题。
5.2客户端(client)
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
# while 1:
# to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
# if not to_server_data:
# # 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
# print('发送内容不能为空')
# continue
# phone.send(to_server_data)
# if to_server_data.upper() == b'Q':
# break
# from_server_data = phone.recv(300) # 最多接受1024字节
# # print(f'from_server_data.decode("gbk")')
# print(len(from_server_data))
#
# phone.close()
# 2. 连续短暂的send多次(数据量很小),你的数据会统一发送出去.
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
#
#
# phone.send(b'he')
# phone.send(b'll')
# phone.send(b'o')
#
#
# phone.close()
# Nigle算法
5.3展示收发问题的服务端(server)
# 发多次收一次
# import socket
#
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(5)
#
#
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
#
# from_client_data = conn.recv(1024) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
#
# from_client_data = conn.recv(1024) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
# conn.close()
# phone.close()
# 发一次收多次
# import socket
#
# phone = socket.socket()
#
# phone.bind(('127.0.0.1',8848))
#
# phone.listen(5)
#
#
# conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
#
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
#
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
#
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
#
# from_client_data = conn.recv(3) # 最多接受1024字节
# print(f'来自客户端addr消息:from_client_data.decode("utf-8")')
#
# conn.close()
# phone.close()
5.4 展示收发问题的客户端(client)
# 发多次收一次
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
#
#
# phone.send(b'he')
# phone.send(b'llo')
#
#
# phone.close()
# Nigle算法
# 发一次收多次
# import socket
#
# phone = socket.socket()
#
# phone.connect(('127.0.0.1',8848))
#
#
# phone.send(b'hello world')
#
#
# phone.close()
6.如何解决粘包现象
解决粘包现象的思路:
服务端发一次数据 10000字节,
客户端接收数据时,循环接收,每次(至多)接收1024个字节,直至将所有的字节全部接收完毕.将接收的数据拼接在一起,最后解码.
1. 遇到的问题: recv的次数无法确定.
你发送总具体数据之前,先给我发一个总数据的长度:5000个字节。然后在发送总数据。
客户端: 先接收一个长度。 5000个字节。
然后我再循环recv 控制循环的条件就是只要你接受的数据< 5000 一直接收。
2. 遇到的问题: 总数据的长度转化成的字节数不固定
服务端:
conn.send(total_size)
conn.send(result)
total_size int类型
客户端:
total_size_bytes = phone.recv(4)
total_size
data = b''
while len(data) < total_size:
data = data + phone.recv(1024)
你要将total_size int类型转化成bytes类型才可以发送
387 ---- > str(387) '387' ---->bytes b'387' 长度 3bytes
4185 ----> str(4185) '4185' ---->bytes b'4185' 长度 4bytes
18000------------------------------------------------------> 长度 5bytes
我们要解决:
将不固定长度的int类型转化成固定长度的bytes并且还可以翻转回来。
struct模块
5.low版解决粘包现象
5.1服务端
# 1. 粘包第一种: send的数据过大,大于对方recv的上限时,对方第二次recv时,会接收上一次没有recv完的剩余的数据。
import socket
import subprocess
import struct
phone = socket.socket()
phone.bind(('127.0.0.1',8848))
phone.listen(2)
# listen: 2 允许有两个客户端加到半链接池,超过两个则会报错
while 1:
conn,addr = phone.accept() # 等待客户端链接我,阻塞状态中
# print(f'链接来了: conn,addr')
while 1:
try:
from_client_data = conn.recv(1024) # 接收命令
if from_client_data.upper() == b'Q':
print('客户端正常退出聊天了')
break
obj = subprocess.Popen(from_client_data.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
result = obj.stdout.read() + obj.stderr.read()
total_size = len(result)
print(f'总字节数:total_size')
# 1. 制作固定长度的报头
head_bytes = struct.pack('i',total_size)
# 2. 发送固定长度的报头
conn.send(head_bytes)
# 3. 发送总数据
conn.send(result)
except ConnectionResetError:
print('客户端链接中断了')
break
conn.close()
phone.close()
# import struct
# # 将一个数字转化成等长度的bytes类型。
# ret = struct.pack('i', 180000000)
# # print(ret, type(ret), len(ret))
#
# # 通过unpack反解回来
# ret1 = struct.unpack('i',ret)[0]
# # print(ret1)
# print(ret1, type(ret1))
# 总数据:总数据长度
# s1 = 'lagfdkjglkhjklh'
# b1 = s1.encode('utf-8')
# print(b1)
# print(len(b1))
5.2客户端(client)
import socket
import struct
phone = socket.socket()
phone.connect(('127.0.0.1',8848))
while 1:
to_server_data = input('>>>输入q或者Q退出').strip().encode('utf-8')
if not to_server_data:
# 服务端如果接受到了空的内容,服务端就会一直阻塞中,所以无论哪一端发送内容时,都不能为空发送
print('发送内容不能为空')
continue
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
break
# 1. 接收报头
head_bytes = phone.recv(4)
# 2. 反解报头
total_size = struct.unpack('i',head_bytes)[0]
total_data = b''
while len(total_data) < total_size:
total_data += phone.recv(1024)
print(len(total_data))
print(total_data.decode('gbk'))
phone.close()
以上是关于如何解决python socket server重启后端口被占用的问题的主要内容,如果未能解决你的问题,请参考以下文章
Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)解决方法