当前位置: 代码网 > it编程>前端脚本>Python > Python中Socket编程底层原理解析与应用实战

Python中Socket编程底层原理解析与应用实战

2024年08月28日 Python 我要评论
引言socket编程是网络通信的基础,python通过内置的socket模块提供了强大的网络编程接口。socket编程允许开发者创建客户端和服务器程序,实现数据在网络中的传输。本文将结合实际案例,详细

引言

socket编程是网络通信的基础,python通过内置的socket模块提供了强大的网络编程接口。socket编程允许开发者创建客户端和服务器程序,实现数据在网络中的传输。本文将结合实际案例,详细介绍python中socket编程的基本概念、常用方法和实际应用。

一、基本概念

服务器与客户端

  • 服务器:一系列硬件或软件,为一个或多个客户端(服务的用户)提供所需的“服务”。它响应客户端的请求,并等待更多的请求。
  • 客户端:向服务器请求服务的用户或程序。它发送请求并接收服务器的响应。

套接字(socket)

  • 套接字是计算机网络数据结构,它体现了通信端点的概念。在任何类型的通信开始之前,网络应用程序必须创建套接字。套接字可以被比作电话插孔,没有它将无法进行通信。
  • python中的socket模块支持多种类型的套接字,包括基于ipv4的af_inet(流式套接字和数据报套接字)。

流式套接字(sock_stream)

  • 用于提供面向连接、可靠的数据传输服务。它基于tcp协议,确保数据按顺序、无差错、不重复地传输。

数据报套接字(sock_dgram)

  • 提供一种无连接的服务。数据报套接字基于udp协议,不保证数据传输的可靠性,数据可能在传输过程中丢失或重复,且无法保证顺序地接收到数据。

二、python中的socket编程

2.1 常见的套接字对象方法和属性

在python的socket编程中,常用的方法包括:

  • socket(): 创建一个新的套接字对象。
  • bind(): 将套接字绑定到特定的ip地址和端口号上。
  • listen(): 开始监听客户端的连接请求。
  • accept(): 接受一个连接请求,并返回一个新的套接字对象和客户端的地址信息。
  • connect(): 客户端使用该方法连接到服务器。
  • send() / sendall(): 发送数据到连接的套接字。sendall()确保数据被完整发送。
  • recv() / recvfrom(): 接收数据。recv()用于tcp连接,recvfrom()用于udp连接。
  • close(): 关闭套接字。

2.2 创建tcp服务和客户端

2.2.1 创建tcp服务

创建一个简单的tcp服务器,步骤如下:

  1. 导入socket模块。
  2. 创建套接字对象,指定af_inet和sock_stream。
  3. 绑定套接字到ip地址和端口号。
  4. 调用listen()方法监听连接请求。
  5. 使用accept()方法接受连接请求,进入通信循环。
  6. 在通信循环中,使用recv()接收数据,使用send()或sendall()发送数据。
  7. 关闭套接字。
import socket

host = '127.0.0.1'  # 监听所有可用接口
port = 9001
addr = (host, port)
bufsiz = 1024

def tcp_server():
    with socket.socket(socket.af_inet, socket.sock_stream) as s:
        s.bind(addr)
        s.listen()
        print('等待用户接入...')
        while true:
            conn, addr = s.accept()
            with conn:
                print(f'连接来自 {addr}')
                while true:
                    data = conn.recv(bufsiz)
                    if not data:
                        break
                    print(f'收到数据: {data.decode()}')
                    conn.send(data)  # echo服务器,原样返回数据

if __name__ == '__main__':
    tcp_server()

在这里插入图片描述

2.2.2 创建tcp客户端

创建tcp客户端的步骤如下:

  • 导入socket模块。
  • 创建套接字对象,指定af_inet和sock_stream。
  • 使用connect()方法连接到服务器。
  • 进入通信循环,使用send()发送数据,使用recv()接收数据。
  • 关闭套接字。
import socket

host = '127.0.0.1'
port = 9001
addr = (host, port)
bufsiz = 1024

def tcp_client():
    with socket.socket(socket.af_inet, socket.sock_stream) as s:
        s.connect(addr)
        print('连接服务成功!!')
        while true:
            data = input('请输入数据: ')
            if data == 'q':
                break
            s.send(data.encode())
            recved =s.recv(bufsiz).decode()
            print(f'收到服务器响应: {recved}')

if __name__ == '__main__':
    tcp_client()

在这里插入图片描述

客户端输入消息,收到服务端同样的返回

在这里插入图片描述

2.3 创建udp服务和客户端

udp服务与tcp服务的主要区别在于无连接和不可靠的数据传输。

2.3.1 创建udp服务器

udp服务器通常不需要监听连接请求,因为它不建立持久的连接。服务器只需绑定到特定端口,并等待接收数据。

import socket

host = '127.0.0.1'
port = 9002
bufsiz = 1024
addr = (host, port)

def udp_server():
    with socket.socket(socket.af_inet, socket.sock_dgram) as s:
        s.bind(addr)
        print('udp服务器启动...')
        while true:
            data, addr = s.recvfrom(bufsiz)
            print(f'收到来自 {addr} 的数据: {data.decode()}')
            resp = '收到您的消息!'.encode()
            s.sendto(resp, addr)

if __name__ == '__main__':
    udp_server()

在这里插入图片描述

2.3.2 创建udp客户端

udp客户端向服务器发送数据,并等待接收响应(尽管这不是必须的,因为udp是无连接的)。

import socket

host = '127.0.0.1'
port = 9002
bufsiz = 1024
addr = (host, port)

def udp_client():
    with socket.socket(socket.af_inet, socket.sock_dgram) as s:
        while true:
            data = input('请输入数据(输入q退出): ')
            if data == 'q':
                break
            s.sendto(data.encode(), addr)
            resp, server = s.recvfrom(bufsiz)
            print(f'收到服务器响应: {resp.decode()}')

if __name__ == '__main__':
    udp_client()

在这里插入图片描述

客户端输入消息,也能收到服务端消息

在这里插入图片描述

三、实际案例:简单的聊天室应用

以下是一个简单的tcp聊天室应用,它包含一个服务器和多个客户端。服务器将来自任一客户端的消息广播给所有已连接的客户端。

tcp聊天室服务器

import socket
import threading

host = 'localhost'
port = 9003
bufsiz = 1024
addr = (host, port)
clients = []

def handle_client(conn, addr):
    print(f'连接来自 {addr}')
    conn.send('欢迎来到聊天室!'.encode())
    clients.append(conn)
    try:
        while true:
            data = conn.recv(bufsiz)
            if not data:
                break
            broadcast(data, conn)
    finally:
        conn.close()
        clients.remove(conn)

def broadcast(data, sender):
    for client in clients:
        print("打印客户端",client)
        print("打印客户端发来的数据",data.decode())
        if client == sender:
            try:
                #将客户端的原文发动给客户端
                sender.send(data)
            except:
                clients.remove(client)

def main():
    with socket.socket(socket.af_inet, socket.sock_stream) as s:
        s.bind(addr)
        s.listen()
        print('等待用户接入...')
        while true:
            conn, addr = s.accept()
            thread = threading.thread(target=handle_client, args=(conn, addr))
            thread.start()

if __name__ == '__main__':
    main()

在这里插入图片描述

tcp聊天室客户端

import socket

host = 'localhost'
port = 9003
bufsiz = 1024
addr = (host, port)

def chat_client():
    with socket.socket(socket.af_inet, socket.sock_stream) as s:
        s.connect(addr)
        print(s.recv(bufsiz).decode())
        while true:
            data = input('请输入消息(输入q退出): ')
            if data == 'q':
                break
            s.send(data.encode())
            if data.lower() == 'bye':
                break
            print(s.recv(bufsiz).decode())

if __name__ == '__main__':
    chat_client()

在这里插入图片描述

我们也可以运行好几个客户端,服务端打印哪个客户端连过来

在这里插入图片描述

当然,我们可以继续深入讨论socket编程及其在python中的应用,包括一些高级话题和最佳实践。以下是一些扩展内容:

四、高级话题和最佳实践

1. 异步socket编程

python的asyncio库提供了对异步io的支持,这使得编写非阻塞的socket客户端和服务器变得更加容易。使用asyncio,你可以编写出性能更高、响应更快的网络应用程序。

异步tcp服务器示例

import asyncio

async def handle_echo(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')
    print(f"received {message} from {addr}")

    print(f"send: {message.upper()} to {addr}")
    writer.write(message.upper().encode())
    await writer.drain()

    print("close the connection")
    writer.close()

async def main():
    server = await asyncio.start_server(
        handle_echo, '127.0.0.1', 8888)

    addr = server.sockets[0].getsockname()
    print(f'serving on {addr}')

    async with server:
        await server.serve_forever()

asyncio.run(main())

异步tcp客户端示例

import asyncio

async def tcp_echo_client(message, host, port):
    reader, writer = await asyncio.open_connection(host, port)

    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!', '127.0.0.1', 8888))

2. 错误处理和异常

在网络编程中,处理各种网络错误和异常是非常重要的。例如,连接超时、连接中断、数据发送失败等都是常见的错误情况。

在python中,你可以通过try...except块来捕获和处理这些异常。例如,使用socket.timeout来处理连接超时,使用socket.error来处理一般的socket错误。

3. 安全性

当编写网络应用程序时,安全性是一个重要的考虑因素。以下是一些提升socket程序安全性的方法:

  • 使用ssl/tls来加密数据传输。python的ssl模块可以与socket模块一起使用来创建安全的socket连接。
  • 验证客户端的身份(如果需要的话)。可以使用证书、密钥或令牌等方式来验证客户端的合法性。
  • 限制可以连接到服务器的ip地址或端口范围。这可以通过防火墙规则或服务器软件中的设置来实现。

4. 性能和优化

socket编程的性能优化可以涉及多个方面,包括网络延迟、吞吐量、并发处理能力等。以下是一些优化技巧:

  • 使用非阻塞或异步io来减少等待时间。
  • 使用合适的缓冲区大小来平衡内存使用和网络性能。
  • 使用多线程或多进程来处理多个并发连接。
  • 压缩数据以减少传输量,特别是当数据量大时。
  • 使用缓存来存储常用数据,减少对后端服务的请求。

5. 调试和日志记录

在网络编程中,调试和日志记录是非常重要的工具。它们可以帮助你理解程序的行为,诊断问题,并优化性能。

  • 使用python的logging模块来记录程序的运行状态、错误信息和警告。
  • 在关键位置添加调试语句或断点,以便在出现问题时能够追踪程序的执行流程。
  • 使用网络抓包工具(如wireshark)来捕获和分析网络数据包,了解数据的实际传输情况。

五、总结

socket编程是构建网络应用程序的基础。通过掌握socket编程的基本概念、tcp和udp的使用方法,以及异步编程、错误处理、安全性、性能和调试等高级话题,你可以开发出高效、稳定、安全的网络应用程序。希望本文对你有所帮助!

以上就是python中socket编程底层原理解析与应用实战的详细内容,更多关于python socket编程的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com