Python网络编程
内容导航:
- 网络编程概述
- TCP编程
- UDP编程
1. 网络编程概述
既然是做爬虫开发,必然需要了解Python网络编程方面的知识。计算机网络是把各个计算机连接到一起,让网络中的计算机可以互相通信。网络编程就是如何在程序中实现两台计算机的通信。
提到网络编程,必须提到的一个概念是Socket。Socket(套接字)是网络编程的一个抽象概念,通常我们用一个Socket表示“打开了一个网络连接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。Python提供了两个基本的Socket模块:
- Socket,提供了标准的BSD Sockets API。
- SocketServer,提供了服务器中心类,可以简化网络服务器的开发。
2. TCP编程
网络编程一般包括两部分:服务端和客户端。TCP是一种面向连接的通信方式,主动发起连接的叫客户端,被动响应连接的叫服务端。
2.1 TCP服务端编程
创建和运行TCP服务端一般需要五个步骤:
- 创建Socket,绑定Socket到本地IP与端口。
- 开始监听连接。
- 进入循环,不断接收客户端的连接请求。
- 接收传来的数据,并发送给对方数据。
- 传输完毕后,关闭Socket。
TCP服务端程序示例如下(须在终端中通过python tcp_server.py
命令运行):
!cat tcp_server.py
import socket
import threading
import time
def dealClient(sock, addr):
# 第四步:接收传来的数据,并发送给对方数据
print('Accept new connection from {0}...'.format(addr))
sock.send(b'Server: Hello, I am server!')
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
print('-->>{}'.format(data.decode('utf-8')))
sock.send(('Server: {}'.format(data.decode('utf-8'))).encode('utf-8'))
# 第五步:关闭Socket
sock.close()
print('Connection from %s:%s closed.' % addr)
def main():
# 第一步:创建一个基于IPv4和TCP协议的Socket
# Socket绑定的IP(127.0.0.1为本机IP)与端口
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9999))
# 第二步:监听连接
s.listen(5)
print('Waiting for connection...')
while True:
# 第三步:接收一个新连接:
sock, addr = s.accept()
# 创建新线程来处理TCP连接:
t = threading.Thread(target=dealClient, args=(sock, addr))
t.start()
if __name__ == "__main__":
main()
为了在终端窗口中运行服务端程序,需要先切换到本实践项目的工作目录。可通过以下命令查看当前工作目录:
!pwd
/data/workspace/myshixun_tpm50433/tuvr5qje/PyNetProgramming
然后再终端窗口中执行以下命令:
# cd /data/workspace/myshixun_tpm50433/tuvr5qje/PyNetProgramming
# python tcp_server.py
2.2 TCP客户端编程
接着编写客户端,与服务端进行交互,TCP客户端的创建和运行需要三个步骤:
- 创建Socket,连接远端地址。
- 连接后发送数据和接收数据。
- 传输完毕后,关闭Socket。
TCP客户端程序如下,运行该程序之前需要先执行上述TCP服务端程序。
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'))
while True:
message = input(prompt="Client:")
s.send(message.encode('utf-8'))
print('-->>'+ s.recv(1024).decode('utf-8'))
if message == 'quit':
break
s.send(b'exit')
s.close()
-->>Server: Hello, I am server!
Client: ok
-->>Server: ok
Client: quit
-->>Server: quit
测试完毕后,为了避免TCP服务端长时运行,可通过以下命令终止服务端进程:
# 查看当前运行的进程
!ps -e
PID TTY TIME CMD
1 ? 00:00:01 start.sh
12 ? 00:00:16 jupyter-lab
502 ? 00:00:01 python3
534 ? 00:00:00 python3
1308 ? 00:00:00 python3
2125 ? 00:00:00 python3
3454 pts/0 00:00:00 sh
3656 pts/0 00:00:00 python
3812 ? 00:00:00 sleep
3813 pts/1 00:00:00 sh
3814 pts/1 00:00:00 ps
# 根据PID终止python进程
!kill 3656
3 UDP编程
TCP通信需要一个建立可靠连接的过程,而且通信双方以流的形式发送数据。相对于TCP, UDP则是面向无连接的协议。使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包,但是不关心是否能到达目的端。虽然用UDP传输数据不可靠,但是由于它没有建立连接的过程,速度比TCP快得多,对于不要求可靠到达的数据,就可以使用UDP协议。
使用UDP协议,和TCP一样,也有服务端和客户端之分。
3.1 UDP服务端编程
UDP编程相对于TCP编程比较简单,服务端创建和运行只需要三个步骤:
- 创建Socket,绑定指定的IP和端口
- 直接发送数据和接收数据
- 关闭Socket
UDP服务器端示例程序如下(须在终端中通过python udp_server.py
命令运行):
!cat udp_server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('127.0.0.1', 9999))
print('Bind UDP on 9999...')
while True:
data, addr = s.recvfrom(1024)
print('Received from {0}'.format(addr))
s.sendto(b'From Server: %s' % data, addr)
为了在终端窗口中运行服务端程序,需要先切换到本实践项目的工作目录。可通过以下命令查看当前工作目录:
!pwd
/data/workspace/myshixun_tpm50433/tuvr5qje/PyNetProgramming
然后再终端窗口中执行以下命令:
# cd /data/workspace/myshixun_tpm50433/tuvr5qje/PyNetProgramming
# python udp_server.py
3.2 UDP客户端编程
服务端创建和运行也只需要三个步骤:
- 创建Socket
- 直接向(从)指定的IP和端口发送数据和接收数据
- 关闭Socket
客户端示例程序如下,运行该程序之前需要先执行上述UDP服务端程序。
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'ABC', b'CDE', b'DEF']:
s.sendto(data, ('127.0.0.1',9999))
print(s.recv(1024).decode('utf-8'))
s.close()
From Server: ABC
From Server: CDE
From Server: DEF
测试完毕后,为了避免UDP服务端长时运行,可通过以下命令终止服务端进程:
# 查看当前运行的进程
!ps -e
PID TTY TIME CMD
1 ? 00:00:01 start.sh
12 ? 00:00:16 jupyter-lab
502 ? 00:00:01 python3
534 ? 00:00:00 python3
1308 ? 00:00:00 python3
2125 ? 00:00:00 python3
3454 pts/0 00:00:00 sh
3883 pts/0 00:00:00 python
3946 pts/1 00:00:00 sh
3947 ? 00:00:00 sleep
3948 pts/1 00:00:00 ps
# 根据PID终止python进程
!kill 3883