Python学习笔记_基础篇(十)_socket编程

本章内容

1、socket

2、IO多路复用

3、socketserver

Socket

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

基本上,Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入 http://www.cnblogs.com/ 时,你会打开一个套接字,然后连接到 http://www.cnblogs.com/ 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如 gtalk 和 skype 也是类似。任何网络通讯都是通过 Socket 来完成的。

Python 官方关于 Socket 的函数请看 http://docs.python.org/library/socket.html

socket和file的区别:

1、file模块是针对某个指定文件进行【打开】【读写】【关闭】

2、socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

那我们就先来创建一个socket服务端吧

import socketsk = socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen(5)conn,address = sk.accept()
sk.sendall(bytes("Hello world",encoding="utf-8"))

server

import socketobj = socket.socket()
obj.connect(("127.0.0.1",8080))ret = str(obj.recv(1024),encoding="utf-8")
print(ret)

View Code

socket更多功能

     def bind(self, address): # real signature unknown; restored from __doc__"""bind(address)Bind the socket to a local address.  For IP sockets, the address is apair (host, port); the host must refer to the local host. For raw packetsockets the address is a tuple (ifname, proto [,pkttype [,hatype]])"""
'''将套接字绑定到本地地址。是一个IP套接字的地址对(主机、端口),主机必须参考本地主机。'''passdef close(self): # real signature unknown; restored from __doc__"""close()Close the socket.  It cannot be used after this call."""'''关闭socket'''passdef connect(self, address): # real signature unknown; restored from __doc__"""connect(address)Connect the socket to a remote address.  For IP sockets, the addressis a pair (host, port)."""'''将套接字连接到远程地址。IP套接字的地址'''passdef connect_ex(self, address): # real signature unknown; restored from __doc__"""connect_ex(address) -> errnoThis is like connect(address), but returns an error code (the errno value)instead of raising an exception when an error occurs."""passdef detach(self): # real signature unknown; restored from __doc__"""detach()Close the socket object without closing the underlying file descriptor.The object cannot be used after this call, but the file descriptorcan be reused for other purposes.  The file descriptor is returned."""
'''关闭套接字对象没有关闭底层的文件描述符。'''passdef fileno(self): # real signature unknown; restored from __doc__"""fileno() -> integerReturn the integer file descriptor of the socket."""'''返回整数的套接字的文件描述符。'''return 0def getpeername(self): # real signature unknown; restored from __doc__"""getpeername() -> address infoReturn the address of the remote endpoint.  For IP sockets, the addressinfo is a pair (hostaddr, port)."""'''返回远程端点的地址。IP套接字的地址'''passdef getsockname(self): # real signature unknown; restored from __doc__"""getsockname() -> address infoReturn the address of the local endpoint.  For IP sockets, the addressinfo is a pair (hostaddr, port)."""'''返回远程端点的地址。IP套接字的地址'''passdef getsockopt(self, level, option, buffersize=None): # real signature unknown; restored from __doc__"""getsockopt(level, option[, buffersize]) -> valueGet a socket option.  See the Unix manual for level and option.If a nonzero buffersize argument is given, the return value is astring of that length; otherwise it is an integer."""'''得到一个套接字选项'''passdef gettimeout(self): # real signature unknown; restored from __doc__"""gettimeout() -> timeoutReturns the timeout in seconds (float) associated with socket operations. A timeout of None indicates that timeouts on socket operations are disabled."""'''返回的超时秒数(浮动)与套接字相关联'''return timeoutdef ioctl(self, cmd, option): # real signature unknown; restored from __doc__"""ioctl(cmd, option) -> longControl the socket with WSAIoctl syscall. Currently supported 'cmd' values areSIO_RCVALL:  'option' must be one of the socket.RCVALL_* constants.SIO_KEEPALIVE_VALS:  'option' is a tuple of (onoff, timeout, interval)."""return 0def listen(self, backlog=None): # real signature unknown; restored from __doc__"""listen([backlog])Enable a server to accept connections.  If backlog is specified, it must beat least 0 (if it is lower, it is set to 0); it specifies the number ofunaccepted connections that the system will allow before refusing newconnections. If not specified, a default reasonable value is chosen."""'''使服务器能够接受连接。'''passdef recv(self, buffersize, flags=None): # real signature unknown; restored from __doc__"""recv(buffersize[, flags]) -> dataReceive up to buffersize bytes from the socket.  For the optional flagsargument, see the Unix manual.  When no data is available, block untilat least one byte is available or until the remote end is closed.  Whenthe remote end is closed and all data is read, return the empty string."""
'''当没有数据可用,阻塞,直到至少一个字节是可用的或远程结束之前关闭。'''passdef recvfrom(self, buffersize, flags=None): # real signature unknown; restored from __doc__"""recvfrom(buffersize[, flags]) -> (data, address info)Like recv(buffersize, flags) but also return the sender's address info."""passdef recvfrom_into(self, buffer, nbytes=None, flags=None): # real signature unknown; restored from __doc__"""recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info."""passdef recv_into(self, buffer, nbytes=None, flags=None): # real signature unknown; restored from __doc__"""recv_into(buffer, [nbytes[, flags]]) -> nbytes_readA version of recv() that stores its data into a buffer rather than creating a new string.  Receive up to buffersize bytes from the socket.  If buffersize is not specified (or 0), receive up to the size available in the given buffer.See recv() for documentation about the flags."""passdef send(self, data, flags=None): # real signature unknown; restored from __doc__"""send(data[, flags]) -> countSend a data string to the socket.  For the optional flagsargument, see the Unix manual.  Return the number of bytessent; this may be less than len(data) if the network is busy."""'''发送一个数据字符串到套接字。'''passdef sendall(self, data, flags=None): # real signature unknown; restored from __doc__"""sendall(data[, flags])Send a data string to the socket.  For the optional flagsargument, see the Unix manual.  This calls send() repeatedlyuntil all data is sent.  If an error occurs, it's impossibleto tell how much data has been sent."""'''发送一个数据字符串到套接字,直到所有数据发送完成'''passdef sendto(self, data, flags=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__ """sendto(data[, flags], address) -> countLike send(data, flags) but allows specifying the destination address.For IP sockets, the address is a pair (hostaddr, port)."""passdef setblocking(self, flag): # real signature unknown; restored from __doc__"""setblocking(flag)Set the socket to blocking (flag is true) or non-blocking (false).setblocking(True) is equivalent to settimeout(None);setblocking(False) is equivalent to settimeout(0.0)."""
'''是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。'''passdef setsockopt(self, level, option, value): # real signature unknown; restored from __doc__"""setsockopt(level, option, value)Set a socket option.  See the Unix manual for level and option.The value argument can either be an integer or a string."""passdef settimeout(self, timeout): # real signature unknown; restored from __doc__"""settimeout(timeout)Set a timeout on socket operations.  'timeout' can be a float,giving in seconds, or None.  Setting a timeout of None disablesthe timeout feature and is equivalent to setblocking(1).Setting a timeout of zero is the same as setblocking(0)."""passdef share(self, process_id): # real signature unknown; restored from __doc__"""share(process_id) -> bytesShare the socket with another process.  The target process idmust be provided and the resulting bytes object passed to the targetprocess.  There the shared socket can be instantiated by callingsocket.fromshare()."""return b""def shutdown(self, flag): # real signature unknown; restored from __doc__"""shutdown(flag)Shut down the reading side of the socket (flag == SHUT_RD), the writing sideof the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR)."""passdef _accept(self): # real signature unknown; restored from __doc__"""_accept() -> (integer, address info)Wait for an incoming connection.  Return a new socket file descriptorrepresenting the connection, and the address of the client.For IP sockets, the address info is a pair (hostaddr, port)."""pass

更多功能

注:撸主知道大家懒,所以把全部功能的中文标记在每个功能的下面啦。下面撸主列一些经常用到的吧

sk.bind(address)

s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。

backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)

连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close()

关闭套接字

sk.recv(bufsize[,flag])

接受套接字的数据。数据以字符串形式返回,bufsize指定 最多 可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag])

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout)

设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()

返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()

套接字的文件描述符

TCP:

import  socketserver
服务端class Myserver(socketserver.BaseRequestHandler):def handle(self):conn = self.requestconn.sendall(bytes("你好,我是机器人",encoding="utf-8"))while True:ret_bytes = conn.recv(1024)ret_str = str(ret_bytes,encoding="utf-8")if ret_str == "q":breakconn.sendall(bytes(ret_str+"你好我好大家好",encoding="utf-8"))if __name__ == "__main__":server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Myserver)server.serve_forever()客户端import socketobj = socket.socket()obj.connect(("127.0.0.1",8080))ret_bytes = obj.recv(1024)
ret_str = str(ret_bytes,encoding="utf-8")
print(ret_str)while True:inp = input("你好请问您有什么问题? \n >>>")if inp == "q":obj.sendall(bytes(inp,encoding="utf-8"))breakelse:obj.sendall(bytes(inp, encoding="utf-8"))ret_bytes = obj.recv(1024)ret_str = str(ret_bytes,encoding="utf-8")print(ret_str)

案例一 机器人聊天

服务端import socketsk = socket.socket()sk.bind(("127.0.0.1",8080))
sk.listen(5)while True:conn,address = sk.accept()conn.sendall(bytes("欢迎光临我爱我家",encoding="utf-8"))size = conn.recv(1024)size_str = str(size,encoding="utf-8")file_size = int(size_str)conn.sendall(bytes("开始传送", encoding="utf-8"))has_size = 0f = open("db_new.jpg","wb")while True:if file_size == has_size:breakdate = conn.recv(1024)f.write(date)has_size += len(date)f.close()客户端import socket
import osobj = socket.socket()obj.connect(("127.0.0.1",8080))ret_bytes = obj.recv(1024)
ret_str = str(ret_bytes,encoding="utf-8")
print(ret_str)size = os.stat("yan.jpg").st_size
obj.sendall(bytes(str(size),encoding="utf-8"))obj.recv(1024)with open("yan.jpg","rb") as f:for line in f:obj.sendall(line)

案例二 上传文件

UdP

import socket
ip_port = ('127.0.0.1',9999)
sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
sk.bind(ip_port)while True:data = sk.recv(1024)print dataimport socket
ip_port = ('127.0.0.1',9999)sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
while True:inp = input('数据:').strip()if inp == 'exit':breaksk.sendto(bytes(inp,encoding = "utf-8"),ip_port)sk.close()

udp传输

WEB服务应用:

#!/usr/bin/env python
#coding:utf-8
import socketdef handle_request(client):buf = client.recv(1024)client.send("HTTP/1.1 200 OK\r\n\r\n")client.send("Hello, World")def main():sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.bind(('localhost',8080))sock.listen(5)while True:connection, address = sock.accept()handle_request(connection)connection.close()if __name__ == '__main__':main()

IO多路复用

I/O(input/output),即输入/输出端口。每个设备都会有一个专用的I/O地址,用来处理自己的输入输出信息 首先什么是I/O:

I/O分为磁盘io和网络io,这里说的是网络io

IO多路复用:

I/O多路复用指:通过一种机制,可以监视多个描述符(socket),一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

Linux

Linux中的 select,poll,epoll 都是IO多路复用的机制。

Linux下网络I/O使用socket套接字来通信,普通I/O模型只能监听一个socket,而I/O多路复用可同时监听多个socket.

I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理.

Python

Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

Windows Python:提供: selectMac Python:提供: selectLinux Python:提供: select、poll、epoll

对于select模块操作的方法:

句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)参数: 可接受四个参数(前三个必须)
返回值:三个列表select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
5、当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

import socket
import selectsk1 = socket.socket()
sk1.bind(("127.0.0.1",8001))
sk1.listen()sk2 = socket.socket()
sk2.bind(("127.0.0.1",8002))
sk2.listen()sk3 = socket.socket()
sk3.bind(("127.0.0.1",8003))
sk3.listen()li = [sk1,sk2,sk3]while True:r_list,w_list,e_list = select.select(li,[],[],1) # r_list可变化的for line in r_list: conn,address = line.accept()conn.sendall(bytes("Hello World !",encoding="utf-8"))

利用select监听终端操作实例

服务端:
sk1 = socket.socket()
sk1.bind(("127.0.0.1",8001))
sk1.listen()inpu = [sk1,]while True:r_list,w_list,e_list = select.select(inpu,[],[],1)for sk in r_list:if sk == sk1:conn,address = sk.accept()inpu.append(conn)else:try:ret = str(sk.recv(1024),encoding="utf-8")sk.sendall(bytes(ret+"hao",encoding="utf-8"))except Exception as ex:inpu.remove(sk)客户端
import socketobj = socket.socket()obj.connect(('127.0.0.1',8001))while True:inp = input("Please(q\退出):\n>>>")obj.sendall(bytes(inp,encoding="utf-8"))if inp == "q":breakret = str(obj.recv(1024),encoding="utf-8")print(ret)

利用select实现伪同时处理多个Socket客户端请求

服务端:
import socket
sk1 = socket.socket()
sk1.bind(("127.0.0.1",8001))
sk1.listen()
inputs = [sk1]
import select
message_dic = {}
outputs = []
while True:r_list, w_list, e_list = select.select(inputs,[],inputs,1)print("正在监听的socket对象%d" % len(inputs))print(r_list)for sk1_or_conn in r_list:if sk1_or_conn == sk1:conn,address = sk1_or_conn.accept()inputs.append(conn)message_dic[conn] = []else:try:data_bytes = sk1_or_conn.recv(1024)data_str = str(data_bytes,encoding="utf-8")sk1_or_conn.sendall(bytes(data_str+"好",encoding="utf-8"))except Exception as ex:inputs.remove(sk1_or_conn)else:data_str = str(data_bytes,encoding="utf-8")message_dic[sk1_or_conn].append(data_str)outputs.append(sk1_or_conn)for conn in w_list:recv_str = message_dic[conn][0]del message_dic[conn][0]conn.sendall(bytes(recv_str+"好",encoding="utf-8"))for sk in e_list:inputs.remove(sk)客户端:
import socketobj = socket.socket()obj.connect(('127.0.0.1',8001))while True:inp = input("Please(q\退出):\n>>>")obj.sendall(bytes(inp,encoding="utf-8"))if inp == "q":breakret = str(obj.recv(1024),encoding="utf-8")print(ret)

利用select实现伪同时处理多个Socket客户端请求读写分离

socketserver

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “ 线程 ”,该线程用来和客户端进行交互。

1、ThreadingTCPServer基础

使用ThreadingTCPServer:

  • 创建一个继承自 SocketServer.BaseRequestHandler 的类
  • 类中必须定义一个名称为 handle 的方法
  • 启动ThreadingTCPServer

import  socketserverclass Myserver(socketserver.BaseRequestHandler):def handle(self):conn = self.requestconn.sendall(bytes("你好,我是机器人",encoding="utf-8"))while True:ret_bytes = conn.recv(1024)ret_str = str(ret_bytes,encoding="utf-8")if ret_str == "q":breakconn.sendall(bytes(ret_str+"你好我好大家好",encoding="utf-8"))if __name__ == "__main__":server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),Myserver)server.serve_forever()

服务端

import socketobj = socket.socket()obj.connect(("127.0.0.1",8080))ret_bytes = obj.recv(1024)
ret_str = str(ret_bytes,encoding="utf-8")
print(ret_str)while True:inp = input("你好请问您有什么问题? \n >>>")if inp == "q":obj.sendall(bytes(inp,encoding="utf-8"))breakelse:obj.sendall(bytes(inp, encoding="utf-8"))ret_bytes = obj.recv(1024)ret_str = str(ret_bytes,encoding="utf-8")print(ret_str)

客户端

2、ThreadingTCPServer源码剖析

ThreadingTCPServer的类图关系如下:

内部调用流程为:

  • 启动服务端程序
  • 执行 TCPServer.init 方法,创建服务端Socket对象并绑定 IP 和 端口
  • 执行 BaseServer.init 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
  • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 …
  • 当客户端连接到达服务器
  • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
  • 执行 ThreadingMixIn.process_request_thread 方法
  • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

相对应的源码如下:

class BaseServer:"""Base class for server classes.Methods for the caller:- __init__(server_address, RequestHandlerClass)- serve_forever(poll_interval=0.5)- shutdown()- handle_request()  # if you do not use serve_forever()- fileno() -> int   # for select()Methods that may be overridden:- server_bind()- server_activate()- get_request() -> request, client_address- handle_timeout()- verify_request(request, client_address)- server_close()- process_request(request, client_address)- shutdown_request(request)- close_request(request)- handle_error()Methods for derived classes:- finish_request(request, client_address)Class variables that may be overridden by derived classes orinstances:- timeout- address_family- socket_type- allow_reuse_addressInstance variables:- RequestHandlerClass- socket"""timeout = Nonedef __init__(self, server_address, RequestHandlerClass):"""Constructor.  May be extended, do not override."""self.server_address = server_addressself.RequestHandlerClass = RequestHandlerClassself.__is_shut_down = threading.Event()self.__shutdown_request = Falsedef server_activate(self):"""Called by constructor to activate the server.May be overridden."""passdef serve_forever(self, poll_interval=0.5):"""Handle one request at a time until shutdown.Polls for shutdown every poll_interval seconds. Ignoresself.timeout. If you need to do periodic tasks, do them inanother thread."""self.__is_shut_down.clear()try:while not self.__shutdown_request:# XXX: Consider using another file descriptor or# connecting to the socket to wake this up instead of# polling. Polling reduces our responsiveness to a# shutdown request and wastes cpu at all other times.r, w, e = _eintr_retry(select.select, [self], [], [],poll_interval)if self in r:self._handle_request_noblock()finally:self.__shutdown_request = Falseself.__is_shut_down.set()def shutdown(self):"""Stops the serve_forever loop.Blocks until the loop has finished. This must be called whileserve_forever() is running in another thread, or it willdeadlock."""self.__shutdown_request = Trueself.__is_shut_down.wait()# The distinction between handling, getting, processing and# finishing a request is fairly arbitrary.  Remember:## - handle_request() is the top-level call.  It calls#   select, get_request(), verify_request() and process_request()# - get_request() is different for stream or datagram sockets# - process_request() is the place that may fork a new process#   or create a new thread to finish the request# - finish_request() instantiates the request handler class;#   this constructor will handle the request all by itselfdef handle_request(self):"""Handle one request, possibly blocking.Respects self.timeout."""# Support people who used socket.settimeout() to escape# handle_request before self.timeout was available.timeout = self.socket.gettimeout()if timeout is None:timeout = self.timeoutelif self.timeout is not None:timeout = min(timeout, self.timeout)fd_sets = _eintr_retry(select.select, [self], [], [], timeout)if not fd_sets[0]:self.handle_timeout()returnself._handle_request_noblock()def _handle_request_noblock(self):"""Handle one request, without blocking.I assume that select.select has returned that the socket isreadable before this function was called, so there should beno risk of blocking in get_request()."""try:request, client_address = self.get_request()except socket.error:returnif self.verify_request(request, client_address):try:self.process_request(request, client_address)except:self.handle_error(request, client_address)self.shutdown_request(request)def handle_timeout(self):"""Called if no new request arrives within self.timeout.Overridden by ForkingMixIn."""passdef verify_request(self, request, client_address):"""Verify the request.  May be overridden.Return True if we should proceed with this request."""return Truedef process_request(self, request, client_address):"""Call finish_request.Overridden by ForkingMixIn and ThreadingMixIn."""self.finish_request(request, client_address)self.shutdown_request(request)def server_close(self):"""Called to clean-up the server.May be overridden."""passdef finish_request(self, request, client_address):"""Finish one request by instantiating RequestHandlerClass."""self.RequestHandlerClass(request, client_address, self)def shutdown_request(self, request):"""Called to shutdown and close an individual request."""self.close_request(request)def close_request(self, request):"""Called to clean up an individual request."""passdef handle_error(self, request, client_address):"""Handle an error gracefully.  May be overridden.The default is to print a traceback and continue."""print '-'*40print 'Exception happened during processing of request from',print client_addressimport tracebacktraceback.print_exc() # XXX But this goes to stderr!print '-'*40

Baseserver

class TCPServer(BaseServer):"""Base class for various socket-based server classes.Defaults to synchronous IP stream (i.e., TCP).Methods for the caller:- __init__(server_address, RequestHandlerClass, bind_and_activate=True)- serve_forever(poll_interval=0.5)- shutdown()- handle_request()  # if you don't use serve_forever()- fileno() -> int   # for select()Methods that may be overridden:- server_bind()- server_activate()- get_request() -> request, client_address- handle_timeout()- verify_request(request, client_address)- process_request(request, client_address)- shutdown_request(request)- close_request(request)- handle_error()Methods for derived classes:- finish_request(request, client_address)Class variables that may be overridden by derived classes orinstances:- timeout- address_family- socket_type- request_queue_size (only for stream sockets)- allow_reuse_addressInstance variables:- server_address- RequestHandlerClass- socket"""address_family = socket.AF_INETsocket_type = socket.SOCK_STREAMrequest_queue_size = 5allow_reuse_address = Falsedef __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):"""Constructor.  May be extended, do not override."""BaseServer.__init__(self, server_address, RequestHandlerClass)self.socket = socket.socket(self.address_family,self.socket_type)if bind_and_activate:try:self.server_bind()self.server_activate()except:self.server_close()raisedef server_bind(self):"""Called by constructor to bind the socket.May be overridden."""if self.allow_reuse_address:self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.socket.bind(self.server_address)self.server_address = self.socket.getsockname()def server_activate(self):"""Called by constructor to activate the server.May be overridden."""self.socket.listen(self.request_queue_size)def server_close(self):"""Called to clean-up the server.May be overridden."""self.socket.close()def fileno(self):"""Return socket file number.Interface required by select()."""return self.socket.fileno()def get_request(self):"""Get the request and client address from the socket.May be overridden."""return self.socket.accept()def shutdown_request(self, request):"""Called to shutdown and close an individual request."""try:#explicitly shutdown.  socket.close() merely releases#the socket and waits for GC to perform the actual close.request.shutdown(socket.SHUT_WR)except socket.error:pass #some platforms may raise ENOTCONN hereself.close_request(request)def close_request(self, request):"""Called to clean up an individual request."""request.close()

TCP server

class ThreadingMixIn:"""Mix-in class to handle each request in a new thread."""# Decides how threads will act upon termination of the# main processdaemon_threads = Falsedef process_request_thread(self, request, client_address):"""Same as in BaseServer but as a thread.In addition, exception handling is done here."""try:self.finish_request(request, client_address)self.shutdown_request(request)except:self.handle_error(request, client_address)self.shutdown_request(request)def process_request(self, request, client_address):"""Start a new thread to process the request."""t = threading.Thread(target = self.process_request_thread,args = (request, client_address))t.daemon = self.daemon_threadst.start()

ThreadingMixIn

class BaseRequestHandler:"""Base class for request handler classes.This class is instantiated for each request to be handled.  Theconstructor sets the instance variables request, client_addressand server, and then calls the handle() method.  To implement aspecific service, all you need to do is to derive a class whichdefines a handle() method.The handle() method can find the request as self.request, theclient address as self.client_address, and the server (in case itneeds access to per-server information) as self.server.  Since aseparate instance is created for each request, the handle() methodcan define arbitrary other instance variariables."""def __init__(self, request, client_address, server):self.request = requestself.client_address = client_addressself.server = serverself.setup()try:self.handle()finally:self.finish()def setup(self):passdef handle(self):passdef finish(self):pass

SocketServer.BaseRequestHandler

SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 selectThreading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/39955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux安装Docker

一、Docker系统版本介绍 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 或 Windows 操作系统的机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相…

诚迈科技荣膺小米“最佳供应商奖”

近日,诚迈科技受邀参加小米战略合作伙伴HBR总结会。诚迈科技以尽职尽责的合作态度、精益求精的交付质量荣膺小米公司颁发的最佳供应商奖,其性能测试团队荣获优秀团队奖。 诚迈科技与小米在手机终端方向一直保持着密切的合作关系,涉及系统框架…

【Java基础】Java对象的生命周期

【Java基础】Java对象的生命周期 一、概述 一个类通过编译器将一个Java文件编译为Class字节码文件,然后通过JVM中的解释器编译成不同操作系统的机器码。虽然操作系统不同,但是基于解释器的虚拟机是相同的。java类的生命周期就是指一个class文件加载到类…

python控制obs实现无缝切换场景!obs-websocket-py

前言 最近一直在研究孪生数字人wav2lip。目前成果可直接输入高清嘴型,2070显卡1分钟音频2.6分钟输出。在直播逻辑上可以做到1比1.3这样,所以现在开始研究直播。在逻辑上涉及到了无缝切换,看到csdn上有一篇文章还要vip解锁。。。那自己研究吧…

尚硅谷MySQL笔记 3-9

我不会记录的特别详细 大体框架 基本的Select语句运算符排序与分页多表查询单行函数聚合函数子查询 第三章 基本的SELECT语句 SQL分类 这个分类有很多种,大致了解下即可 DDL(Data Definition Languages、数据定义语言),定义了…

项目难点:解决IOS调用起软键盘之后页面样式布局错乱问题

需求背景 : 开发了一个问卷系统重构项目,刚开始开发的为 PC 端,其中最头疼的一点无非就是 IE 浏览器的兼容适配性问题; 再之后项目经理要求开发移动端,简单的说就是写 H5 页面,到时候会内嵌在 App 应用、办…

multiple definition of......first defined here

一、背景 环境: 银河麒麟–ARM–GCC7.4.0 写了一个动态库,依赖opencv和freeImage等第三方库,用cmake进行编译。原本在centos6-x86-gcc7.5.0上面进行编译非常的顺利,但是拿到麒麟arm上面编译就提示了这个错误:这个报错…

Ruby软件外包开发语言特点

Ruby 是一种动态、开放源代码的编程语言,它注重简洁性和开发人员的幸福感。在许多方面都具有优点,但由于其动态类型和解释执行的特性,它可能不适合某些对性能和类型安全性要求较高的场景。下面和大家分享 Ruby 语言的一些主要特点以及适用的场…

【C语言】动态通讯录 -- 详解

⚪前言 前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客,但是静态版通讯录的空间是无法被改变的,而且空间利用率也不高。为了解决静态通讯录这一缺点,这时就要有一个能够随着存入联系人数量的增加而增大…

Ansys Zemax | 手机镜头设计 - 第 1 部分:光学设计

本文是 3 篇系列文章的一部分,该系列文章将讨论智能手机镜头模组设计的挑战,从概念、设计到制造和结构变形的分析。本文是三部分系列的第一部分,将专注于OpticStudio中镜头模组的设计、分析和可制造性评估。(联系我们获取文章附件…

安防监控视频云存储平台EasyNVR通道频繁离线的原因排查与解决

安防视频监控汇聚EasyNVR视频集中存储平台,是基于RTSP/Onvif协议的安防视频平台,可支持将接入的视频流进行全平台、全终端分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。为了满足用户的集成与二次开发需求&#xf…

企业计算机服务器遭到了locked勒索病毒攻击如何解决,勒索病毒解密

网络技术的不断发展,也为网络安全埋下了隐患,近期,我们收到很多企业的求助,企业的计算机服务器遭到了locked勒索病毒的攻击,导致企业的财务系统内的所有数据被加密无法读取,严重影响了企业的正常运行。最近…

如何通过观测云的RUM找到前端加载的瓶颈--可观测性入门篇

声明与保证 本文写作于2023年6月,性能优化的评价标准和优化方式仅适用于当前观测云控制台,当然随着产品迭代及技术更新,本文也会应要求适当更新。 创建、修订时间创建修改人版本2023/6/24观测云***v1.0.0 1.网站性能评价的发展史&#xff…

打开vim的语法高亮

在一个Ubuntu中自带的vim版本是8.2.4919,默认就是开始了语法高亮的,打开一个Java文件效果如下: 它不仅仅对Java文件有语法高亮,对很多的文件都有,比如vim的配置文件也有语法高亮,有语法高亮时读起来会容易…

DNNGP模型解读-early stopping 和 batch normalization的使用

一、考虑的因素(仅代表个人观点) 1.首先我们看到他的这篇文章所考虑的不同方面从而做出的不同改进,首先考虑到了对于基因组预测的深度学习方法的设计 ,我们设计出来这个方法就是为了基因组预测而使用,这也是主要目的&…

排序算法-冒泡排序(C语言实现)

简介😀 冒泡排序是一种简单但效率较低的排序算法。它重复地扫描待排序元素列表,比较相邻的两个元素,并将顺序错误的元素交换位置,直到整个列表排序完成。 实现🧐 以下内容为本人原创,经过自己整理得出&am…

WAVE SUMMIT2023六大分会场同步开启,飞桨+文心大模型加速区域产业智能化!

由深度学习技术及应用国家工程研究中心主办、百度飞桨和文心大模型承办的WAVE SUMMIT深度学习开发者大会2023将于8月16日重磅来袭!届时上海、广州、深圳、成都、南昌和宁波六大分会场将同步开启! 分会汇聚区域产业大咖、科研机构专家、知名学者和技术大…

【C++ 学习 ⑬】- 详解 list 容器

目录 一、list 容器的基本介绍 二、list 容器的成员函数 2.1 - 迭代器 2.2 - 修改操作 三、list 的模拟实现 3.1 - list.h 3.2 - 详解 list 容器的迭代器 3.2 - test.cpp 一、list 容器的基本介绍 list 容器以类模板 list<T>&#xff08;T 为存储元素的类型&…

【第二阶段】kotlin函数引用

针对上篇传入函数参数我们也可以重新定义一个函数&#xff0c;然后在main中调用时传入函数对象 lambda属于函数类型的对象&#xff0c;需要把普通函数变成函数类型的对象&#xff08;函数引用&#xff09;&#xff0c;使用“&#xff1a;&#xff1a;” /*** You can edit, ru…

DRF 缓存

应用环境 django4.2.3 &#xff0c;python3.10 由于对于服务而言&#xff0c;有些数据查询起来比较费时&#xff0c;所以&#xff0c;对于有些数据&#xff0c;我们需要将其缓存。 最近做了一个服务&#xff0c;用的时 DRF 的架构&#xff0c;刚好涉及缓存&#xff0c;特此记…