1.TPC服务端程序开发流程:
1.1.创建客户端套接字对象
1.2.绑定IP地址和端口号
1.3.设置监听
1.4.等待接受客户端的连接请求
1.5.接受数据
1.6.发送数据
1.7.关闭客户端套接字
2.注意事项:
2.1.客户端和服务端程序进行通信的时候必须建立连接;
2.TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的;
2.3.TCP服务端必须绑定端口号,否则客户端就找不到服务端;
2.4.Listen之后的套接字是被动套接字,只负责接受新的客户端的连接请求,不能收发数据;
2.5.当客户端和服务端建立连接之后,服务端会产生一个新的套接字,专门用来收发数据;
2.6.关闭accept返回的套接字意味着和这个客户端通信完毕;
2.7.当客户端调用close之后,服务端的recv会解阻塞,返回的数据长度为0,服务端可以通过返回的数据长度来判断客户端是否下线, 反之服务端关闭套接字,客户端的recv也会解阻塞,返回数据长度为0。
代码:
import socket
# 创建客户端套接字对象
# socket.AF_INET: 表示ipv4地址
# socket.SOCK_STREAM: 表示流式传输协议,即TCP传输协议
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定IP地址和端口号
# tcp_server_socket.bind(('127.0.0.1',8969))
tcp_server_socket.bind(('',8080)) # 动态绑定IP地址,方便代码的通用性
# 设置监听,128表示服务器等待连接的排队的最大数量
tcp_server_socket.listen(128)
# 等待接受客户端的连接请求
# conn_socket:服务于这个客户端的专用套接字
# ip_port:客户端的IP地址和端口号
conn_socket,ip_port = tcp_server_socket.accept()
print("客户端已连接!",ip_port)
# 接受数据
recv_data = conn_socket.recv(1024)
print("客户端发送的请求为:",recv_data.decode('GBK'))
# 发送数据
conn_socket.send("收到,over!".encode('GBK'))
# 关闭客户端套接字
conn_socket.close()
tcp_server_socket.close()
测试截图如下:
在以上代码中,服务器只与一个客户端连接,当与多个服务器连接时,由于其会等待客户端的消息发送,等待接收到消息后才会执行之后的语句,若此时客户端不进行数据传输就会造成线程阻塞。
解决方法:多线程的TCP服务端程序
当客户端和服务器端建立连接后,创建子线程,使用子线程专门处理客户端的请求和响应,防止主线程阻塞
代码:
import socket
import threading
def handle_client(conn_socket):
"""专门处理客户端的请求和响应"""
# 接受数据
recv_data = conn_socket.recv(1024)
print("客户端发送的请求为:", recv_data.decode('GBK'))
# 发送数据
conn_socket.send("收到,over!".encode('GBK'))
# 关闭客户端套接字
conn_socket.close()
# 创建客户端套接字对象
# socket.AF_INET: 表示ipv4地址
# socket.SOCK_STREAM: 表示流式传输协议,即TCP传输协议
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定IP地址和端口号
# tcp_server_socket.bind(('127.0.0.1',8969))
tcp_server_socket.bind(('',8080)) # 动态绑定IP地址,方便代码的通用性
# 设置监听,128表示服务器等待连接的排队的最大数量
tcp_server_socket.listen(128)
while True:
# 等待接受客户端的连接请求
# conn_socket:服务于这个客户端的专用套接字
# ip_port:客户端的IP地址和端口号
conn_socket,ip_port = tcp_server_socket.accept()
print("客户端已连接!",ip_port)
# 创建线程对象
sub = threading.Thread(target=handle_client,args=(conn_socket,))
# 启动子线程
sub.start()
测试截图:
此时,服务器可连接多个客户端进行通信并且不会造成堵塞!!!