《Python高级编程》学习心得——第十章 Python Socket编程
Socket编程原理
下图展示了计算机网络五层模型的框架:
计算机网络是由一系列协议构成的,其中协议是分层的,最顶层的应用层协议如HTTP,FTP,SMTP支持Web应用如网页浏览、文件传输、邮件发送;次顶层的传输层提供了端对端的连接,主要有TCP和UDP协议,其中大部分Web应用使用的是TCP协议(一直听说早期的QQ使用的是UDP协议,不知是真是假,下次找在鹅厂工作的同学问问);网络层负责寻址和路由,路由器就工作在网络层,涉及的最重要的协议是IP协议;为IP协议提供地址解析的ARP协议工作在数据链路层;最底层的物理层负责为上层提供可靠的物理媒介。
Socket是操作系统提供的一个对传输层的抽象接口,可以使用封装好的TCP/UDP协议,来编写定制的网络应用(类Unix系统也用Socket实现进程之间的通信)。当然,也可以自己用Socket编程的方式实现HTTP等应用层协议实现的功能,不过更简单的方式是调用HTTP协议相关的包来实现。但是,总有些功能不同于HTTP,FTP,SMTP等协议,需要我们自己通过Socket编程来实现,比如即时聊天工具就是一类。不同于HTTP协议中服务端总是响应客户端的请求,即时聊天工具客户端和服务端都具备主动发送数据的能力。
用Socket和多线程实现多客户端连接聊天工具
多客户端连接聊天工具可以模拟真实应用中客服平台等需求,涉及Socket编程(实际应用中会使用Web Socket实现)和多线程的知识,下面直接看代码和注释。值得注意的是Socket发送的是byte,需要对str作编码解码处理。
SocketClient.py
import socket
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) # AF_INET: IPV4, SOCK_STREAM: TCP
client.connect(('127.0.0.1', 8000)) # connect localhost:8000
while True:
re_data = input() # wait for user input
client.send(re_data.encode('UTF-8')) # send byte data
if re_data == 'quit':
break
ge_data = client.recv(1024) # receive data
print(ge_data.decode('UTF-8')) # decode byte data
client.close() # close connection
SocketServer.py
import socket
import threading
def process_client(sock, addr):
print('Connect client addr: {}'.format(addr))
while True:
ge_data = sock.recv(1024) # receive data
ge_str = str(ge_data.decode('UTF-8'))
print(ge_str)
if ge_str == 'quit': # if receive data 'quit', close connect
print('Disconnect client addr: {}'.format(addr))
break
re_data = input() # wait for user input
sock.send(re_data.encode('UTF-8')) # send byte data
sock.close() # close connection with
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) # AF_INET: IPV4, SOCK_STREAM: TCP
server.bind(('127.0.0.1', 8000)) # bind to localhost:8000
server.listen() # listen for clients
while True:
sock, addr = server.accept() # accept client
client_thread = threading.Thread(target=process_client, args=(sock, addr)) # create a client thread
client_thread.start() # start a client thread
server.close() # close server
Client ‘HIT’ Console
HIT
Hello, HIT
quit
Client ‘WIT’ Console
WIT
Hello, WIT
quit
Server Console
Connect client addr: ('127.0.0.1', 51776)
HIT
Hello, HIT
Connect client addr: ('127.0.0.1', 51784)
WIT
Hello, WIT
quit
Disconnect client addr: ('127.0.0.1', 51784)
quit
Disconnect client addr: ('127.0.0.1', 51776)