socket 简称套接字,应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
创建套接字:
import socket
s = socket.socket(family,type)
参数如下: family: 套接字家族可以使 AF_UNIX 或者 AF_INET。 type: 套接字类型可以根据是面向连接的还是非连接分为 SOCK_STREAM(TCP套接字) 或 SOCK_DGRAM(UDP套接字)。
部分socket对象内建方法: 服务器端套接字
函数 | 描述 |
---|
s.bind() | 绑定地址(host,port)到套接字, 在 AF_INET下,以元组(host,port)的形式表示地址与端口 | s.listen() | 开始 TCP 监听。可指定最大连接数量。该值至少为 1,大部分应用程序设为 5 就可以了 | s.accept(): | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
客户端套接字
函数 | 描述 |
---|
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 | s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共套接字
测试 | |
---|
s.recv() | 接收 TCP 数据,数据以字符串形式返回,bufsize 指定要接收的最大数据量。flag 提供有关消息的其他信息,通常可以忽略。 | s.send() | 发送 TCP 数据,将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于 string 的字节大小。 | s.sendall() | 完整发送 TCP 数据。将 string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常。 | s.close() | 关闭套接字 |
创建一个简易版TCP服务器:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 7777))
s.listen(10)
print("等待客户端建立连接")
res = s.accept()
print(f"客户端建立了连接:{res}")
s.close()
运行程序后此时是堵塞状态,会一直等待客户端建立连接,通过浏览器来请求下,结果如下:
等待客户端建立连接
客户端建立了连接:(<socket.socket fd=948, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 7777), raddr=('127.0.0.1', 58362)>, ('127.0.0.1', 58362))
可见创建了两个元组,客户端的套接字与地址信息,而这个套接字是专门用来与客户端通信的,通过元组解包拿到此套接字与地址:
cli_sock,address = s.accept()
print("客户端套接字:"cli_sock)
print("地址:"address )
结果:
等待客户端建立连接
客户端建立了连接
客户端套接字: <socket.socket fd=948, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 7777), raddr=('127.0.0.1', 61211)>
地址: ('127.0.0.1', 61211)
接收客户端的请求信息:cli_sock.recv()
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 7777))
s.listen(10)
print("等待客户端建立连接")
cli_sock, address = s.accept()
print("客户端建立了连接")
print("客户端套接字:", cli_sock)
print(cli_sock.recv(1024).decode())
cli_sock.send("请求成功")
s.close()
结果:
等待客户端建立连接
客户端建立了连接
客户端套接字: <socket.socket fd=120, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 7777), raddr=('127.0.0.1', 63797)>
GET / HTTP/1.1
Host: 127.0.0.1:7777
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
创建客户端 向服务端发起请求,传递数据
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 7777))
s.send("hello world".encode())
print(s.recv(1024).decode())
客户端结果:
请求成功
服务端结果:
等待客户端建立连接
客户端建立了连接
客户端套接字: <socket.socket fd=1032, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 7777), raddr=('127.0.0.1', 60668)>
hello world
多线程处理客户端请求,封装如下:
import socket
from concurrent.futures.thread import ThreadPoolExecutor
class TCPServer():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind(('127.0.0.1', 7777))
self.s.listen(10)
def handle_request(self, cli_sock, address):
print(f"客户端建立了连接{address}")
cli_sock.send("请求成功".encode())
print(cli_sock.recv(1024).decode())
cli_sock.close()
def run(self):
with ThreadPoolExecutor(max_workers=10) as pool:
while True:
print("等待客户端建立连接")
cli_sock, address = self.s.accept()
pool.submit(self.handle_request, cli_sock, address)
TCPServer().run()
|