Python中的网络编程介绍

101 阅读6分钟

本教程将介绍Python中的套接字以及如何使用套接字模块在Python中构建HTTP服务器和客户端。它还将介绍Tornado,一个Python网络库,它是长轮询、WebSockets和其他需要与每个用户建立长期连接的应用的理想选择。

什么是套接字?

套接字是两个应用程序之间的链接,它们可以相互通信(可以是在一台机器上的本地通信,也可以是在不同地点的两台机器之间的远程通信)。

基本上,套接字作为两个实体之间的通信链接,即服务器和客户端。服务器将发出被客户要求的信息。例如,当你访问这个页面时,浏览器创建了一个套接字并连接到服务器。

套接字模块

为了创建一个套接字,你使用socket.socket() 函数,其语法就像这样简单:

import socket
s= socket.socket (socket_family, socket_type, protocol=0)

下面是参数的描述:

  • socket_family:代表地址(和协议)家族。它可以是AF_UNIX或AF_INET。
  • socket_type:代表套接字类型,可以是SOCK_STREAM或SOCK_DGRAM。
  • 协议:这是一个可选的参数,它通常默认为0。

在获得你的套接字对象后,你可以根据需要使用套接字模块中的方法创建一个服务器或客户端。

创建一个简单的客户端

在我们开始之前,让我们看看 Python 中可用的客户端套接字方法:

  • s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • s.connect():启动一个TCP服务器连接。

要创建一个新的套接字,首先要导入套接字类的套接字方法:

import socket

接下来,我们将创建一个流(TCP)套接字,如下所示:

stream_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

AF_INET 参数表示你正在请求一个互联网协议(IP)套接字,特别是IPv4。第二个参数是TCP套接字的传输协议类型SOCK_STREAM 。此外,你也可以通过指定套接字AF_INET6 参数来创建一个IPv6套接字。

指定服务器:

server = "localhost"

指定我们要通信的端口:

port =80

将套接字连接到服务器正在监听的端口:

server_address = ((host, port))
stream_socket.connect(server_address)


值得注意的是,主机和端口必须是一个元组。

向服务器发送一个数据请求:

message = 'message'
stream_socket.sendall(message)

从服务器获取响应:

data = sock.recv(10)
print(data)

要关闭一个连接的套接字,你使用close方法:

stream_socket.close()

下面是客户端/服务器的完整代码:

import socket
 
# Create a TCP/IP socket
stream_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
# Define host
host = 'localhost'
 
# define the communication port
port = 8080
 
# Connect the socket to the port where the server is listening
server_address = ((host, port))
 
print("connecting")
 
stream_socket.connect(server_address)
 
 
# Send data
message = 'message'
stream_socket.sendall(message.encode())
 
# response
data = stream_socket.recv(10)
print(data)
 
 
print('socket closed')

建立一个简单的服务器

现在让我们来看看一个简单的Python服务器。下面是Python中可用的套接字服务器方法:

  • s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • s.bind():将地址(主机名,端口号)与套接字绑定。
  • s.listen():设置并启动TCP监听器。
  • s.accept():接受TCP客户端连接。

我们将遵循以下步骤:

  • 创建一个套接字。
  • 将套接字绑定到一个端口。
  • 开始接受该套接字的连接。

这里是服务器程序:

import socket
 
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
# Define host
host = 'localhost'
 
# define the communication port
port = 8080
 
# Bind the socket to the port
sock.bind((host, port))
# Listen for incoming connections
sock.listen(1)
 
# Wait for a connection
print('waiting for a connection')
connection, client = sock.accept()
 
print(client, 'connected')
 
# Receive the data in small chunks and retransmit it
 
data = connection.recv(16)
print('received "%s"' % data)
if data:
 
    connection.sendall(data)
else:
    print('no data from', client)
 
 
# Close the connection
connection.close()

现在服务器已经准备好接收连接了。

现在在不同的终端窗口中运行客户端和服务器程序,这样它们就可以互相通信了。

服务器输出

$ python server.py 
waiting for a connection
('127.0.0.1', 45504) connected
received "b'message'

客户端输出

$ python client.py 
connecting
b'message'
socket closed

要查看哪些端口目前正在使用,你可以使用nestat -ntlp命令,如下图所示

龙卷风框架

Tornado框架是Python中可用于网络编程的库之一。在本节中,我们将讨论这个库,并展示如何使用它来构建WebSockets。

Tornado是一个Python网络框架和异步网络库。Tornado使用非阻塞的网络I/O,因此能够扩展到数以万计的开放连接。这一特性使其成为长轮询、WebSockets以及其他需要与每个用户建立长期连接的应用程序的理想选择。

让我们创建一个简单的Tornado WebSocket:

import tornado.ioloop
import tornado.web


class ApplicationHandler(tornado.web.RequestHandler):

    def get(self):
        self.message = message = """<html>
<head>
    <title>Tornado Framework</title>

</head>
<body
    <h2>Welcome to the Tornado framework</h2>
</body>
</html>"""
        self.write(message)


if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", ApplicationHandler),
    ])
    application.listen(5001)
    tornado.ioloop.IOLoop.instance().start()

在上面的代码中:

  • 我们定义了ApplicationHandler ,该类作为请求的处理程序,并使用write() 方法返回响应。
  • main 方法是该程序的入口。
  • tornado.web.Application 创建了一个网络应用程序的基础,并接受一个处理程序的集合,即ApplicationHandler。
  • 应用程序在5000端口监听,客户端可以使用相同的端口与该应用程序通信。
  • tornado.ioloop.IOLoop.instance().start() 为一个应用程序创建一个非阻塞的线程。

如果我们运行该应用程序,我们将得到如下截图所示的结果:

Tornado还与asyncio模块集成,允许你在同一个事件循环中使用这两个库。Asyncio是一个Python库,它将使你能够用 async/await 语法编写coroutines 。

同步与异步编程

同步编程是指任务是有顺序的。所有的任务都遵循一个特定的顺序,这意味着每个任务在下一个任务开始之前都要从头到尾完成。

同步编程的缺点是,如果一个特定的任务需要相当长的时间来执行,前面的任务必须等待该任务完成;这将导致延迟。

然而,异步编程意味着任务可以同时进行,无需等待其他工作完成执行。

异步通信主要用于聊天应用程序,以及显示实时数据的应用程序。

当从API中获取数据时,异步编程拯救了这一天。从API中获取数据或进行HTTP请求可能需要比预期更长的时间;与其等待http请求完成,不如在HTTP调用上应用异步函数。

异步调用释放了程序,使其在其他领域继续执行。

异步编程的另一个优点是,如果你正在进行多个请求,其中一个请求突然停止,这不会影响到其他的请求,因为程序被允许转移到下一个任务。

假设你有一个应用程序,多次向外部API服务器请求。通过同步编程,应用程序将不得不等待,直到进行中的API完成HTTP请求并返回响应,使你的应用程序变得缓慢。

例如,假设我们想请求一个外部API,如天气API。让我们用Tornado执行同步和异步调用,以获取伦敦市的天气信息:

# synchronous function

from tornado.httpclient import HTTPClient
key = 'my_secret_key'

def get_weather():
    city = 'london'
    url = 'https://api.weatherapi.com/v1/current.json?key='+key+'&q='+city+'&aqi=no'
    print(url)
    http_client = HTTPClient()
    response = http_client.fetch(url)
    return (response.body)
    
# Asynchronous function
from tornado.httpclient import AsyncHTTPClient
secret_key = 'my_secret_key'

async def get_weather():
    city = 'london'
    url = 'http://api.weatherapi.com/v1/current.json?key='+key+'&q='+city+'&aqi=no'
    print(url)
    http_client = AsyncHTTPClient()
    response = await http_client.fetch(url)
    return (response.body)

总结

现在你一定已经掌握了Python中套接字编程的基础知识,以及如何建立一个简单的服务器和客户端。请自由地通过建立你自己的聊天客户端进行试验。更多信息,请访问官方Python文档。