程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Detailed explanation of Python TCP concurrent programming and code implementation - Taking the chat room implemented by Bio & NiO & AIO model as an example

編輯:Python

Python TCP Concurrent programming details and code implementation - With BIO&NIO&AIO Model implementation chat room as an example

  • 1.IO Overview of network programming
  • 2. Chat room scenario analysis
  • BIO principle , characteristic , Applicable scenario , Code implementation
  • NIO principle , characteristic , Applicable scenario , Code implementation
  • AIO principle , characteristic , Applicable scenario , Code implementation

1.IO Overview of network programming

Hello everyone , This time I will tell you about TCP Concurrent programming of the protocol , The boss arranged a task before , Realize the connection of multiple instruments to the server TCP Connect , And realize communication . Making programs run concurrently is a topic that is often discussed , Today, let's talk about the development of chat rooms Python TCP Various concurrent modes under communication .

We all know TCP Point to point communication , When a connection is established , Because you want to handle the read and write of this connection , The program will block , Other instruments cannot be connected , as follows :

First ServerSocket Will listen to a port on the server , When the client is found to have Socket To try to connect it , It will accept The Socket Connection request for , At the same time, a corresponding server is established on the server Socket Communicate with . So there are two Socket 了 , One client and one server ( It is also point-to-point communication ).

The principle of realizing multiple connections is actually the use of the server Multithreading 、 asynchronous And so on to solve the blocking link in the figure above , Then loop to listen for the connection request of the client , Instantiate one more for each request socket And the client socket Establish point-to-point communication . as follows

Development of multi person chat room , You need to understand first IO Programming , At the operating system level, first understand linux Systematic IO Model , as follows , Divided into blocking , Non blocking , asynchronous , Synchronization mode . IO The network programming of can be divided into BIO( Blocking IO),NIO( Non blocking IO),AIO( asynchronous IO) etc. , Their application scenarios are also different . Use the built-in components of the language to realize IO Network programming model to realize the connection between multiple clients and servers .
Here we will introduce several common implementations TCP Cases of multiple client connections and message forwarding , Take a simple multi person chat as an example .

——————————————————————————

2. Chat room scenario analysis

The server of multi person chat room , There are three blocking scenarios , Namely establish socket Connect 、 Client data read in and send data to the client , The first two scenarios need to constantly query the data of the operating system kernel buffer , So you need to poll constantly . as follows , This blocking statement needs to be executed in a loop .

  1. clientSocket, clientAddr = sock.accept() # Establishing a connection
  2. data = clientSocket.recv(1024) # Reading data

IO The network programming model provided a better method to solve these blocking problems , The following is an introduction .

BIO principle , characteristic , Applicable scenario , Code implementation

BIO: Synchronous blocking IO Network programming model

BIO The main thing is that a new thread is opened for each connection , Implement a simple , But waste of resources , It is suitable for less connections , Low development difficulty , Enough server resources .

  • characteristic : utilize The main thread keeps polling whether the client is connected , Then create a thread pool , utilize The sub thread handles data reading and writing .
  • advantage : Programming is simple , Easy to maintain , To achieve convenient .
  • shortcoming : Threads keep switching , waste cpu, You also need to consider thread locks ( Data is accessed by multiple threads ) The problem of .
  • The biggest drawback : The number of threads that the server can create is limited ** Of , Each time a thread server is established, a thread stack should be opened up (64k), When the connection reaches 10k The left and right servers are about to collapse , Cannot handle high concurrency .
  • Applicable scenario Fewer connections , Server resources are sufficient


There's another problem , At the operating system level , Although multithreading can solve the problem of connection blocking , But after the connection is established , If the current thread has no data to read temporarily , Still will Blocking in the operating system kernel cache read Operationally , Waiting for the data to arrive , The efficiency is not high .. Here's the picture , Red circles represent blocking . At the same time python Due to the use of global interpretation lock in (GIL) Why , Code cannot run concurrently on multiple cores at the same time , in other words Python Multiple threads of cannot be concurrent , Use multithreading to improve your own Python After code , The running efficiency of the program may decrease

#**very Simple client **
import socket
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSocket.connect(("127.0.0.1", 8001))
print(" Connected to server ")
clientSocket.send("hello".encode("UTF-8"))
while True:
#data = input(" Client sends data :").strip() It is recommended to open a thread to process input 
data = clientSocket.recv(1024)
print(data.decode())
clientSocket.close()
#BIO The server 
from socket import *
import threading
clientAddrList = []
def forwaMsg(socket,msg): # Realize the information forwarding function of the chat room 
for item in clientAddrList:
if item[0] != socket: # Forward to others socket
item[0].send(" The server forwarded you ".encode()+msg) #item[1] There is address information in it , You can also add 
def handle_request(conn,clientAddr): # Thread event handling 
recvData = conn.recv(1024)
if len(recvData) > 0:
print(" come from ",str(clientAddr)," Information about ",recvData)
print(threading.current_thread().getName() ) # When multiple clients are connected here , The output is different threads 
#TODO Message forwarding 
forwaMsg(clientSocket,recvData)
else:
conn.close()
clientAddrList.remove((conn, clientAddr))
print("%s It's offline " % str(clientAddr))
if __name__=='__main__':
# 1. Create a server socket
sock = socket(AF_INET, SOCK_STREAM)
# 2. Bind host and port 
addr = ('', 8001) #
sock.bind(addr)
# 3. Set the maximum number of listeners , Concurrent 
sock.listen(10)
while 1:
clientSocket, clientAddr = sock.accept() # It's new here socket For point-to-point communication with users 
print(" A new client is connected :%s" % str(clientAddr))
clientAddrList.append((clientSocket, clientAddr))
t1 = threading.Thread(target = handle_request, args = (clientSocket, clientAddr)) # Each additional client creates a thread 
t1.setDaemon(True) # Set thread guard 
t1.start()

The implementation of the server is relatively simple , From the execution results , You can see that two clients have established two sub threads ,MainThread Handle connection blocking .

NIO principle , characteristic , Applicable scenario , Code implementation

NIO: Synchronous nonblocking IO Network programming model

NIO There is no need to create threads , Set up multiple threads , Turned into Implement a single thread Manage multiple clients , Reduce congestion and resource consumption , High scalability , But when one of the connections is blocked ( Poor network ?) when , Will pull a hair and move the whole body .

  • characteristic : utilize multiplexer selector Handle +socket( Configure to non blocking mode ) Realization ,selector In more than one socket Between polling , You can process the data in any way .
  • Be careful :java Of socket Cannot be configured as non blocking , Use channel Instead of socket
  • advantage : Reduce congestion , Improve cpu Utilization efficiency , No thread switching is necessary , There is no need to consider locks . High efficiency can naturally achieve high concurrency
  • shortcoming : When a connection reads data , May also block , The whole situation has been delayed
  • Applicable scenario : There are many connections ,CPU Intensive data ( It refers to a small amount of data at a time , But it needs to be calculated on the server )

# coding:utf-8
from socket import *
# 1. Create a server socket
sock = socket(AF_INET, SOCK_STREAM)
# 2. Bind host and port 
addr = ('', 8001) #
sock.bind(addr)
# 3. Set the maximum number of listeners , Concurrent 
sock.listen(10)
# 4. Set to non blocking 
sock.setblocking(False)
print(' Non blocking server created ');
# Save client socket
clientAddrList = []
while 1:
try:
clientSocket, clientAddr = sock.accept()
print(" A new client is connected :%s" % str(clientAddr))
clientSocket.setblocking(False)
clientAddrList.append((clientSocket, clientAddr))
except BlockingIOError as e:
pass
for clientSocket, clientAddr in clientAddrList:
try:
recvData = clientSocket.recv(1024)
if len(recvData)>0:
print(" come from ",str(clientAddr)," Information about ",recvData)
import threading
print(threading.current_thread().getName() ) # When multiple clients are connected here , The output is MainThread
#TODO Forward the message It says 
else:
clientSocket.close()
clientAddrList.remove((clientSocket, clientAddr))
print("%s It's offline " % str(clientAddr))
except:
pass
# Another way of writing 
import socket
import select
from collections import deque
server = socket.socket()
server.setblocking(False) # Set to non blocking 
server.bind(("", 8001))
server.listen(5)
rlist = deque([server])
wlist = deque()
xlist = deque()
while True:
read_list, write_list, error_list = select.select(rlist, wlist, xlist)
for socket_item in read_list:
if socket_item == server:
conn, addr = socket_item.accept()
conn.setblocking(False) # Set to non blocking 
rlist.append(conn)
else:
print(socket_item.recv(1024).decode("utf-8"))
for write_item in write_list:
pass
for error_item in error_list:
error_item.close()
rlist.remove(error_item)

Execution results : You can see that the communication is also main In the thread

AIO principle , characteristic , Applicable scenario , Code implementation

AIO: Asynchronous non-blocking IO Network programming model

AIO, asynchronous , The main feature is that the application does not block and wait for data , requirement The operating system actively sends data to the application program

  • characteristic : The application reads the data Task submitted To the operating system , After the system gets the data, it will return to the application program ,socket Asynchronous call accept,read Such as function , And return a future object , according to future Status determines whether the task returns
  • advantage : Program execution is not blocked , Efficient
  • shortcoming : Not suitable for lightweight data transmission , Because every time the data preparation is completed , The operating system notifies the application , Frequent communication between processes is chasing errors 、 Management and resource consumption are very high , It is better to transmit long data .
  • Applicable scenario There are many connections , Long connection duration ,IO intensive

import socket
from concurrent.futures import ProcessPoolExecutor
class MyTcpServer:
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.server = socket.socket()
self.server.bind((self.ip, self.port))
self.server.listen(5) # maximum connection 
self.clientAddrList = []
def wait_accept(self):
conn, addr = self.server.accept()
return conn, addr
def handle_request(self, conn,addr):
while 1:
try:
recvData = conn.recv(1024)
if len(recvData) > 0:
print(" come from ",addr," Information about ",recvData)
import threading
print(threading.current_thread().getName() ) # When multiple clients are connected here , The output is MainThread
#TODO Forward a message 
except Exception as e:
print(e)
server.clientAddrList.remove((conn, addr))
break
conn.close()
if __name__ == '__main__':
server = MyTcpServer('127.0.0.1', 8001)
pool = ProcessPoolExecutor(5) # 5 Processes have been serving 
print(" The asynchronous server has been established ");
while 1:
conn, addr = server.wait_accept()
print(" client ",addr," Connected ")
server.clientAddrList.append((conn, addr))
pool.submit(server.handle_request, conn,addr) # Submit tasks asynchronously 


—————————————————————————————————

for instance , You go to the library to borrow books ,

  • BIO You've been waiting in the library since the book was borrowed , Until someone returns the book ( first-class 30 God ?)
  • NIO It is equivalent to seeing it once a day .
  • AIO It is equivalent to the books being returned. The administrator sends the books to the door of your dormitory .
  • There is also a multiplexing IO, When the book arrives, the administrator contacts you but lets you pick it up by yourself .

meanwhile Python It also supports the use of processes to achieve concurrency , Due to the problem of global interpretation lock mentioned earlier ,Python To use effectively CPU A better way to use parallel resources is to use multiple processes , And achieve real concurrency . Of course , The process does not share memory , It costs more than threads , For computing intensive tasks , It is appropriate to use multi process concurrency , For example, for the algorithm processing after the instrument data is transmitted , Execution efficiency : Multi process > Single thread > Multithreading .

Attach multi process code , Generally develop chat rooms or web The server does not require multiple processes .

from multiprocessing import Process
def worker():
print 'Worker'
p = Process(target=worker)
p.start()
p.join(

Your praise is my biggest motivation to update ~


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved