Python网络编程与并发编程_02

套接字编程实战

socket对象的内置函数和属性

UDP服务器最简化案例

from socket import *

# 最简化的UDP服务器代码
# AF_INET指定使用IPv4地址
# SOCK_DGRAM指定使用UDP协议
s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字

# 这里绑定的是本地回环地址的8888端口,表示服务器将在本地的8888端口上监听
# 如果IP地址留空或设置为None,服务器将监听所有可用的网络接口上的指定端口
s.bind(("127.0.0.1", 8888))  # 绑定端口,ip可以不写

print("等待接受数据!")

# recv()方法用于接收数据,它将阻塞直到有数据到达
# 返回值是一个包含两部分的元组:数据内容和发送方的地址信息
recv_data = s.recv(1024)  # 1024代表本次接受的最大字节数

print(f"收到远程信息:{recv_data[0].decode('gbk')}, from {recv_data[1]}")

# 关闭套接字
s.close()

这段代码的逻辑如下:

  1. 导入socket库。
  2. 创建一个UDP套接字。
  3. 将套接字绑定到本地的8888端口上,准备接收数据。
  4. 打印一条消息,通知服务器正在等待接收数据。
  5. 使用recv方法接收数据。这里设置的1024是缓冲区的大小,即服务器一次能够接收的最大数据量。
  6. 打印出接收到的数据以及发送方的地址信息。
  7. 最后关闭套接字,释放资源。

UDP客户端最简化案例

from socket import *

# 创建UDP类型的套接字
# AF_INET指定使用IPv4地址
# SOCK_DGRAM指定使用UDP协议
s = socket(AF_INET, SOCK_DGRAM)

# 定义服务器的地址和端口,这里使用的是本地回环地址和端口号8888
address = ("127.0.0.1", 8888)

# 提示用户输入数据,input函数会读取用户输入的字符串
data = input("请输入: ")

# sendto方法用于发送数据到指定的地址
# data.encode("gbk")将字符串数据转换为GBK编码的字节流,因为socket发送的是字节数据
# 第二个参数address是元组,包含服务器的IP地址和端口号
s.sendto(data.encode("gbk"), address)

# 关闭套接字,释放系统资源
s.close()

这段代码的逻辑是:

  1. 导入socket库。
  2. 创建一个UDP套接字。
  3. 定义服务器的IP地址和端口号。
  4. 提示用户输入要发送的数据。
  5. 使用sendto方法将用户输入的数据发送到服务器。这里,data.encode("gbk")是将输入的字符串转换为字节流,因为UDP协议发送的是字节数据。
  6. 关闭套接字。

UDP服务端持续接收信息

from socket import *


s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
s.bind(("127.0.0.1", 8888))  # 绑定端口,ip可以不写

print("等待接受数据!")
while True:
    recv_data = s.recvfrom(1024)  # 1024 代表本次接受的最大字节数
    recv_content = recv_data[0].decode("gbk")
    print(f"收到远程消息: {recv_content}, from {recv_data[1]}")
    if recv_content == "88":
        print("结束聊天!")
        break

# 关闭套接字
s.close()

UDP客户端持续发送信息

from socket import *


s = socket(AF_INET, SOCK_DGRAM)
address = ("127.0.0.1", 8888)

while True:
    data = input("请输入: ")
    s.sendto(data.encode("gbk"), address)
    if data == "88":
        print("结束聊天!")
        break

# 关闭套接字,释放系统资源
s.close()

UDP和多线程实现双向自由通信

客户端

from socket import *
from threading import Thread


def receive_data():
    while True:
        receive_data = s.recvfrom(1024)
        receive_content = receive_data[0].decode("gbk")
        print(f"收到远程信息: {receive_content}, from {receive_data[1]}")
        if receive_content == "88":
            print("结束聊天")
            break


def send_data():
    address = ("127.0.0.1", 8888)
    while True:
        data = input("请输入: ")
        s.sendto(data.encode("gbk"), address)
        if data == "88":
            print("结束聊天")
            break


if __name__ == '__main__':
    s = socket(AF_INET, SOCK_DGRAM)
    s.bind(("127.0.0.1", 9999))
    t1 = Thread(target=receive_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

服务端

from socket import *
from threading import Thread


def receive_data():
    while True:
        receive_data = s.recvfrom(1024)  # 表示本次接受的最大字节数为1024
        receive_content = receive_data[0].decode("gbk")
        print(f"收到远程消息:{receive_content}, from {receive_data[1]}")
        if receive_content == "88":
            print("结束聊天")
            break


def send_data():
    address = ("127.0.0.1", 9999)
    while True:
        data = input("请输入: ")
        s.sendto(data.encode("gbk"), address)
        if data == "88":
            print("结束聊天")
            break


if __name__ == '__main__':
    s = socket(AF_INET, SOCK_DGRAM)  # 创建UDP类型的套接字
    # 示服务器将在本地的8888端口上监听
    s.bind(('127.0.0.1', 8888))  # 绑定端口,ip可以不写

    t1 = Thread(target=receive_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

TCP服务端简化案例

from socket import *

# 建立TCP类型的套接字
server_socket = socket(AF_INET, SOCK_STREAM)

# 本机监听8899端口
# bind方法将套接字绑定到特定的地址和端口上,以便开始监听
server_socket.bind(("127.0.0.1", 8899))

# 开始监听传入连接,最多可以有5个客户连接同时等待接入
server_socket.listen(5)
print("等待接受连接!")

# accept方法用于接受一个新连接,它将阻塞直到一个连接到达
# 返回值是一个元组,包含两个元素:客户端套接字和客户端地址信息
client_socket, client_info = server_socket.accept()

# 使用recv方法从客户端套接字接收数据,缓冲区大小为1024字节
# recv方法将阻塞直到有数据到达
receive_data = client_socket.recv(1024)

# 将接收到的字节数据解码为GBK格式的字符串,并打印出来
# 同时打印出客户端的地址信息
print(f"收到信息: {receive_data.decode('gbk')}, 来自: {client_info}")

# 关闭与客户端的连接套接字
client_socket.close()

# 关闭监听套接字,释放资源
server_socket.close()

这段代码逻辑

  1. 导入socket库。
  2. 创建一个TCP类型的套接字。
  3. 将套接字绑定到本机的8899端口上。
  4. 调用listen方法开始监听传入连接,最多可以有5个连接同时等待接入。
  5. 打印一条消息,通知服务器正在等待接受连接。
  6. 使用accept方法接受一个新连接。accept方法将阻塞直到一个连接到达,返回一个包含客户端套接字和客户端地址信息的元组。
  7. 使用recv方法从客户端套接字接收数据,缓冲区大小为1024字节。
  8. 将接收到的字节数据解码为GBK格式的字符串,并打印出来。同时打印出客户端的地址信息。
  9. 关闭与客户端的连接套接字。
  10. 关闭监听套接字。

TCP客户端简化案例

from socket import *

client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(('127.0.0.1', 8899))

client_socket.send("hello".encode("gbk"))
client_socket.close()

TCP服务端持续交互

from socket import *

server_socket = socket(AF_INET, SOCK_STREAM)  # 建立TCP套接字
server_socket.bind(("127.0.0.1", 8899))  # 本机监听8899端口
server_socket.listen(5)
print("等待接受连接!")

client_socket, client_info = server_socket.accept()
print("一个客户端建立连接成功!")
while True:
    receive_data = client_socket.recv(1024)
    receive_content = receive_data.decode("gbk")
    print(f"客户端说: {receive_content}, 来自: {client_info}")
    if receive_content == "end":
        break

    msg = input(">")
    client_socket.send(msg.encode("gbk"))

client_socket.close()
server_socket.close()

TCP客户端持续交互

from socket import *

client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(("127.0.0.1", 8899))
while True:
    # 给服务器发消息
    msg = input(">")
    client_socket.send(msg.encode("gbk"))
    if msg == "end":
        break

    # 接受服务器端数据
    receive_data = client_socket.recv(1024)
    print(f"服务器端说: {receive_data.decode('gbk')}")

client_socket.close()

TCP服务端增加多线程

from socket import *
from threading import Thread


def receive_data():
    while True:
        receive_data = client_socket.recv(1024)
        receive_content = receive_data.decode("gbk")
        print(f"客户端说: {receive_content}, 来自: {client_info}")
        if receive_content == "end":
            print("结束连接!")
            break


def send_data():
    while True:
        msg = input(">")
        client_socket.send(msg.encode("gbk"))
        if msg == "end":
            print("结束连接!")
            break


if __name__ == '__main__':
    server_socket = socket(AF_INET, SOCK_STREAM)  # 建立TCP套接字
    server_socket.bind(("127.0.0.1", 8899))  # 本机监听8899端口
    server_socket.listen(5)
    print("等待接受连接!")

    client_socket, client_info = server_socket.accept()
    print("一个客户端建立连接成功!")

    t1 = Thread(target=receive_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    client_socket.close()
    server_socket.close()

TCP客户端增加线程

from socket import *
from threading import Thread


def receive_data():
    while True:
        # 接受服务器端数据
        receive_data = client_socket.recv(1024)
        receive_content = receive_data.decode('gbk')
        print(f"服务器端说: {receive_content}")
        if receive_content == "end":
            print("结束连接")
            break


def send_data():
    while True:
        # 给服务器发消息
        msg = input(">")
        client_socket.send(msg.encode("gbk"))
        if msg == "end":
            break


if __name__ == '__main__':
    client_socket = socket(AF_INET, SOCK_STREAM)
    client_socket.connect(("127.0.0.1", 8899))

    t1 = Thread(target=receive_data)
    t2 = Thread(target=send_data)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    client_socket.close()

碰到的问题

OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

  • 解决方法:通常是客户端和服务端的接口设置的不对,参考上面的代码UDP和多线程实现双向自由通信
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值