Python 简明教程

Python - Socket Programming

Python Socket Programming

Socket programming 是一种技术,其中我们让连接在网络中的两个节点之间进行通信,其中服务器节点监听来自客户端节点的传入请求。

Socket programming is a technique in which we communicate between two nodes connected in a network where the server node listens to the incoming requests from the client nodes.

在 Python 中, socket 模块用于套接字编程。标准库中的 socket 模块包括在硬件级别进行服务器和客户端之间通信所需的功能。

In Python, the socket module is used for socket programming. The socket module in the standard library included functionality required for communication between server and client at hardware level.

本模块提供了 BSD 套接字接口的访问权限。它可在所有操作系统上使用,例如 Linux、Windows、MacOS。

This module provides access to the BSD socket interface. It is available on all operating systems such as Linux, Windows, MacOS.

What are Sockets?

套接字是双向通信通道的端点。套接字可以在进程内进行通信,也可以在同一电脑上的进程之间或不同区域中的进程之间进行通信。

Sockets are the endpoints of a bidirectional communications channel. Sockets may communicate within a process, between processes on the same machine, or between processes on different continents.

套接字通过 IP 地址和端口号组合识别。为了开始通信,它应该在两端均正确配置。

A socket is identified by the combination of IP address and the port number. It should be properly configured at both ends to begin communication.

connection
ip address

套接字可以用许多不同信道类型执行:Unix 域套接字、TCP、UDP 等。套接字库为处理常见的传输提供了特定类,并为处理其余部分提供了一个通用接口。

Sockets may be implemented over a number of different channel types: Unix domain sockets, TCP, UDP, and so on. The socket library provides specific classes for handling the common transports as well as a generic interface for handling the rest.

套接字编程术语意味着以编程方式设置套接字,使其能够发送和接收数据。

The term socket programming implies programmatically setting up sockets to be able to send and receive data.

有两种类型的通信协议 −

There are two types of communication protocols −

  1. connection-oriented protocol

  2. connection-less protocol

TCP 或传输控制协议是一种面向连接的协议。数据由服务器以数据包形式传输,并由接收器按照相同传输顺序进行组装。因为通信两端的套接字在开始之前需要设置,所以这种方法的可靠性更高。

TCP or Transmission Control Protocol is a connection-oriented protocol. The data is transmitted in packets by the server, and assembled in the same order of transmission by the receiver. Since the sockets at either end of the communication need to be set before starting, this method is more reliable.

UDP 或用户数据报协议是无连接的。该方法不可靠,因为套接字不需要建立任何用于传输数据连接和终止处理。

UDP or User Datagram Protocol is connectionless. The method is not reliable because the sockets does not require establishing any connection and termination process for transferring the data.

Python socket Module

socket 模块用于为网络中连接的节点创建和管理套接字编程。 socket 模块提供了一个 socket 类。您需要使用 socket.socket() 构造函数创建套接字。

The socket module is used for creating and managing socket programming for the connected nodes in a network. The socket module provides a socket class. You need to create a socket using the socket.socket() constructor.

socket 类的对象代表主机名和端口号对。

An object of the socket class represents the pair of host name and the port numbers.

Syntax

下面是 socket.socket() 构造函数的语法 -

The following is the syntax of socket.socket() constructor –

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

Parameters

  1. family − AF_INET by default. Other values - AF_INET6 (eight groups of four hexadecimal digits), AF_UNIX, AF_CAN (Controller Area Network) or AF_RDS (Reliable Datagram Sockets).

  2. socket_type − should be SOCK_STREAM (the default), SOCK_DGRAM, SOCK_RAW or perhaps one of the other SOCK_ constants.

  3. protocol − number is usually zero and may be omitted.

Return Type

此方法返回一个套接字对象。

This method returns a socket object.

一旦有了套接字对象,你可以使用所需的方法创建客户端或服务器程序。

Once you have the socket object, then you can use the required methods to create your client or server program.

Server Socket Methods

在服务器上实例化的套接字称为服务器套接字。以下方法可在服务器上的套接字对象上使用 −

The socket instantiated on server is called server socket. Following methods are available to the socket object on the server −

  1. bind() method − This method binds the socket to specified IP address and port number.

  2. listen() method − This method starts server and runs into a listen loop looking for connection request from client.

  3. accept() method − When connection request is intercepted by server, this method accepts it and identifies the client socket with its address.

要在服务器上创建套接字,请使用以下片段 −

To create a socket on a server, use the following snippet −

import socket
server = socket.socket()
server.bind(('localhost',12345))
server.listen()
client, addr = server.accept()
print ("connection request from: " + str(addr))

默认情况下,服务器绑定到本地计算机的 IP 地址“localhost”,监听在任意空闲的端口号。

By default, the server is bound to local machine’s IP address 'localhost' listening at arbitrary empty port number.

Client Socket Methods

在客户端设置了类似的套接字。它主要向其 IP 地址和端口号处监听的服务器套接字发送连接请求。

Similar socket is set up on the client end. It mainly sends connection request to server socket listening at its IP address and port number

connect() method

此方法以一个二元组对象作为参数。这两个成员是服务器的 IP 地址和端口号。

This method takes a two-item tuple object as argument. The two items are IP address and port number of the server.

obj=socket.socket()
obj.connect((host,port))

一旦连接被服务器接受,两个套接字对象都可以发送和/或接收数据。

Once the connection is accepted by the server, both the socket objects can send and/or receive data.

send() method

服务器使用它截获的地址向客户端发送数据。

The server sends data to client by using the address it has intercepted.

client.send(bytes)

客户端套接字向与其建立连接的套接字发送数据。

Client socket sends data to socket it has established connection with.

sendall() method

与 send() 类似。但是与 send() 不同,此方法会持续发送数据字节,直到所有数据发送完毕或者出现错误。成功时不返回任何内容。

similar to send(). However, unlike send(),this method continues to send data from bytes until either all data has been sent or an error occurs. None is returned on success.

sendto() method

此方法仅在 UDP 协议的情况下使用。

This method is to be used in case of UDP protocol only.

recv() method

此方法用于检索发送到客户端的数据。对于服务器而言,它使用其请求已被接受的远程套接字。

This method is used to retrieve data sent to the client. In case of server, it uses the remote socket whose request has been accepted.

client.recv(bytes)

recvfrom() method

此方法在 UDP 协议中使用。

This method is used in case of UDP protocol.

Python - Socket Server

要编写 Internet 服务器,我们使用 socket 模块中可用的 socket 函数创建一个 socket 对象。此后使用该 socket 对象来调用其他函数以设置一个 socket 服务器。

To write Internet servers, we use the socket function available in socket module to create a socket object. A socket object is then used to call other functions to setup a socket server.

现在调用 bind(hostname, port) 函数,为您的服务在给定的主机上指定一个端口。

Now call the bind(hostname, port) function to specify a port for your service on the given host.

接下来,调用返回对象的 accept 方法。此方法会一直等待直到某个客户端连接到您指定的端口,然后返回表示对该客户端连接的连接对象。

Next, call the accept method of the returned object. This method waits until a client connects to the port you specified, and then returns a connection object that represents the connection to that client.

Example of Server Socket

import socket
host = "127.0.0.1"
port = 5001
server = socket.socket()
server.bind((host,port))
server.listen()
conn, addr = server.accept()
print ("Connection from: " + str(addr))
while True:
   data = conn.recv(1024).decode()
   if not data:
      break
   data = str(data).upper()
   print (" from client: " + str(data))
   data = input("type message: ")
   conn.send(data.encode())
conn.close()

Python - Socket Client

接下来让我们编写一个非常简单的客户端程序,该程序打开一个对给定的本地主机和端口 5001 的连接。使用 Python 的 socket 模块函数创建 socket 客户端非常简单。

Let us write a very simple client program, which opens a connection to a given port 5001 and a given localhost. It is very simple to create a socket client using the Python’s socket module function.

socket.connect(hosname, port) 在该端口处向 hostname 打开一个 TCP 连接。一旦您打开一个套接字,就可以像任何 IO 对象一样从中读取内容。完成后,别忘了关闭它,就像你会关闭一个文件一样。

The socket.connect(hosname, port) opens a TCP connection to hostname on the port. Once you have a socket open, you can read from it like any IO object. When done, remember to close it, as you would close a file.

Example of Client Socket

下列代码是一个非常简单的客户端,它连接到给定的主机和端口,从套接字读取任何可用的数据,然后在输入“q”时退出。

The following code is a very simple client that connects to a given host and port, reads any available data from the socket, and then exits when 'q' is entered.

import socket
host = '127.0.0.1'
port = 5001
obj = socket.socket()
obj.connect((host,port))
message = input("type message: ")
while message != 'q':
   obj.send(message.encode())
   data = obj.recv(1024).decode()
   print ('Received from server: ' + data)
   message = input("type message: ")
obj.close()
  1. Run Server code first. It starts listening.

  2. Then start client code. It sends request.

  3. Request accepted. Client address identified

  4. Type some text and press Enter.

  5. Data received is printed. Send data to client.

  6. Data from server is received.

  7. Loop terminates when 'q' is input.

服务器-客户端交互如下所示:

Server-client interaction is shown below −

server client interaction

我们已在本地计算机上使用 socket 模块实现了客户端-服务器通信。若要将服务器和客户端代码放置在网络中的两台不同计算机上,我们需要找到服务器的 IP 地址。

We have implemented client-server communication with socket module on the local machine. To put server and client codes on two different machines on a network, we need to find the IP address of the server machine.

在 Windows 中,可以通过运行 ipconfig 命令来找到 IP 地址。ifconfig 命令是 Ubuntu 上的等效命令。

On Windows, you can find the IP address by running ipconfig command. The ifconfig command is the equivalent command on Ubuntu.

ipv4 address

使用 IPv4 地址值更改服务器和客户端代码中的 host 字符串,并像以前一样运行它们。

Change host string in both the server and client codes with IPv4 Address value and run them as before.

Python File Transfer with Socket Module

下面的程序演示了如何使用套接字通信来将某个文件从服务器传输至客户端。

The following program demonstrates how socket communication can be used to transfer a file from server to the client

Server Code

建立连接的代码与之前相同。连接请求被接受后,服务器上的一个文件会以二进制模式打开用于读取,且字节会顺序读取并发送至客户端流,直至到达文件结尾。

The code for establishing connection is same as before. After the connection request is accepted, a file on server is opened in binary mode for reading, and bytes are successively read and sent to the client stream till end of file is reached.

import socket
host = "127.0.0.1"
port = 5001
server = socket.socket()
server.bind((host, port))
server.listen()
conn, addr = server.accept()
data = conn.recv(1024).decode()
filename='test.txt'
f = open(filename,'rb')
while True:
   l = f.read(1024)
   if not l:
      break
   conn.send(l)
   print('Sent ',repr(l))
f.close()
print('File transferred')
conn.close()

Client Code

在客户端上,一个新文件会以 wb 模式打开。从服务器接收到的数据流被写入该文件。当流结束时,输出文件会关闭。客户端计算机上会创建一个新文件。

On the client side, a new file is opened in wb mode. The stream of data received from server is written to the file. As the stream ends, the output file is closed. A new file will be created on the client machine.

import socket

s = socket.socket()
host = "127.0.0.1"
port = 5001

s.connect((host, port))
s.send("Hello server!".encode())

with open('recv.txt', 'wb') as f:
   while True:
      print('receiving data...')
      data = s.recv(1024)
      if not data:
         break
      f.write(data)

f.close()
print('Successfully received')
s.close()
print('connection closed')

The Python socketserver Module

Python 标准库中的 socketserver 模块是一个用于简化编写网络服务器任务的框架。该模块中包含以下类,它们表示同步服务器:

The socketserver module in Python’s standard library is a framework for simplifying task of writing network servers. There are following classes in module, which represent synchronous servers −

socketserver module

这些类与相应的 RequestHandler 类结合使用,用于实现服务。BaseServer 是模块中所有 Server 对象的超类。

These classes work with corresponding RequestHandler classes for implementing the service. BaseServer is the superclass of all Server objects in the module.

TCPServer 类使用互联网 TCP 协议,在客户端和服务器之间提供连续数据流。构造函数会自动尝试调用 server_bind() 和 server_activate()。其他参数会传递至 BaseServer 基类。

TCPServer class uses the internet TCP protocol, to provide continuous streams of data between the client and server. The constructor automatically attempts to invoke server_bind() and server_activate(). The other parameters are passed to the BaseServer base class.

你必须创建 StreamRequestHandler 类的子类。它提供了 self.rfile 和 self.wfile 属性,用于读写以获取请求数据或将数据返回至客户端。

You must also create a subclass of StreamRequestHandler class. IT provides self.rfile and self.wfile attributes to read or write to get the request data or return data to the client.

  1. UDPServer and DatagramRequestHandler − These classes are meant to be used for UDP protocol.

  2. DatagramRequestHandler and UnixDatagramServer − These classes use Unix domain sockets; they’re not available on non-Unix platforms.

Server Code

你必须编写一个 RequestHandler 类。每当连接到服务器时,该类都会被实例化一次,且必须重写 handle() 方法来实现与客户端的通信。

You must write a RequestHandler class. It is instantiated once per connection to the server, and must override the handle() method to implement communication to the client.

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
   def handle(self):
      self.data = self.request.recv(1024).strip()
      host,port=self.client_address
      print("{}:{} wrote:".format(host,port))
      print(self.data.decode())
      msg=input("enter text .. ")
      self.request.sendall(msg.encode())

在服务器分配的端口号上,TCPServer 类的对象会调用 forever() 方法,以将服务器置于监听模式并接受来自客户端的传入请求。

On the server’s assigned port number, an object of TCPServer class calls the forever() method to put the server in the listening mode and accepts incoming requests from clients.

if __name__ == "__main__":
   HOST, PORT = "localhost", 9999
   with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
      server.serve_forever()

Client Code

在使用 socketserver 时,客户端代码与 socket 客户端应用程序比较类似。

When working with socketserver, the client code is more or less similar with the socket client application.

import socket
import sys

HOST, PORT = "localhost", 9999

while True:
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
      # Connect to server and send data
      sock.connect((HOST, PORT))
      data = input("enter text .. .")
      sock.sendall(bytes(data + "\n", "utf-8"))

      # Receive data from the server and shut down
      received = str(sock.recv(1024), "utf-8")
      print("Sent: {}".format(data))
      print("Received: {}".format(received))

在命令提示符终端运行服务器代码。为客户端实例打开多个终端。您可以模拟服务器与多个客户端之间的并发通信。

Run the server code in one command prompt terminal. Open multiple terminals for client instances. You can simulate a concurrent communication between the server and more than one clients.