一、tcp服务器
1.1 tcp服务器端的流程
- 创建 socket 对象
- 绑定IP 和端口
- 设置监听
- 阻塞等待客户端的链接
- 新的 socket 收信息
- 新的 socket 发信息
- 关闭
文章来源地址https://www.toymoban.com/news/detail-724484.html
1.2 tcp服务端的代码实现
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在 connect()时由系统随机生成一个。
代码:
import socket
if __name__ == '__main__':
# 1 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2 绑定 IP 和端口
# server_socket.bind(('电脑本机IP',8888))
server_socket.bind(('',8888)) # 前面空,绑定服务器的任意一个网卡
# 3 监听,参数是同时连接的客户端数量
server_socket.listen(128)
print('等待ing.....')
# 4 阻塞等待客户端连接
# 返回一个元组 (新socket, (客户端IP,端口) )
new_socket, client_ip_port = server_socket.accept()
# 5 新的socket收信息
buf = new_socket.recv(4096)
print(buf.decode())
# 6 新的socket发信息
send_data = (f'{client_ip_port}连接成功').encode()
new_socket.send(send_data)
# 7 关闭
new_socket.close()
server_socket.close()
点击运行
启动服务端
点击连接网络
发送消息 123
1.3 设置端口复用
刚才的代码有一个问题,就是如果端口已经使用,再次连接的时候会报错误
这就涉及端口复用的问题
正常情况下,服务器的代码是永远不会关闭的.就不会出现这个问题
特殊情况: 启动服务器之后, 运行一次,马上关闭再次运行,会出现这个 bug, 地址已经被使用
端口需要等待 30s - 2min 才可以再次使用
代码实现让端口关闭之后,可以立刻使用,这就是端口复用
代码加在 1 创建socket对象 和 2 绑定 之间
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
setsockop t的三个参数
- level 设置那个级别的socket SOL_SOCKET 表示当前socket
- optname 设置什么内容,权限 SO_REUSEADDR 表示端口复用
- value 设置的值,True
完整代码:
import socket
if __name__ == '__main__':
# 1 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
# 2 绑定 IP 和端口
server_socket.bind(('电脑本机IP',8888))
# server_socket.bind(('',8888)) # 前面空,绑定服务器的任意一个网卡
# 3 监听,参数是同时连接的客户端数量
server_socket.listen(128)
print('等待ing.....')
# 4 阻塞等待客户端连接
# 返回一个元组 (新socket, (客户端IP,端口) )
new_socket, client_ip_port = server_socket.accept()
# 5 新的socket收信息
buf = new_socket.recv(4096)
print(buf.decode())
# 6 新的socket发信息
send_data = (f'{client_ip_port}连接成功').encode()
new_socket.send(send_data)
# 7 关闭
new_socket.close()
server_socket.close()
pass
1.4 判断客户端是否退出连接
其实很简单,
判断依据:
客户端退出连接的时候,服务器的socket 不再阻塞,收到一个空字符串,长度是0
使用这个空字符串去判断就行
代码:
import socket
if __name__ == '__main__':
# 1 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
# 2 绑定 IP 和端口
server_socket.bind(('电脑本机IP',8888))
# server_socket.bind(('',8888)) # 前面空,绑定服务器的任意一个网卡
# 3 监听,参数是同时连接的客户端数量
server_socket.listen(128)
print('等待ing.....')
# 4 阻塞等待客户端连接
# 返回一个元组 (新socket, (客户端IP,端口) )
new_socket, client_ip_port = server_socket.accept()
# 5 新的socket收信息
buf = new_socket.recv(4096)
if buf:
print(buf.decode())
# 6 新的socket发信息
send_data = (f'{client_ip_port}连接成功').encode()
new_socket.send(send_data)
else:
print(f'客户端{client_ip_port}断开连接')
# 7 关闭
new_socket.close()
server_socket.close()
pass
效果:
1.5 多任务版本的服务器
多任务,肯定是使用进程或者线程去实现的
那么,应该在哪里使用进程或者线程呢?
应该是在有客户端连接之后,创建线程
首先,服务器等待连接应该是循环等待
其次,重复的任务,(即每一个线程应该做的任务),使用一个函数去定义实现
代码:
import socket
import threading
# 定义任务函数
def handle_request(new_socket,client_ip_port):
while True: # 这样客户端可以一直发信息
# 5 新的socket收信息
buf = new_socket.recv(4096)
if buf:
print(buf.decode())
# 6 新的socket发信息
send_data = (f'{client_ip_port}连接成功').encode()
new_socket.send(send_data)
else:
print(f'客户端{client_ip_port}断开连接')
break
# 7 关闭
new_socket.close()
if __name__ == '__main__':
# 1 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
# 2 绑定 IP 和端口
server_socket.bind(('电脑本机IP',8888))
# server_socket.bind(('',8888)) # 前面空,绑定服务器的任意一个网卡
# 3 监听,参数是同时连接的客户端数量
server_socket.listen(128)
print('等待ing.....')
while True:
# 4 阻塞等待客户端连接
new_socket, client_ip_port = server_socket.accept()
# 有客户端连接,建立多线程
sub_thread = threading.Thread(target=handle_request,args = (new_socket,client_ip_port) )
sub_thread.start()
server_socket.close()
pass
1.6 注意点
1.7 send 和 recv 原理
文章来源:https://www.toymoban.com/news/detail-724484.html
到了这里,关于03 python网络应用实战(三)tcp服务端设计实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!