Python Socket编程
标准库中的socket模块包含了在服务器和客户端之间进行硬件级通信所需的功能。
这个模块提供了对BSD套接字接口的访问。它可在所有操作系统上使用,如Linux,Windows,MacOS。
什么是套接字
套接字是双向通信通道的端点。套接字可以在一个进程内部通信,在同一台机器上的不同进程之间通信,或者在不同大陆上的不同进程之间通信。
套接字由IP地址和端口号的组合来标识。在开始通信之前,两端都应该正确配置好套接字。
套接字可以在多种不同的通道类型上实现:Unix域套接字、TCP、UDP等等。套接字库提供了处理常见传输的特定类,以及处理其他传输的通用接口。
套接字编程一词意味着以编程方式设置套接字以能够发送和接收数据。
有两种类型的通信协议−
- 连接导向的协议
-
无连接的协议
TCP或传输控制协议是一种连接导向的协议。服务器通过数据包传输数据,接收器按照传输顺序组装数据。由于通信的两端的套接字需要在开始之前设置,这种方法更可靠。
UDP或用户数据报协议是无连接的。这种方法不可靠,因为套接字不需要建立任何连接和终止过程来传输数据。
Python套接字模块
此模块包括Socket类。套接字对象代表主机名和端口号的配对。构造方法具有以下签名−
语法
socket.socket (socket_family, socket_type, protocol=0)
参数
- family −默认值为AF_INET。其他可选值为AF_INET6(八组四位十六进制数)、AF_UNIX、AF_CAN(Controller Area Network)或AF_RDS(可靠数据报套接字)。
-
socket_type −应该是SOCK_STREAM(默认值)、SOCK_DGRAM、SOCK_RAW或其他SOCK_常量之一。
-
protocol −通常为零,可以省略。
返回类型
此方法返回一个套接字对象。
一旦获得套接字对象,您就可以使用所需的方法来创建客户端或服务器程序。
服务器套接字方法
在服务器上实例化的套接字称为服务器套接字。可以在服务器上对套接字对象使用以下方法:
- bind()方法 −将套接字绑定到指定的IP地址和端口号。
-
listen()方法 −该方法启动服务器并进入一个循环,等待客户端的连接请求。
-
accept()方法 −当服务器接收到连接请求时,这个方法会接受连接,并确定客户端套接字及其地址。
要在服务器上创建套接字,请使用以下代码段:
import socket
server = socket.socket()
server.bind(('localhost',12345))
server.listen()
client, addr = server.accept()
print ("connection request from: " + str(addr))
默认情况下,服务器绑定到本地机器的IP地址“localhost”,并监听任意的空闲端口号。
客户端套接字方法
在客户端端设置类似的套接字。它主要向在其IP地址和端口号监听的服务器套接字发送连接请求。
connect() 方法
此方法接受一个包含两个项的元组对象作为参数。这两个项分别是服务器的IP地址和端口号。
obj=socket.socket()
obj.connect((host,port))
一旦连接被服务器接受,两个套接字对象都可以发送和/或接收数据。
send() 方法
服务器通过使用拦截到的地址向客户端发送数据。
client.send(bytes)
客户端套接字将数据发送到它已建立连接的套接字。
sendall()方法
类似于send()方法。然而,与send()不同的是,该方法会继续从字节中发送数据,直到全部数据都被发送或发生错误。成功时返回None。
sendto()方法
此方法仅用于UDP协议。
recv()方法
此方法用于检索发送给客户端的数据。对于服务器,它使用已接受请求的远程套接字。
client.recv(bytes)
recvfrom()方法
这个方法用于UDP协议的情况。
Python – Socket 服务器
为了编写Internet服务器,我们使用socket模块中的socket函数来创建一个socket对象。然后使用socket对象来调用其他函数来设置一个socket服务器。
现在调用bind(hostname,port)函数来为你的服务指定一个端口。
接下来,调用返回对象的accept方法。该方法会等待直到客户端连接到你指定的端口,然后返回一个表示与该客户端连接的连接对象。
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客户端非常简单。
socket.connect(hostname, port) 打开一个TCP连接到主机名和端口。一旦你打开了一个socket,你可以像任何IO对象一样从它读取。完成后,记得关闭它,就像关闭一个文件一样。
以下代码是一个非常简单的客户端,它连接到给定的主机和端口,从socket中读取任何可用的数据,然后当输入’q’时退出。
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()
- 首先运行服务器代码。它开始监听。
-
然后启动客户端代码。它发送请求。
-
请求已接受。客户端地址已确定
-
输入一些文本并按Enter键。
-
接收到的数据被打印出来。将数据发送给客户端。
-
接收到来自服务器的数据。
-
当输入’q’时,循环终止。
服务器-客户端交互如下所示−
我们在本地机器上使用socket模块实现了客户端和服务器之间的通信。要在网络上的两台不同机器上放置服务器和客户端代码,我们需要找到服务器机器的IP地址。
在Windows上,您可以通过运行ipconfig命令找到IP地址。在Ubuntu上,ifconfig命令是相应的命令。
在服务器和客户端代码中将主机字符串更改为IPv4地址值,并像以前一样运行它们。
使用Socket模块进行Python文件传输
以下程序演示了如何使用socket通信从服务器传输文件到客户端。
服务器代码
建立连接的代码与以前相同。在连接请求被接受后,服务器上的一个文件以二进制模式打开进行读取,然后逐个字节读取并发送到客户端流,直到文件结束。
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()
客户端代码
在客户端上,一个新文件以 wb 模式打开。从服务器接收到的数据流被写入文件中。当数据流结束时,输出文件被关闭。在客户端机器上将会创建一个新文件。
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')
Python的socketserver模块
Python标准库中的socketserver模块是一个简化编写网络服务器任务的框架。该模块中有以下表示同步服务器的类:
这些类与相应的RequestHandler类一起使用,用于实现服务。BaseServer是模块中所有Server对象的超类。
TCPServer 类使用互联网TCP协议,在客户端和服务器之间提供连续的数据流。构造函数自动尝试调用server_bind()和server_activate()。其他参数传递给BaseServer基类。
你还必须创建一个 StreamRequestHandler 类的子类。它提供了self.rfile和self.wfile属性,用于读取或写入请求数据或向客户端返回数据。
- UDPServer 和 DatagramRequestHandler - 这些类用于UDP协议。
-
DatagramRequestHandler 和 UnixDatagramServer - 这些类使用Unix域套接字,不适用于非Unix平台。
服务器代码
你必须编写一个RequestHandler类。它在与服务器的每个连接中实例化一次,并且必须覆盖handle()方法来实现与客户端的通信。
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()方法将服务器置于监听模式,并接受来自客户端的传入请求。
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever()
客户端代码
在使用socketserver时,客户端的代码与socket客户端应用程序基本上是类似的。
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))
在一个命令提示符终端中运行服务器代码。打开多个终端用于客户端实例。您可以模拟服务器和多个客户端之间的并发通信。
Server | Client-1 | Client-2 |
---|---|---|
D:\socketsrvr>python myserver.py127.0.0.1:54518 wrote:from client-1enter text ..hello 127.0.0.1:54522 wrote:how are youenter text ..fine 127.0.0.1:54523 wrote:from client-2enter text ..hi client-2 127.0.0.1:54526 wrote:good byeenter text ..bye bye 127.0.0.1:54530 wrote:thanksenter text ..bye client-2 |
D:\socketsrvr>python myclient.pyenter text .. .from client-1Sent:from client-1Received: helloenter text .. .how are youSent:how are youReceived: fineenter text .. .good byeSent: good byeReceived: bye byeenter text .. . | D:\socketsrvr>python myclient.pyenter text .. .from client-2Sent:from client-2Received: hi client-2enter text .. .thanksSent: thanksReceived:bye client-2enter text .. . |