Python3: 网络编程 TCP 和 UDP 协议 - socket

本文链接: https://blog.csdn.net/xietansheng/article/details/115557957

Python3 学习笔记(目录)

1. Socket — 底层网络接口

Socket(套接字)底层网络接口: socket — Low-level networking interface

1.1 建立连接

Socket 构造方法:

# 创建一个 socket 对象
#
# family: 套接字地址族, 默认为 socket.AF_INET, 
#         还有 AF_INET6, AF_UNIX, AF_CAN, AF_PACKET, AF_RDS
#
# type: 套接字类型, 主要为 SOCK_STREAM 和 SOCK_DGRAM(还有其他), 
#       分别表示 面向连接(TCP) 和 非连接(UDP)。
#
# proto: 套接字协议, 默认为 0
#
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

服务端(TCP/UDP) 方法:

# 将 socket 绑定到指定地址, 在 AF_INET 下, 
# address 以元祖 (host, port) 的形式表示, 
# host 可以为空字符串 '' 表示所有可用接口
socket.bind(address)

服务端(TCP) 方法:

# 开始 TCP 连接监听,
#
# backlog: 允许的最大连接数, 
#          如果指定, 则必须 >= 0(如果较低, 可以设置为 0),
#          如果不指定, 则自动选择默认的合理值
socket.listen([backlog])


# 接收一个 TCP 客户端连接(阻塞式等待客户端连接)
#
# 返回一个元祖 (socket object, address info)
#
# socket object: 与客户端建立的 socket,
# address info: 一个元祖 (host, port) 表示客户端的地址信息
#
socket.accept()

客户端(TCP) 方法:

# 连接 TCP 服务器, address 为元祖 (host, port), 如果出错(如超时、找不到主机等), 将抛出异常。
socket.connect(address)

# 连接 TCP 服务器, 出错时不抛出异常, 而是返回错误码, 返回 0 表示连接成功。
socket.connect_ex(address)

1.2 数据发送/接收

发送/接收(TCP) 方法:

# 发送 TCP 字节数据, 该 socket 必须已连接到远程 socket。
#
# bytes: 需要发送的字节数据
# flags: 可选参数, 默认为0
#
# 返回已发送的字节数(数据有可能没有全部发送)。
socket.send(bytes[, flags])


# 发送 TCP 字节数据, 该 socket 必须已连接到远程 socket, 
# 与 send() 不同的是该方法会持续发送数据, 直到所有的数据都已发送或发生错误为止。
#
# bytes: 需要发送的字节数据
#
# 返回 None 表示发送成功
socket.sendall(bytes[, flags])


# 发送文件数据到 TCP 连接, 该 socket 必须已连接到远程 socket。
#
# file: 文件对象, 必须是以二进制模式打开的常规文件
# offset: 从文件的哪里开始读取
# count: 要发送的字节总数, None 表示发送文件直到达到 EOF
#
# 返回已发送的字节总数
socket.sendfile(file, offset=0, count=None)


# 接收 TCP 字节数据
#
# bufsize: 一次允许接收的最大数据量
#
# 返回 接收到的 bytes
socket.recv(bufsize[, flags])


# 接收 TCP 字节数据, 把数据存储到缓冲区 buffer 中(而不是创建一个 bytes)。
#
# buffer: 可写的字节缓冲区, 例如 bytearray
# nbytes: 最大接收的字节数, 不传(或传0), 则为缓冲区的可用大小
#
# 返回接收到的字节数
socket.recv_into(buffer[, nbytes[, flags]])

发送/接收(UDP) 方法:

# 发送 UDP 字节数据,  该 socket 不应连接到远程 socket。
#
# bytes: 需要发送的字节数据
# address: 发送到的目标地址, 以元祖 (host, port) 来表示
#
# 返回发送的字节数
socket.sendto(bytes, address)
socket.sendto(bytes, flags, address)


# 接收 UDP 字节数据
#
# bufsize: 一次允许接收的最大数据量
#
# 返回 元祖 (bytes, address), 
#     bytes 表示接收到的字节数据,
#     address 也是一个元祖(host, port), 表示客户端地址(回传数据时使用)
socket.recvfrom(bufsize[, flags])


# 接收 UDP 字节数据, 把数据存储到缓冲区 buffer 中(而不是创建一个 bytes)。
#
# buffer: 可写的字节缓冲区, 例如 bytearray
# nbytes: 最大接收的字节数, 不传(或传0), 则为缓冲区的可用大小
#
# 返回 元祖 (nbytes, address), 
#     nbytes 表示接收到的字节数,
#     address 也是一个元祖(host, port), 表示客户端地址(回传数据时使用)
socket.recvfrom_into(buffer[, nbytes[, flags]])

1.3 其他方法

其他(TCP/UDP) 常用方法/属性:

# (TCP) 返回 socket 连接到的 远程地址, 返回元祖 (host, port)
socket.getpeername()

# 返回 socket 自己本地的地址, 返回元祖 (host, port)
socket.getsockname()


# 设置 socket 阻塞操作的超时时间, value 值为浮点类型的 秒数,
# 0 表示非阻塞模式, None 表示阻塞模式(没有超时期限)
socket.settimeout(value: float)

# 返回当前设置的 socket 阻塞操作的超时时间
socket.gettimeout()


# 设置 socket 的 阻塞/非阻塞 模式, True 表示阻塞(默认), Falst 表示非阻塞。
#
# sock.setblocking(True)  相当于 sock.settimeout(None)
# sock.setblocking(False) 相当于 sock.settimeout(0.0)
#
socket.setblocking(flag: bool)

# 返回 socket 当前的 阻塞/非阻塞 模式, Falst 表示非阻塞, True 表示阻塞。
socket.getblocking()


# (TCP) 比较优雅的关闭连接, 单方向或双方向关闭连接。
# how: 
#     socket.SHUT_RD    不允许进一步接收
#     socket.SHUT_WR    不允许进一步发送
#     socket.SHUT_RDWR  不允许进一步发送和接收
socket.shutdown(how)

# (TCP/UDP) 关闭 socket 连接。
# close() 释放与连接关联的资源, 但不一定立即关闭连接。
# 如果想及时关闭连接, close() 之前调用 shutdown()。
socket.close()


socket.family                   # 套接字地址族
socket.type                     # 套接字类型
socket.proto                    # 套接字协议

2. UDP 示例

UDP 服务端:

import socket

# 创建面向非连接(UDP)服务端 Socket
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定 主机和端口, "" 表示本地所有可用接口
ss.bind(("", 8080))

while True:
    # 阻塞等待接收客户端发来的数据, 返回元祖 (数据, 客户端地址)
    data, address = ss.recvfrom(1024)

    # 打印 客户端地址 和 收到的数据
    print("%s: %s" % (address, data.decode("UTF-8")))

    # 回复数据到客户端(连接必须还没有关闭)
    ss.sendto("收到".encode("UTF-8"), address)

# 关闭 服务端 Socket
# ss.close()

UDP 客户端:

import socket

# 创建面向非连接(UDP)客户端 Socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 服务端地址 和 端口
address = ("localhost", 8080)

# 发送数据 到 指定地址和端口
s.sendto("你好 Hello".encode("UTF-8"), address)

# 阻塞接收服务端回复的数据, 返回元祖 (数据, 服务端地址)
data, addr = s.recvfrom(1024)

# 打印 服务端地址 和 回复的数据
print("%s: %s" % (addr, data.decode("UTF-8")))

# 关闭 Socket
s.close()

socket 不再需要使用时必须确保被关闭(例如在 try finally 中关闭), socket 对象支持 with 上下文管理器, 可以使用 with 语句自动关闭 socket。

3. TCP 示例

TCP 服务端:

import socket

# 创建面向连接(TCP)服务端 Socket
ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定 主机和端口, "" 表示本地所有可用接口
ss.bind(("", 8080))

# 开始监听 客户端 连接
ss.listen()

while True:
    # 阻塞等待接收一个客户端连接, 返回元祖 (客户端socket, 客户端地址)
    # conn: 与客户端建立的 socket 对象
    # addr: 客户端地址, 元祖 (host, port)
    conn, addr = ss.accept()

    # 接收客户端发来的数据
    data = conn.recv(1024)

    # 打印 客户端地址 和 收到的数据
    print("%s: %s" % (addr, data.decode("UTF-8")))

    # 发送数据到客户端
    conn.sendall("收到".encode("UTF-8"))

    # 关闭 客户端 socket
    conn.close()

# 关闭 服务端 Socket
# ss.close()

TCP 客户端:

import socket

# 创建面向非连接(TCP)客户端 Socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 服务端地址 和 端口
address = ("localhost", 8080)

# 连接服务端
s.connect(address)

# 发送数据 到 服务端
s.sendall("你好 Hello".encode("UTF-8"))

# 阻塞接收服务端发送的数据
data = s.recv(1024)

# 打印 服务端发送的数据
print(data.decode("UTF-8"))

# 关闭 Socket
s.close()

socket 不再需要使用时必须确保被关闭(例如在 try finally 中关闭), socket 对象支持 with 上下文管理器, 可以使用 with 语句自动关闭 socket,代码示例:

"""
TCP 服务端
"""
import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as ss:
    ss.bind(("", 8080))
    ss.listen()
    while True:
        conn, addr = ss.accept()
        with conn:
            data = conn.recv(1024)
            print("%s: %s" % (addr, data.decode("UTF-8")))
            conn.sendall("收到".encode("UTF-8"))
"""
TCP 客户端
"""
import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(("localhost", 8080))
    s.sendall("你好 Hello".encode("UTF-8"))
    data = s.recv(1024)
    print(data.decode("UTF-8"))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢TS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值