三要素:
1. IP地址: 网络环境下每一台计算机的唯一标识, 通过IP地址来找到指定的计算机
2. 端口: 用于标识进程的逻辑地址, 通过端口来找到指定的进程
3. 协议: 定义通信规则, 符合协议则可以通信, 否则无法正常通信
端口: 程序间进行数据交互
端口号: 程序在设备的唯一标识
TCP协议
TCP特点:
面向连接: 通信双方必须先建立好连接才能进行数据传输,数据传输完成后,需要断开连接,以释放系统资源
可靠传输:
1. 都建立了连接, 传输数据可靠
2. 必须要先建立连接, 相对效率较低
3. 大多数服务器程序都是使用TCP协议开发的,比如文件下载,网页浏览等
知名端口号: 0-1023(被系统占用或为保留端口)
动态端口号: 1024 - 65535
socket(简称 套接字)
是进程之间的一个通信工具,好比家用电器工作都是基于插座进行,进程之间想要进行网络通信需要socket
socket负责进程之间的网络数据传输,好比数据的搬运工
两个进程之间通过socket进行相互通讯,就必须有服务端和客户端,服务端等待其他进程的连接,客户端主动连接服务端,都可以发送、接受数据
# socket(AddressFamily, Type)
# 参数 AddressFamily可以选择 AF_INET用于Internet进程间通信,实际工作中常用
# 参数 Type表示套接字类型, 可以是 SOCK_STREAM流式套接字,主要用于 TCP协议
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#
# family=AddressFamily.AF_INET:这表示socket使用的地址族是IPv4(AF_INET)。如果你使用的是IPv6,这里会是AddressFamily.AF_INET6。
fd=368
:这是socket的文件描述符(file descriptor),是操作系统用来标识和访问socket的一个数字。每个socket都有一个唯一的文件描述符。这个值在每次创建时都有可能不同family=2
:这表示socket使用的地址族。在Python的socket模块中,地址族通常是通过枚举来指定的,但在某些情况下(比如打印对象时),它们可能会以数值形式显示。2
通常对应于 socket.AF_INET
,即IPv4地址族。type=1
:这表示socket的类型。同样,类型通常是通过枚举来指定的,但在这里以数值形式显示。1
通常对应于 socket.SOCK_STREAM
,即面向连接的TCP协议。proto=0
:这表示socket使用的协议。对于TCP和UDP,这个值通常是0,因为它们的协议类型已经由地址族和类型参数指定了。套接字是计算机网络编程的基础,是操作系统提供的一种通信机制,用于在两个节点之间传递数据。它是应用层与传输层之间的接口,允许程序在网络上传输数据,支持多种协议,如TCP、UDP等。
SOCK_STREAM
):
SOCK_DGRAM
):
Python提供了socket
模块来处理套接字编程。以下是TCP和UDP套接字编程的基本步骤和示例。
TCP 服务端
import socket
# 创建TCP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址(IP和端口)
server_socket.bind(('localhost', 8080))
# 开始监听,允许的最大连接数为5
# listen方法内接受一个整数传参数,表示接受的连接数量
server_socket.listen(5)
print("Server is listening on port 8080...")
while True:
# 接收客户端连接
# accept方法返回的是二元元组(客户端和服务端的本次链接对象,客户端地址信息)
# accept()方法是 阻塞方法,若无连接,将不向下运行
client_socket, addr = server_socket.accept()
print(f"Connection established with {addr}")
# 接收客户端数据
# recv接受的是缓冲区大小,一般给1024即可
# recv方法返回的是一个字节数组(bytes)对象
# 可以通过 decode方法用UTF-8编码转换为字符串(解码)
data = client_socket.recv(1024).decode('utf-8')
print(f"Received from client: {data}")
if data == 'exit':
# 关闭客户端连接
client_socket.close()
# server_socket.close()
# 发送数据给客户端
"""
client_socket是在server_socket.accept()后创建的,
它负责与客户端通信。server_socket只用于监听连接,而client_socket
用于与特定客户端进行数据传输。
encode可以将字符串 编码 为字节数组对象
"""
replay = input(' ').encode('utf-8')
client_socket.send(replay)
# 关闭客户端连接
client_socket.close()
TCP 客户端
import socket
# 1. 创建 socket对象
socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接服务端
socket_client.connect(('localhost', 8888))
# 3. 发送消息、接受返回消息
while True:
data = input('客户端:')
if data == 'exit':
break
socket_client.send(data.encode('UTF-8'))
reply = socket_client.recv(1024).decode('UTF-8')
print(f'服务端:{reply}')
# 4. 关闭连接
socket_client.close()
UDP 服务端
import socket
# 创建UDP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定地址
server_socket.bind(('localhost', 8080))
print("UDP server is up and listening...")
while True:
# 接收数据
data, addr = server_socket.recvfrom(1024)
print(f"Received from {addr}: {data.decode('utf-8')}")
# 发送响应数据
server_socket.sendto(b"Hello from UDP server!", addr)
UDP 客户端
import socket
# 创建UDP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 发送数据给服务器
client_socket.sendto(b"Hello from UDP client!", ('localhost', 8080))
# 接收服务器的数据
response, server_addr = client_socket.recvfrom(1024)
print(f"Received from server: {response.decode('utf-8')}")
# 关闭套接字
client_socket.close()
socket.socket(family, type)
:创建一个套接字对象。
family
: 地址族(AF_INET
表示IPv4, AF_INET6
表示IPv6)。type
: 套接字类型(SOCK_STREAM
表示TCP,SOCK_DGRAM
表示UDP)。socket.bind(address)
:将套接字绑定到一个地址(IP, 端口)。socket.listen(backlog)
:使套接字进入监听模式,backlog
指定最大等待连接的数量。socket.accept()
:接受客户端连接,返回(客户端套接字,客户端地址)。socket.connect(address)
:客户端使用该函数连接到服务器。socket.recv(bufsize)
:接收数据,bufsize
指定接收数据的最大字节数。socket.send(data)
:发送数据,data
是要发送的字节串。socket.close()
:关闭套接字。socket.recvfrom(bufsize)
:UDP套接字接收数据,返回(数据,发送者地址)。socket.sendto(data, address)
:UDP套接字发送数据。在网络编程中,可能会遇到各种异常情况,如连接超时、网络中断等,因此在编写套接字程序时,必须处理这些异常。
import socket
try:
# 尝试创建套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 尝试连接到服务器
client_socket.connect(('localhost', 8080))
# 发送数据
client_socket.send(b"Hello!")
except socket.error as e:
print(f"Socket error: {e}")
finally:
# 确保关闭套接字
client_socket.close()
可以设置套接字的超时,以避免程序无限期等待某些操作。
import socket
# 创建TCP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置超时时间为5秒
client_socket.settimeout(5)
try:
client_socket.connect(('localhost', 8080))
client_socket.send(b"Hello!")
except socket.timeout:
print("Connection timed out.")
finally:
client_socket.close()
套接字是网络编程的核心技术之一,它提供了不同节点间的数据传输方式。理解和掌握套接字的使用方法可以帮助我们构建各种网络应用程序,例如聊天系统、Web服务器、文件传输工具等。