Python 网络编程(Socket)
一、Socket 套接字
1、Socket 编程
- socket本质是编程接口(API),对TCP/IP的封装,提供可供程序员做网络开发所用的接口。Socket 编程是应用进程间通信的抽象机制。
- 应用编程接口API:应用进程的控制权和操作系统的控制权进行转换的一个系统调用接口
- Socket 的意思为“插座”。是 BSD UNIX 的进程通信机制,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原义那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,提供不同的服务。 客户软件将插头插到不同编号的插座,就可以得到相应的服务。
2、Socket
Socket 标识:
- 不同主机间 Socket 连接的标识:IP地址+端口号
- 操作系统/进程管理套接字的标识:套接字描述符(socket descriptor),小整数
Socket 创建:
- 当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息,返回套接字描述符
- 每个进程有一个 Socket 描述符表
- 如果多个进程共享一个套接字,关闭套接字时引用计数减1,减至0才关闭
- 如果进程中的一个线程将一个套接字关闭,该套接字直接关闭,该进程中的其他线程也将不能访问该套接字
二、TCP
1、客户端
访问网站: HTTP 协议
# 导入socket库
import socket
# 创建一个socket,AF_INET 表示采用 IPv4 网络协议,SOCK_STREAM 表示 TCP 连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接,需指明端口号,web 服务端口默认为 80
s.connect(('www.baidu.com', 80))
# 发送数据
s.send(b'GET / HTTP/1.1\r\nHost:www.baidu.com\r\nConnection:close\r\n\r\n')
# 接收数据
buffer = []
while True:
# 每次最多接收1k字节
d = s.recv(1024)
if d:
buffer.append(d)
else:
break
data = b''.join(buffer)
# 关闭连接
s.close()
# 解析服务器响应数据
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# 把接收的数据写入文件
with open('baidu.html', 'wb') as f:
f.write(html)
自定义连接:
# 导入socket库
import socket
# 创建一个socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接
s.connect(('127.0.0.1', 5000))
# 接收欢迎消息
print(s.recv(1024).decode('utf-8'))
for data in [b'Python', b'C++', b'AI']:
# 发送数据
s.send(data)
# 接受数据
print(s.recv(1024).decode('utf-8'))
# 发送结束连接信号
s.send(b'exit')
# 关闭连接
s.close()
2、服务器
# 导入 socket 库,threading 库
import socket
import threading
import time
# 处理请求函数
def tcp_link(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)
# 创建一个socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定端口
s.bind(('127.0.0.1', 5000))
# 监听端口,5表示最多同时监听5个
s.listen(5)
print('Waiting for connection...')
# 等待连接,处理连接
while True:
# 接受一个新连接
sock, addr = s.accept()
# 创建新线程来处理TCP连接
t = threading.Thread(target=tcp_link, args=(sock, addr))
t.start()
三、UDP
1、客户端
# 导入socket库:
import socket
# 创建一个socket,SOCK_DGRAM 表示 UDP 连接
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 数据发送与接收
for data in [b'Python', b'C++', b'AI']:
# 发送数据:
s.sendto(data, ('127.0.0.1', 5000))
# 接收数据:
print(s.recv(1024).decode('utf-8'))
# 关闭连接
s.close()
2、服务器
# 导入socket库:
import socket
import threading
# 处理请求函数
def udp_link(data, addr):
print('Received from %s:%s.' % addr)
s.sendto(b'Hello, %s!' % data, addr)
# 创建一个socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind(('127.0.0.1', 5000))
print('Bind UDP on 5000...')
# 等待接收数据并处理
while True:
# 接收数据:
data, addr = s.recvfrom(1024)
t = threading.Thread(target=udp_link, args=(data, addr))
t.start()
GOOD LUCK!