初学Python语言,今天搭建了Python环境,经朋友推荐,采用PyCharm+Anaconda搭建的环境,Anaconda是Python的开源发行版本,省去了包管理和不同Python版本的问题。由于之前熟悉网络编程,熟悉了Python基本语法后,实现了简单的网络编程。
本篇文章包括三个部分,首先介绍了一下Socket网络编程的基础知识,然后分别从服务器端和客户端介绍了网络通信原理及代码实现。
1. Socket基础知识
Socket通信模型
建立Socket连接至少需要一对套接字,其中一个运行客户端,另一个运行于服务器端。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
(1)服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
(2)客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。(为此,客户端套接字必须首先描述它要连接的服务器的套接字,指出服务器套接字的地址和端口号,然后就向服务器套接字提出连接请求)
(3)连接确认:当服务器套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。(而服务器套接字继续处于监听状态,继续接收其他客户端套接字的连接请求)
2. 服务器端
服务器端创建Socket并绑定监听的地址和端口,并调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量。
# 服务器建立socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定监听的地址和端口 s.bind(('127.0.0.1', 9999)) # 开始监听端口 s.listen(5) print('Waiting for connection...')
服务器端通过while死循环不断监听来自客户端的连接请求,一旦有客户端连接,服务器的accept()方法接收请求,并创建新的线程处理请求。
while True: # 接受一个新连接; sock, addr = s.accept() # 创建新线程来处理TCP连接: t = threading.Thread(target=tcplink, args=(sock,addr)) t.start()
服务器端采用多线程实现,每连接到一个客户端就创建一个新的线程,避免服务器单线程带来的阻塞问题。
def tcplink(sock, addr): print('Accept new connection from %s:%s...' % addr) sock.send(b'Welcome!') while True: data = sock.recv(1024) time.sleep(1) if not data or data.decode('utf-8') == 'exit': break sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8')) sock.close() print('Connection from %s:%s closed' % addr)
连接建立后,客户端和服务器便开始通信了。程序中服务器监听到来自客户端的请求后,首先发送一条Welcome信息,然后阻塞等待客户端的数据,接收到客户端的数据后,服务器在前面加上Hello,并将消息发送给客户端。如果客户端发送"exit"串,则关闭服务器和客户端的连接。
3. 客户端
为测试服务器程序,我们编写了一个简单的客户端程序:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立连接: s.connect(('127.0.0.1', 9999)) # 接收欢迎消息: print(s.recv(1024).decode('utf-8')) for data in [b'Michael', b'Tracy', b'Sarah']: # 发送数据: s.send(data) print(s.recv(1024).decode('utf-8')) s.send(b'exit') s.close()
4. 运行结果
服务器端
客户端
需要注意的是,客户端运行完成后就直接退出,而由于服务器维持着一个长连接,必须手动强制关闭程序。
【参考资料】
[1] 廖雪峰, TCP编程.
所有评论(0)