第九章 Python Socket编程

目录

10.1 Socket的基本概念

什么是Socket?

Socket类型

Socket地址

10.2 创建Socket

示例代码:

10.3 绑定Socket

示例代码:

10.4 监听和接受连接

示例代码:

10.5 连接到服务器

示例代码:

10.6 处理并发连接

多线程处理并发连接

10.7 数据报Socket编程

服务器端示例代码:

客户端示例代码:

10.8 使用select实现I/O多路复用

示例代码:

10.9 异步Socket编程

服务器端示例代码:

客户端示例代码:

10.10 Socket编程最佳实践

处理异常

使用超时

资源管理

示例代码:

10.11 实战案例:简单的聊天程序

服务器端代码:

客户端代码:

10.12 本章小结


Socket编程是网络编程的重要组成部分,它允许程序在网络上进行通信。Python提供了强大的socket模块,使得编写网络应用变得更加简单和直观。本章将详细探讨Python中的Socket编程,涵盖基本概念、常用操作和实际应用案例。

10.1 Socket的基本概念

什么是Socket?

Socket是一种用于网络通信的端点,它可以在不同的计算机之间传输数据。Socket编程涉及到在网络中创建、绑定、监听和连接Socket,以实现数据的发送和接收。

Socket类型
  • 流式Socket(SOCK_STREAM):基于TCP协议,提供面向连接的可靠数据传输服务。
  • 数据报Socket(SOCK_DGRAM):基于UDP协议,提供无连接的、不可靠的数据传输服务。
Socket地址

Socket地址由IP地址和端口号组成,用于唯一标识网络中的通信端点。

10.2 创建Socket

创建Socket是进行网络编程的第一步。可以使用socket.socket()函数来创建一个Socket对象。

示例代码:
import socket

# 创建一个TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 设置Socket选项(可选)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

10.3 绑定Socket

绑定Socket是指将Socket与特定的IP地址和端口号关联起来,使得Socket可以在指定的地址和端口上监听或发送数据。

示例代码:
import socket

# 创建一个TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定Socket到地址和端口
server_address = ('localhost', 8080)
sock.bind(server_address)

print(f"Starting up on {server_address[0]} port {server_address[1]}")

10.4 监听和接受连接

在服务器端,Socket需要进入监听状态,等待客户端的连接请求。当有客户端连接时,服务器需要接受连接,并创建一个新的Socket来处理该连接。

示例代码:
import socket

# 创建一个TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定Socket到地址和端口
server_address = ('localhost', 8080)
sock.bind(server_address)

# 监听连接
sock.listen(1)

while True:
    print("Waiting for a connection")
    connection, client_address = sock.accept()
    try:
        print(f"Connection from {client_address}")
        while True:
            data = connection.recv(16)
            if data:
                print(f"Received: {data}")
                connection.sendall(data)
            else:
                break
    finally:
        connection.close()

10.5 连接到服务器

在客户端,Socket需要连接到服务器的地址和端口,以便进行数据传输。

示例代码:
import socket

# 创建一个TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接到服务器
server_address = ('localhost', 8080)
print(f"Connecting to {server_address[0]} port {server_address[1]}")
sock.connect(server_address)

try:
    # 发送数据
    message = 'This is the message. It will be repeated.'
    print(f"Sending: {message}")
    sock.sendall(message.encode())

    # 接收数据
    amount_received = 0
    amount_expected = len(message)
    
    while amount_received < amount_expected:
        data = sock.recv(16)
        amount_received += len(data)
        print(f"Received: {data}")
finally:
    print("Closing socket")
    sock.close()

10.6 处理并发连接

在实际应用中,服务器通常需要同时处理多个客户端连接。可以使用多线程或多进程来实现并发连接处理。

多线程处理并发连接

示例代码:

import socket
import threading

def handle_client(connection, client_address):
    try:
        print(f"Connection from {client_address}")
        while True:
            data = connection.recv(16)
            if data:
                print(f"Received: {data}")
                connection.sendall(data)
            else:
                break
    finally:
        connection.close()

# 创建一个TCP/IP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 8080)
sock.bind(server_address)
sock.listen(5)

while True:
    print("Waiting for a connection")
    connection, client_address = sock.accept()
    client_thread = threading.Thread(target=handle_client, args=(connection, client_address))
    client_thread.start()

10.7 数据报Socket编程

数据报Socket基于UDP协议,适用于需要快速传输、不需要可靠连接的数据传输场景。

服务器端示例代码:
import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 8080)
sock.bind(server_address)

while True:
    print("Waiting to receive message")
    data, address = sock.recvfrom(4096)
    print(f"Received {data} bytes from {address}")
    if data:
        sent = sock.sendto(data, address)
        print(f"Sent {sent} bytes back to {address}")
客户端示例代码:
import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('localhost', 8080)
message = 'This is the message. It will be repeated.'

try:
    print(f"Sending: {message}")
    sent = sock.sendto(message.encode(), server_address)
    data, server = sock.recvfrom(4096)
    print(f"Received: {data}")
finally:
    print("Closing socket")
    sock.close()

10.8 使用select实现I/O多路复用

select模块允许同时监听多个Socket,适用于需要同时处理多个连接的场景。它通过监视Socket的状态来实现I/O多路复用。

示例代码:
import select
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('localhost', 8080)
server.bind(server_address)
server.listen(5)

sockets_list = [server]
clients = {}

print("Server started on port 8080")

while True:
    read_sockets, _, _ = select.select(sockets_list, [], sockets_list)
    for notified_socket in read_sockets:
        if notified_socket == server:
            client_socket, client_address = server.accept()
            sockets_list.append(client_socket)
            clients[client_socket] = client_address
            print(f"Accepted new connection from {client_address}")
        else:
            message = notified_socket.recv(1024)
            if message:
                print(f"Received message from {clients[notified_socket]}: {message.decode('utf-8')}")
                notified_socket.sendall(message)
            else:
                print(f"Closed connection from {clients[notified_socket]}")
                sockets_list.remove(notified_socket)
                del clients[notified_socket]
                notified_socket.close()

10.9 异步Socket编程

Python的asyncio库提供了对异步Socket编程的支持,可以更高效地处理I/O操作。

服务器端示例代码:
import asyncio

async def handle_client(reader, writer):
    while True:
        data = await reader.read(100)
        if not data:
            break
        message = data.decode()
        addr = writer.get_extra_info('peername')
        print(f"Received {message} from {addr}")
        writer.write(data)
        await writer.drain()
    writer.close()

async def main():
    server = await asyncio.start_server(handle_client, 'localhost', 8080)
    async with server:
        await server.serve_forever()

asyncio.run(main())
客户端示例代码:
import asyncio

async def tcp_echo_client(message):
    reader, writer = await asyncio.open_connection('localhost', 8080)
    print(f'Send: {message}')
    writer.write(message.encode())
    data = await reader.read(100)
    print(f'Received: {data.decode()}')
    writer.close()

asyncio.run(tcp_echo_client('Hello, World!'))

10.10 Socket编程最佳实践

在进行Socket编程时,遵循一些最佳实践可以提高代码的健壮性和可维护性。

处理异常

在网络编程中,异常情况是常见的,应该在代码中处理各种可能的异常。

使用超时

设置Socket超时可以避免程序长时间阻塞在某个操作上,提高程序的响应能力。

资源管理

确保Socket资源在使用完毕后被正确释放,避免资源泄漏。

示例代码:
import socket

try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)  # 设置超时
    server_address = ('localhost', 8080)
    sock.connect(server_address)
    sock.sendall(b'Hello, World!')
    data = sock.recv(1024)
    print(f'Received: {data.decode()}')
finally:
    print('Closing socket')
    sock.close()

10.11 实战案例:简单的聊天程序

通过一个实际案例,展示如何使用Socket编程实现一个简单的聊天程序,支持多个客户端与服务器进行通信。

服务器端代码:
import socket
import threading

def handle_client(client_socket):
    while True:
        try:
            message = client_socket.recv(1024)
            if not message:
                break
            print(f"Received: {message.decode()}")
            broadcast(message, client_socket)
        except:
            break
    client_socket.close()

def broadcast(message, client_socket):
    for client in clients:
        if client != client_socket:
            try:
                client.send(message)
            except:
                client.close()
                clients.remove(client)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 8080))
server.listen(5)
clients = []

print("Chat server started on port 8080")

while True:
    client_socket, addr = server.accept()
    clients.append(client_socket)
    print(f"Accepted new connection from {addr}")
    client_thread = threading.Thread(target=handle_client, args=(client_socket,))
    client_thread.start()
客户端代码:
import socket
import threading

def receive_messages(client_socket):
    while True:
        try:
            message = client_socket.recv(1024)
            if not message:
                break
            print(message.decode())
        except:
            break

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 8080))

receive_thread = threading.Thread(target=receive_messages, args=(client_socket,))
receive_thread.start()

while True:
    message = input()
    client_socket.send(message.encode())

10.12 本章小结

在本章中,我们详细探讨了Python中的Socket编程,包括Socket的基本概念、创建和绑定Socket、监听和接受连接、处理并发连接、数据报Socket编程、使用select实现I/O多路复用、异步Socket编程以及Socket编程的最佳实践。通过实际案例,我们展示了如何使用Socket编程实现一个简单的聊天程序。

Socket编程是网络编程的基础,掌握Socket编程可以让您在网络应用开发中更加得心应手。希望这篇博客能够帮助您深入理解和应用Python的Socket编程。

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

深度学习客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值