wsgiref分析
- """Generic socket server classes.
- This module tries to capture the various aspects of defining a server:
- For socket-based servers:
- - address family:
- - AF_INET{,6}: IP (Internet Protocol) sockets (default)
- - AF_UNIX: Unix domain sockets
- - others, e.g. AF_DECNET are conceivable (see <socket.h>
- - socket type:
- - SOCK_STREAM (reliable stream, e.g. TCP)
- - SOCK_DGRAM (datagrams, e.g. UDP)
- For request-based servers (including socket-based):
- - client address verification before further looking at the request
- (This is actually a hook for any processing that needs to look
- at the request before anything else, e.g. logging)
- - how to handle multiple requests:
- - synchronous (one request is handled at a time)
- - forking (each request is handled by a new process)
- - threading (each request is handled by a new thread)
- The classes in this module favor the server type that is simplest to
- write: a synchronous TCP/IP server. This is bad class design, but
- save some typing. (There's also the issue that a deep class hierarchy
- slows down method lookups.)
- There are five classes in an inheritance diagram, four of which represent
- synchronous servers of four types:
- +------------+
- | BaseServer |
- +------------+
- |
- v
- +-----------+ +------------------+
- | TCPServer |------->| UnixStreamServer |
- +-----------+ +------------------+
- |
- v
- +-----------+ +--------------------+
- | UDPServer |------->| UnixDatagramServer |
- +-----------+ +--------------------+
- Note that UnixDatagramServer derives from UDPServer, not from
- UnixStreamServer -- the only difference between an IP and a Unix
- stream server is the address family, which is simply repeated in both
- unix server classes.
- Forking and threading versions of each type of server can be created
- using the ForkingMixIn and ThreadingMixIn mix-in classes. For
- instance, a threading UDP server class is created as follows:
- class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
- The Mix-in class must come first, since it overrides a method defined
- in UDPServer! Setting the various member variables also changes
- the behavior of the underlying server mechanism.
- To implement a service, you must derive a class from
- BaseRequestHandler and redefine its handle() method. You can then run
- various versions of the service by combining one of the server classes
- with your request handler class.
- The request handler class must be different for datagram or stream
- services. This can be hidden by using the request handler
- subclasses StreamRequestHandler or DatagramRequestHandler.
- Of course, you still have to use your head!
- For instance, it makes no sense to use a forking server if the service
- contains state in memory that can be modified by requests (since the
- modifications in the child process would never reach the initial state
- kept in the parent process and passed to each child). In this case,
- you can use a threading server, but you will probably have to use
- locks to avoid two requests that come in nearly simultaneous to apply
- conflicting changes to the server state.
- On the other hand, if you are building e.g. an HTTP server, where all
- data is stored externally (e.g. in the file system), a synchronous
- class will essentially render the service "deaf" while one request is
- being handled -- which may be for a very long time if a client is slow
- to read all the data it has requested. Here a threading or forking
- server is appropriate.
- In some cases, it may be appropriate to process part of a request
- synchronously, but to finish processing in a forked child depending on
- the request data. This can be implemented by using a synchronous
- server and doing an explicit fork in the request handler class
- handle() method.
- Another approach to handling multiple simultaneous requests in an
- environment that supports neither threads nor fork (or where these are
- too expensive or inappropriate for the service) is to maintain an
- explicit table of partially finished requests and to use select() to
- decide which request to work on next (or whether to handle a new
- incoming request). This is particularly important for stream services
- where each client can potentially be connected for a long time (if
- threads or subprocesses cannot be used).
- Future work:
- - Standard classes for Sun RPC (which uses either UDP or TCP)
- - Standard mix-in classes to implement various authentication
- and encryption schemes
- - Standard framework for select-based multiplexing
- XXX Open problems:
- - What to do with out-of-band data?
- BaseServer:
- - split generic "request" functionality out into BaseServer class.
- Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>
- example: read entries from a SQL database (requires overriding
- get_request() to return a table entry from the database).
- entry is processed by a RequestHandlerClass.
- """
- # Author of the BaseServer patch: Luke Kenneth Casson Leighton
- # XXX Warning!
- # There is a test suite for this module, but it cannot be run by the
- # standard regression test.
- # To run it manually, run Lib/test/test_socketserver.py.
- __version__ = "0.4"
- import socket
- import select
- import sys
- import os
- import errno
- try:
- import threading
- except ImportError:
- import dummy_threading as threading
- __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
- "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
- "StreamRequestHandler","DatagramRequestHandler",
- "ThreadingMixIn", "ForkingMixIn"]
- if hasattr(socket, "AF_UNIX"):
- __all__.extend(["UnixStreamServer","UnixDatagramServer",
- "ThreadingUnixStreamServer",
- "ThreadingUnixDatagramServer"])
- def _eintr_retry(func, *args):
- """restart a system call interrupted by EINTR"""
- while True:
- try:
- return func(*args)
- except (OSError, select.error) as e:
- if e.args[0] != errno.EINTR:
- raise
- 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 or
- instances:
- - timeout
- - address_family
- - socket_type
- - allow_reuse_address
- Instance variables:
- - RequestHandlerClass
- - socket
- """
- timeout = None
- def __init__(self, server_address, RequestHandlerClass):
- """Constructor. May be extended, do not override."""
- self.server_address = server_address
- self.RequestHandlerClass = RequestHandlerClass
- self.__is_shut_down = threading.Event()
- self.__shutdown_request = False
- def server_activate(self):
- """Called by constructor to activate the server.
- May be overridden.
- """
- pass
- def serve_forever(self, poll_interval=0.5):
- """Handle one request at a time until shutdown.
- Polls for shutdown every poll_interval seconds. Ignores
- self.timeout. If you need to do periodic tasks, do them in
- another 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 = False
- self.__is_shut_down.set()
- def shutdown(self):
- """Stops the serve_forever loop.
- Blocks until the loop has finished. This must be called while
- serve_forever() is running in another thread, or it will
- deadlock.
- """
- self.__shutdown_request = True
- self.__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 itself
- def 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.timeout
- elif 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()
- return
- self._handle_request_noblock()
- def _handle_request_noblock(self):
- """Handle one request, without blocking.
- I assume that select.select has returned that the socket is
- readable before this function was called, so there should be
- no risk of blocking in get_request().
- """
- try:
- request, client_address = self.get_request()
- except socket.error:
- return
- if 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.
- """
- pass
- def verify_request(self, request, client_address):
- """Verify the request. May be overridden.
- Return True if we should proceed with this request.
- """
- return True
- def 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.
- """
- pass
- def 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."""
- pass
- def handle_error(self, request, client_address):
- """Handle an error gracefully. May be overridden.
- The default is to print a traceback and continue.
- """
- print '-'*40
- print 'Exception happened during processing of request from',
- print client_address
- import traceback
- traceback.print_exc() # XXX But this goes to stderr!
- print '-'*40
- 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 or
- instances:
- - timeout
- - address_family
- - socket_type
- - request_queue_size (only for stream sockets)
- - allow_reuse_address
- Instance variables:
- - server_address
- - RequestHandlerClass
- - socket
- """
- address_family = socket.AF_INET
- socket_type = socket.SOCK_STREAM
- request_queue_size = 5
- allow_reuse_address = False
- def __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()
- raise
- def 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 here
- self.close_request(request)
- def close_request(self, request):
- """Called to clean up an individual request."""
- request.close()
- __version__ = "0.3"
- __all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
- import sys
- import time
- import socket # For gethostbyaddr()
- from warnings import filterwarnings, catch_warnings
- with catch_warnings():
- if sys.py3kwarning:
- filterwarnings("ignore", ".*mimetools has been removed",
- DeprecationWarning)
- import mimetools
- import SocketServer
- # Default error message template
- DEFAULT_ERROR_MESSAGE = """\
- <head>
- <title>Error response</title>
- </head>
- <body>
- <h1>Error response</h1>
- <p>Error code %(code)d.
- <p>Message: %(message)s.
- <p>Error code explanation: %(code)s = %(explain)s.
- </body>
- """
- DEFAULT_ERROR_CONTENT_TYPE = "text/html"
- def _quote_html(html):
- return html.replace("&", "&").replace("<", "<").replace(">", ">")
- class HTTPServer(SocketServer.TCPServer):
- allow_reuse_address = 1 # Seems to make sense in testing environment
- def server_bind(self):
- """Override server_bind to store the server name."""
- SocketServer.TCPServer.server_bind(self)
- host, port = self.socket.getsockname()[:2]
- self.server_name = socket.getfqdn(host)
- self.server_port = port
- SocketServer.StreamRequestHandler
- class BaseRequestHandler:
- """Base class for request handler classes.
- This class is instantiated for each request to be handled. The
- constructor sets the instance variables request, client_address
- and server, and then calls the handle() method. To implement a
- specific service, all you need to do is to derive a class which
- defines a handle() method.
- The handle() method can find the request as self.request, the
- client address as self.client_address, and the server (in case it
- needs access to per-server information) as self.server. Since a
- separate instance is created for each request, the handle() method
- can define arbitrary other instance variariables.
- """
- def __init__(self, request, client_address, server):
- self.request = request
- self.client_address = client_address
- self.server = server
- self.setup()
- try:
- self.handle()
- finally:
- self.finish()
- def setup(self):
- pass
- def handle(self):
- pass
- def finish(self):
- pass
- # The following two classes make it possible to use the same service
- # class for stream or datagram servers.
- # Each class sets up these instance variables:
- # - rfile: a file object from which receives the request is read
- # - wfile: a file object to which the reply is written
- # When the handle() method returns, wfile is flushed properly
- class StreamRequestHandler(BaseRequestHandler):
- """Define self.rfile and self.wfile for stream sockets."""
- # Default buffer sizes for rfile, wfile.
- # We default rfile to buffered because otherwise it could be
- # really slow for large data (a getc() call per byte); we make
- # wfile unbuffered because (a) often after a write() we want to
- # read and we need to flush the line; (b) big writes to unbuffered
- # files are typically optimized by stdio even when big reads
- # aren't.
- rbufsize = -1
- wbufsize = 0
- # A timeout to apply to the request socket, if not None.
- timeout = None
- # Disable nagle algorithm for this socket, if True.
- # Use only when wbufsize != 0, to avoid small packets.
- disable_nagle_algorithm = False
- def setup(self):
- self.connection = self.request#是一个socket对象
- if self.timeout is not None:
- self.connection.settimeout(self.timeout)
- if self.disable_nagle_algorithm:
- self.connection.setsockopt(socket.IPPROTO_TCP,
- socket.TCP_NODELAY, True)
- self.rfile = self.connection.makefile('rb', self.rbufsize) #makefile([mode, [bufsize]]) -- return a file object for the socket [*]
- self.wfile = self.connection.makefile('wb', self.wbufsize)
- def finish(self):
- if not self.wfile.closed:
- try:
- self.wfile.flush()
- except socket.error:
- # An final socket error may have occurred here, such as
- # the local error ECONNABORTED.
- pass
- self.wfile.close()
- self.rfile.close()
- class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
- """HTTP request handler base class.
- The following explanation of HTTP serves to guide you through the
- code as well as to expose any misunderstandings I may have about
- HTTP (so you don't need to read the code to figure out I'm wrong
- :-).
- HTTP (HyperText Transfer Protocol) is an extensible protocol on
- top of a reliable stream transport (e.g. TCP/IP). The protocol
- recognizes three parts to a request:
- 1. One line identifying the request type and path
- 2. An optional set of RFC-822-style headers
- 3. An optional data part
- The headers and data are separated by a blank line.
- The first line of the request has the form
- <command> <path> <version>
- where <command> is a (case-sensitive) keyword such as GET or POST,
- <path> is a string containing path information for the request,
- and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
- <path> is encoded using the URL encoding scheme (using %xx to signify
- the ASCII character with hex code xx).
- The specification specifies that lines are separated by CRLF but
- for compatibility with the widest range of clients recommends
- servers also handle LF. Similarly, whitespace in the request line
- is treated sensibly (allowing multiple spaces between components
- and allowing trailing whitespace).
- Similarly, for output, lines ought to be separated by CRLF pairs
- but most clients grok LF characters just fine.
- If the first line of the request has the form
- <command> <path>
- (i.e. <version> is left out) then this is assumed to be an HTTP
- 0.9 request; this form has no optional headers and data part and
- the reply consists of just the data.
- The reply form of the HTTP 1.x protocol again has three parts:
- 1. One line giving the response code
- 2. An optional set of RFC-822-style headers
- 3. The data
- Again, the headers and data are separated by a blank line.
- The response code line has the form
- <version> <responsecode> <responsestring>
- where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
- <responsecode> is a 3-digit response code indicating success or
- failure of the request, and <responsestring> is an optional
- human-readable string explaining what the response code means.
- This server parses the request and the headers, and then calls a
- function specific to the request type (<command>). Specifically,
- a request SPAM will be handled by a method do_SPAM(). If no
- such method exists the server sends an error response to the
- client. If it exists, it is called with no arguments:
- do_SPAM()
- Note that the request name is case sensitive (i.e. SPAM and spam
- are different requests).
- The various request details are stored in instance variables:
- - client_address is the client IP address in the form (host,
- port);
- - command, path and version are the broken-down request line;
- - headers is an instance of mimetools.Message (or a derived
- class) containing the header information;
- - rfile is a file object open for reading positioned at the
- start of the optional input data part;
- - wfile is a file object open for writing.
- IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
- The first thing to be written must be the response line. Then
- follow 0 or more header lines, then a blank line, and then the
- actual data (if any). The meaning of the header lines depends on
- the command executed by the server; in most cases, when data is
- returned, there should be at least one header line of the form
- Content-type: <type>/<subtype>
- where <type> and <subtype> should be registered MIME types,
- e.g. "text/html" or "text/plain".
- """
- # The Python system version, truncated to its first component.
- sys_version = "Python/" + sys.version.split()[0]
- # The server software version. You may want to override this.
- # The format is multiple whitespace-separated strings,
- # where each string is of the form name[/version].
- server_version = "BaseHTTP/" + __version__
- # The default request version. This only affects responses up until
- # the point where the request line is parsed, so it mainly decides what
- # the client gets back when sending a malformed request line.
- # Most web servers default to HTTP 0.9, i.e. don't send a status line.
- default_request_version = "HTTP/0.9"
- def parse_request(self):
- """Parse a request (internal).
- The request should be stored in self.raw_requestline; the results
- are in self.command, self.path, self.request_version and
- self.headers.
- Return True for success, False for failure; on failure, an
- error is sent back.
- """
- self.command = None # set in case of error on the first line
- self.request_version = version = self.default_request_version
- self.close_connection = 1
- requestline = self.raw_requestline
- requestline = requestline.rstrip('\r\n')
- self.requestline = requestline
- words = requestline.split()
- if len(words) == 3:
- command, path, version = words
- if version[:5] != 'HTTP/':
- self.send_error(400, "Bad request version (%r)" % version)
- return False
- try:
- base_version_number = version.split('/', 1)[1]
- version_number = base_version_number.split(".")
- # RFC 2145 section 3.1 says there can be only one "." and
- # - major and minor numbers MUST be treated as
- # separate integers;
- # - HTTP/2.4 is a lower version than HTTP/2.13, which in
- # turn is lower than HTTP/12.3;
- # - Leading zeros MUST be ignored by recipients.
- if len(version_number) != 2:
- raise ValueError
- version_number = int(version_number[0]), int(version_number[1])
- except (ValueError, IndexError):
- self.send_error(400, "Bad request version (%r)" % version)
- return False
- if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
- self.close_connection = 0
- if version_number >= (2, 0):
- self.send_error(505,
- "Invalid HTTP Version (%s)" % base_version_number)
- return False
- elif len(words) == 2:
- command, path = words
- self.close_connection = 1
- if command != 'GET':
- self.send_error(400,
- "Bad HTTP/0.9 request type (%r)" % command)
- return False
- elif not words:
- return False
- else:
- self.send_error(400, "Bad request syntax (%r)" % requestline)
- return False
- self.command, self.path, self.request_version = command, path, version
- # Examine the headers and look for a Connection directive
- self.headers = self.MessageClass(self.rfile, 0)
- conntype = self.headers.get('Connection', "")
- if conntype.lower() == 'close':
- self.close_connection = 1
- elif (conntype.lower() == 'keep-alive' and
- self.protocol_version >= "HTTP/1.1"):
- self.close_connection = 0
- return True
- def handle_one_request(self):
- """Handle a single HTTP request.
- You normally don't need to override this method; see the class
- __doc__ string for information on how to handle specific HTTP
- commands such as GET and POST.
- """
- try:
- self.raw_requestline = self.rfile.readline(65537)#读取一行,这行最多为65537B
- if len(self.raw_requestline) > 65536:#溢出处理
- self.requestline = ''
- self.request_version = ''
- self.command = ''
- self.send_error(414)
- return
- if not self.raw_requestline:#读取数据为空,关闭连接
- self.close_connection = 1
- return
- if not self.parse_request():#分析请求,出错则返回
- # An error code has been sent, just exit
- return
- mname = 'do_' + self.command#生成动作,例如do_post
- if not hasattr(self, mname):
- self.send_error(501, "Unsupported method (%r)" % self.command)
- return
- method = getattr(self, mname)
- method()
- self.wfile.flush() #actually send the response if not already done.
- except socket.timeout, e:
- #a read or a write timed out. Discard this connection
- self.log_error("Request timed out: %r", e)
- self.close_connection = 1
- return
- def handle(self):
- """Handle multiple requests if necessary."""
- self.close_connection = 1
- self.handle_one_request()
- while not self.close_connection:
- self.handle_one_request()
- def send_error(self, code, message=None):
- """Send and log an error reply.
- Arguments are the error code, and a detailed message.
- The detailed message defaults to the short entry matching the
- response code.
- This sends an error response (so it must be called before any
- output has been generated), logs the error, and finally sends
- a piece of HTML explaining the error to the user.
- """
- try:
- short, long = self.responses[code]
- except KeyError:
- short, long = '???', '???'
- if message is None:
- message = short
- explain = long
- self.log_error("code %d, message %s", code, message)
- # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
- content = (self.error_message_format %
- {'code': code, 'message': _quote_html(message), 'explain': explain})
- self.send_response(code, message)
- self.send_header("Content-Type", self.error_content_type)
- self.send_header('Connection', 'close')
- self.end_headers()
- if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
- self.wfile.write(content)
- error_message_format = DEFAULT_ERROR_MESSAGE
- error_content_type = DEFAULT_ERROR_CONTENT_TYPE
- def send_response(self, code, message=None):
- """Send the response header and log the response code.
- Also send two standard headers with the server software
- version and the current date.
- """
- self.log_request(code)
- if message is None:
- if code in self.responses:
- message = self.responses[code][0]
- else:
- message = ''
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("%s %d %s\r\n" %
- (self.protocol_version, code, message))
- # print (self.protocol_version, code, message)
- self.send_header('Server', self.version_string())
- self.send_header('Date', self.date_time_string())
- def send_header(self, keyword, value):
- """Send a MIME header."""
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("%s: %s\r\n" % (keyword, value))
- if keyword.lower() == 'connection':
- if value.lower() == 'close':
- self.close_connection = 1
- elif value.lower() == 'keep-alive':
- self.close_connection = 0
- def end_headers(self):
- """Send the blank line ending the MIME headers."""
- if self.request_version != 'HTTP/0.9':
- self.wfile.write("\r\n")
- def log_request(self, code='-', size='-'):
- """Log an accepted request.
- This is called by send_response().
- """
- self.log_message('"%s" %s %s',
- self.requestline, str(code), str(size))
- def log_error(self, format, *args):
- """Log an error.
- This is called when a request cannot be fulfilled. By
- default it passes the message on to log_message().
- Arguments are the same as for log_message().
- XXX This should go to the separate error log.
- """
- self.log_message(format, *args)
- def log_message(self, format, *args):
- """Log an arbitrary message.
- This is used by all other logging functions. Override
- it if you have specific logging wishes.
- The first argument, FORMAT, is a format string for the
- message to be logged. If the format string contains
- any % escapes requiring parameters, they should be
- specified as subsequent arguments (it's just like
- printf!).
- The client ip address and current date/time are prefixed to every
- message.
- """
- sys.stderr.write("%s - - [%s] %s\n" %
- (self.client_address[0],
- self.log_date_time_string(),
- format%args))
- def version_string(self):
- """Return the server software version string."""
- return self.server_version + ' ' + self.sys_version
- def date_time_string(self, timestamp=None):
- """Return the current date and time formatted for a message header."""
- if timestamp is None:
- timestamp = time.time()
- year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
- s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
- self.weekdayname[wd],
- day, self.monthname[month], year,
- hh, mm, ss)
- return s
- def log_date_time_string(self):
- """Return the current time formatted for logging."""
- now = time.time()
- year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
- s = "%02d/%3s/%04d %02d:%02d:%02d" % (
- day, self.monthname[month], year, hh, mm, ss)
- return s
- weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
- monthname = [None,
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
- def address_string(self):
- """Return the client address formatted for logging.
- This version looks up the full hostname using gethostbyaddr(),
- and tries to find a name that contains at least one dot.
- """
- host, port = self.client_address[:2]
- return socket.getfqdn(host)
- # Essentially static class variables
- # The version of the HTTP protocol we support.
- # Set this to HTTP/1.1 to enable automatic keepalive
- protocol_version = "HTTP/1.0"
- # The Message-like class used to parse headers
- MessageClass = mimetools.Message
- # Table mapping response codes to messages; entries have the
- # form {code: (shortmessage, longmessage)}.
- # See RFC 2616.
- responses = {
- 100: ('Continue', 'Request received, please continue'),
- 101: ('Switching Protocols',
- 'Switching to new protocol; obey Upgrade header'),
- 200: ('OK', 'Request fulfilled, document follows'),
- 201: ('Created', 'Document created, URL follows'),
- 202: ('Accepted',
- 'Request accepted, processing continues off-line'),
- 203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
- 204: ('No Content', 'Request fulfilled, nothing follows'),
- 205: ('Reset Content', 'Clear input form for further input.'),
- 206: ('Partial Content', 'Partial content follows.'),
- 300: ('Multiple Choices',
- 'Object has several resources -- see URI list'),
- 301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
- 302: ('Found', 'Object moved temporarily -- see URI list'),
- 303: ('See Other', 'Object moved -- see Method and URL list'),
- 304: ('Not Modified',
- 'Document has not changed since given time'),
- 305: ('Use Proxy',
- 'You must use proxy specified in Location to access this '
- 'resource.'),
- 307: ('Temporary Redirect',
- 'Object moved temporarily -- see URI list'),
- 400: ('Bad Request',
- 'Bad request syntax or unsupported method'),
- 401: ('Unauthorized',
- 'No permission -- see authorization schemes'),
- 402: ('Payment Required',
- 'No payment -- see charging schemes'),
- 403: ('Forbidden',
- 'Request forbidden -- authorization will not help'),
- 404: ('Not Found', 'Nothing matches the given URI'),
- 405: ('Method Not Allowed',
- 'Specified method is invalid for this resource.'),
- 406: ('Not Acceptable', 'URI not available in preferred format.'),
- 407: ('Proxy Authentication Required', 'You must authenticate with '
- 'this proxy before proceeding.'),
- 408: ('Request Timeout', 'Request timed out; try again later.'),
- 409: ('Conflict', 'Request conflict.'),
- 410: ('Gone',
- 'URI no longer exists and has been permanently removed.'),
- 411: ('Length Required', 'Client must specify Content-Length.'),
- 412: ('Precondition Failed', 'Precondition in headers is false.'),
- 413: ('Request Entity Too Large', 'Entity is too large.'),
- 414: ('Request-URI Too Long', 'URI is too long.'),
- 415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
- 416: ('Requested Range Not Satisfiable',
- 'Cannot satisfy request range.'),
- 417: ('Expectation Failed',
- 'Expect condition could not be satisfied.'),
- 500: ('Internal Server Error', 'Server got itself in trouble'),
- 501: ('Not Implemented',
- 'Server does not support this operation'),
- 502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
- 503: ('Service Unavailable',
- 'The server cannot process the request due to a high load'),
- 504: ('Gateway Timeout',
- 'The gateway server did not receive a timely response'),
- 505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
- }
- class BaseHandler:
- """Manage the invocation of a WSGI application"""
- # Configuration parameters; can override per-subclass or per-instance
- wsgi_version = (1,0)
- wsgi_multithread = True
- wsgi_multiprocess = True
- wsgi_run_once = False
- origin_server = True # We are transmitting direct to client
- http_version = "1.0" # Version that should be used for response
- server_software = None # String name of server software, if any
- # os_environ is used to supply configuration from the OS environment:
- # by default it's a copy of 'os.environ' as of import time, but you can
- # override this in e.g. your __init__ method.
- os_environ = dict(os.environ.items())
- # Collaborator classes
- wsgi_file_wrapper = FileWrapper # set to None to disable
- headers_class = Headers # must be a Headers-like class
- # Error handling (also per-subclass or per-instance)
- traceback_limit = None # Print entire traceback to self.get_stderr()
- error_status = "500 Internal Server Error"
- error_headers = [('Content-Type','text/plain')]
- error_body = "A server error occurred. Please contact the administrator."
- # State variables (don't mess with these)
- status = result = None
- headers_sent = False
- headers = None
- bytes_sent = 0
- def run(self, application):
- """Invoke the application"""
- # Note to self: don't move the close()! Asynchronous servers shouldn't
- # call close() from finish_response(), so if you close() anywhere but
- # the double-error branch here, you'll break asynchronous servers by
- # prematurely closing. Async servers must return from 'run()' without
- # closing if there might still be output to iterate over.
- try:
- self.setup_environ()
- self.result = application(self.environ, self.start_response)
- self.finish_response()
- except:
- try:
- self.handle_error()
- except:
- # If we get an error handling an error, just give up already!
- self.close()
- raise # ...and let the actual server figure it out.
- def setup_environ(self):
- """Set up the environment for one request"""
- env = self.environ = self.os_environ.copy()
- self.add_cgi_vars()
- env['wsgi.input'] = self.get_stdin()
- env['wsgi.errors'] = self.get_stderr()
- env['wsgi.version'] = self.wsgi_version
- env['wsgi.run_once'] = self.wsgi_run_once
- env['wsgi.url_scheme'] = self.get_scheme()
- env['wsgi.multithread'] = self.wsgi_multithread
- env['wsgi.multiprocess'] = self.wsgi_multiprocess
- if self.wsgi_file_wrapper is not None:
- env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
- if self.origin_server and self.server_software:
- env.setdefault('SERVER_SOFTWARE',self.server_software)
- def finish_response(self):
- """Send any iterable data, then close self and the iterable
- Subclasses intended for use in asynchronous servers will
- want to redefine this method, such that it sets up callbacks
- in the event loop to iterate over the data, and to call
- 'self.close()' once the response is finished.
- """
- try:
- if not self.result_is_file() or not self.sendfile():
- for data in self.result:
- self.write(data)
- self.finish_content()
- finally:
- self.close()
- def get_scheme(self):
- """Return the URL scheme being used"""
- return guess_scheme(self.environ)
- def set_content_length(self):
- """Compute Content-Length or switch to chunked encoding if possible"""
- try:
- blocks = len(self.result)
- except (TypeError,AttributeError,NotImplementedError):
- pass
- else:
- if blocks==1:
- self.headers['Content-Length'] = str(self.bytes_sent)
- return
- # XXX Try for chunked encoding if origin server and client is 1.1
- def cleanup_headers(self):
- """Make any necessary header changes or defaults
- Subclasses can extend this to add other defaults.
- """
- if 'Content-Length' not in self.headers:
- self.set_content_length()
- def start_response(self, status, headers,exc_info=None):
- """'start_response()' callable as specified by PEP 333"""
- if exc_info:
- try:
- if self.headers_sent:
- # Re-raise original exception if headers sent
- raise exc_info[0], exc_info[1], exc_info[2]
- finally:
- exc_info = None # avoid dangling circular ref
- elif self.headers is not None:
- raise AssertionError("Headers already set!")
- assert type(status) is StringType,"Status must be a string"
- assert len(status)>=4,"Status must be at least 4 characters"
- assert int(status[:3]),"Status message must begin w/3-digit code"
- assert status[3]==" ", "Status message must have a space after code"
- if __debug__:
- for name,val in headers:
- assert type(name) is StringType,"Header names must be strings"
- assert type(val) is StringType,"Header values must be strings"
- assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
- self.status = status
- self.headers = self.headers_class(headers)
- return self.write
- def send_preamble(self):
- """Transmit version/status/date/server, via self._write()"""
- if self.origin_server:
- if self.client_is_modern():
- self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
- if 'Date' not in self.headers:
- self._write(
- 'Date: %s\r\n' % format_date_time(time.time())
- )
- if self.server_software and 'Server' not in self.headers:
- self._write('Server: %s\r\n' % self.server_software)
- else:
- self._write('Status: %s\r\n' % self.status)
- def write(self, data):
- """'write()' callable as specified by PEP 333"""
- assert type(data) is StringType,"write() argument must be string"
- if not self.status:
- raise AssertionError("write() before start_response()")
- elif not self.headers_sent:
- # Before the first output, send the stored headers
- self.bytes_sent = len(data) # make sure we know content-length
- self.send_headers()
- else:
- self.bytes_sent += len(data)
- # XXX check Content-Length and truncate if too many bytes written?
- self._write(data)
- self._flush()
- def sendfile(self):
- """Platform-specific file transmission
- Override this method in subclasses to support platform-specific
- file transmission. It is only called if the application's
- return iterable ('self.result') is an instance of
- 'self.wsgi_file_wrapper'.
- This method should return a true value if it was able to actually
- transmit the wrapped file-like object using a platform-specific
- approach. It should return a false value if normal iteration
- should be used instead. An exception can be raised to indicate
- that transmission was attempted, but failed.
- NOTE: this method should call 'self.send_headers()' if
- 'self.headers_sent' is false and it is going to attempt direct
- transmission of the file.
- """
- return False # No platform-specific transmission by default
- def finish_content(self):
- """Ensure headers and content have both been sent"""
- if not self.headers_sent:
- # Only zero Content-Length if not set by the application (so
- # that HEAD requests can be satisfied properly, see #3839)
- self.headers.setdefault('Content-Length', "")
- self.send_headers()
- else:
- pass # XXX check if content-length was too short?
- def close(self):
- """Close the iterable (if needed) and reset all instance vars
- Subclasses may want to also drop the client connection.
- """
- try:
- if hasattr(self.result,'close'):
- self.result.close()
- finally:
- self.result = self.headers = self.status = self.environ = None
- self.bytes_sent = 0; self.headers_sent = False
- def send_headers(self):
- """Transmit headers to the client, via self._write()"""
- self.cleanup_headers()
- self.headers_sent = True
- if not self.origin_server or self.client_is_modern():
- self.send_preamble()
- self._write(str(self.headers))
- def result_is_file(self):
- """True if 'self.result' is an instance of 'self.wsgi_file_wrapper'"""
- wrapper = self.wsgi_file_wrapper
- return wrapper is not None and isinstance(self.result,wrapper)
- def client_is_modern(self):
- """True if client can accept status and headers"""
- return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
- def log_exception(self,exc_info):
- """Log the 'exc_info' tuple in the server log
- Subclasses may override to retarget the output or change its format.
- """
- try:
- from traceback import print_exception
- stderr = self.get_stderr()
- print_exception(
- exc_info[0], exc_info[1], exc_info[2],
- self.traceback_limit, stderr
- )
- stderr.flush()
- finally:
- exc_info = None
- def handle_error(self):
- """Log current error, and send error output to client if possible"""
- self.log_exception(sys.exc_info())
- if not self.headers_sent:
- self.result = self.error_output(self.environ, self.start_response)
- self.finish_response()
- # XXX else: attempt advanced recovery techniques for HTML or text?
- def error_output(self, environ, start_response):
- """WSGI mini-app to create error output
- By default, this just uses the 'error_status', 'error_headers',
- and 'error_body' attributes to generate an output page. It can
- be overridden in a subclass to dynamically generate diagnostics,
- choose an appropriate message for the user's preferred language, etc.
- Note, however, that it's not recommended from a security perspective to
- spit out diagnostics to any old user; ideally, you should have to do
- something special to enable diagnostic output, which is why we don't
- include any here!
- """
- start_response(self.error_status,self.error_headers[:],sys.exc_info())
- return [self.error_body]
- # Pure abstract methods; *must* be overridden in subclasses
- def _write(self,data):
- """Override in subclass to buffer data for send to client
- It's okay if this method actually transmits the data; BaseHandler
- just separates write and flush operations for greater efficiency
- when the underlying system actually has such a distinction.
- """
- raise NotImplementedError
- def _flush(self):
- """Override in subclass to force sending of recent '_write()' calls
- It's okay if this method is a no-op (i.e., if '_write()' actually
- sends the data.
- """
- raise NotImplementedError
- def get_stdin(self):
- """Override in subclass to return suitable 'wsgi.input'"""
- raise NotImplementedError
- def get_stderr(self):
- """Override in subclass to return suitable 'wsgi.errors'"""
- raise NotImplementedError
- def add_cgi_vars(self):
- """Override in subclass to insert CGI variables in 'self.environ'"""
- raise NotImplementedError
- class SimpleHandler(BaseHandler):
- """Handler that's just initialized with streams, environment, etc.
- This handler subclass is intended for synchronous HTTP/1.0 origin servers,
- and handles sending the entire response output, given the correct inputs.
- Usage::
- handler = SimpleHandler(
- inp,out,err,env, multithread=False, multiprocess=True
- )
- handler.run(app)"""
- def __init__(self,stdin,stdout,stderr,environ,
- multithread=True, multiprocess=False
- ):
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
- self.base_env = environ
- self.wsgi_multithread = multithread
- self.wsgi_multiprocess = multiprocess
- def get_stdin(self):
- return self.stdin
- def get_stderr(self):
- return self.stderr
- def add_cgi_vars(self):
- self.environ.update(self.base_env)
- def _write(self,data):
- self.stdout.write(data)
- self._write = self.stdout.write
- def _flush(self):
- self.stdout.flush()
- self._flush = self.stdout.flush
- class BaseCGIHandler(SimpleHandler):
- """CGI-like systems using input/output/error streams and environ mapping
- Usage::
- handler = BaseCGIHandler(inp,out,err,env)
- handler.run(app)
- This handler class is useful for gateway protocols like ReadyExec and
- FastCGI, that have usable input/output/error streams and an environment
- mapping. It's also the base class for CGIHandler, which just uses
- sys.stdin, os.environ, and so on.
- The constructor also takes keyword arguments 'multithread' and
- 'multiprocess' (defaulting to 'True' and 'False' respectively) to control
- the configuration sent to the application. It sets 'origin_server' to
- False (to enable CGI-like output), and assumes that 'wsgi.run_once' is
- False.
- """
- origin_server = False
- """BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
- This is both an example of how WSGI can be implemented, and a basis for running
- simple web applications on a local machine, such as might be done when testing
- or debugging an application. It has not been reviewed for security issues,
- however, and we strongly recommend that you use a "real" web server for
- production use.
- For example usage, see the 'if __name__=="__main__"' block at the end of the
- module. See also the BaseHTTPServer module docs for other API information.
- """
- from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
- import urllib, sys
- from wsgiref.handlers import SimpleHandler
- __version__ = "0.1"
- __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
- server_version = "WSGIServer/" + __version__
- sys_version = "Python/" + sys.version.split()[0]
- software_version = server_version + ' ' + sys_version
- class ServerHandler(SimpleHandler):
- server_software = software_version
- def close(self):
- try:
- self.request_handler.log_request(
- self.status.split(' ',1)[0], self.bytes_sent
- )
- finally:
- SimpleHandler.close(self)
- class WSGIServer(HTTPServer):
- """BaseHTTPServer that implements the Python WSGI protocol"""
- application = None
- def server_bind(self):
- """Override server_bind to store the server name."""
- HTTPServer.server_bind(self)
- self.setup_environ()
- def setup_environ(self):
- # Set up base environment
- env = self.base_environ = {}
- env['SERVER_NAME'] = self.server_name
- env['GATEWAY_INTERFACE'] = 'CGI/1.1'
- env['SERVER_PORT'] = str(self.server_port)
- env['REMOTE_HOST']=''
- env['CONTENT_LENGTH']=''
- env['SCRIPT_NAME'] = ''
- def get_app(self):
- return self.application
- def set_app(self,application):
- self.application = application
- class WSGIRequestHandler(BaseHTTPRequestHandler):
- server_version = "WSGIServer/" + __version__
- def get_environ(self):
- env = self.server.base_environ.copy()
- env['SERVER_PROTOCOL'] = self.request_version
- env['REQUEST_METHOD'] = self.command
- if '?' in self.path:
- path,query = self.path.split('?',1)
- else:
- path,query = self.path,''
- env['PATH_INFO'] = urllib.unquote(path)
- env['QUERY_STRING'] = query
- host = self.address_string()
- if host != self.client_address[0]:
- env['REMOTE_HOST'] = host
- env['REMOTE_ADDR'] = self.client_address[0]
- if self.headers.typeheader is None:
- env['CONTENT_TYPE'] = self.headers.type
- else:
- env['CONTENT_TYPE'] = self.headers.typeheader
- length = self.headers.getheader('content-length')
- if length:
- env['CONTENT_LENGTH'] = length
- for h in self.headers.headers:
- k,v = h.split(':',1)
- k=k.replace('-','_').upper(); v=v.strip()
- if k in env:
- continue # skip content length, type,etc.
- if 'HTTP_'+k in env:
- env['HTTP_'+k] += ','+v # comma-separate multiple headers
- else:
- env['HTTP_'+k] = v
- return env
- def get_stderr(self):
- return sys.stderr
- def handle(self):#处理一个request,构造server时,要传入一个requesthandler
- """Handle a single HTTP request"""
- self.raw_requestline = self.rfile.readline(65537)
- if len(self.raw_requestline) > 65536:
- self.requestline = ''
- self.request_version = ''
- self.command = ''
- self.send_error(414)
- return
- if not self.parse_request(): # An error code has been sent, just exit
- return
- handler = ServerHandler(
- self.rfile, self.wfile, self.get_stderr(), self.get_environ()
- )
- handler.request_handler = self # backpointer for logging
- handler.run(self.server.get_app())
- def demo_app(environ,start_response):#相当于django框架,处理request时会调用它
- from StringIO import StringIO
- stdout = StringIO()
- print >>stdout, "Hello world!"
- print >>stdout
- h = environ.items(); h.sort()
- for k,v in h:
- print >>stdout, k,'=', repr(v)
- start_response("200 OK", [('Content-Type','text/plain')])
- return [stdout.getvalue()]
- def make_server(
- host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
- ):
- """Create a new WSGI server listening on `host` and `port` for `app`"""
- server = server_class((host, port), handler_class)
- server.set_app(app)
- return server
- if __name__ == '__main__':
- httpd = make_server('', 8000, demo_app)
- sa = httpd.socket.getsockname()
- print "Serving HTTP on", sa[0], "port", sa[1], "..."
- import webbrowser
- webbrowser.open('http://localhost:8000/xyz?abc')
- httpd.handle_request() # serve one request, then exit
- httpd.server_close()
- server执行监听,accept,server对象有个成员为requesthandler,服务器在serv_forever时,会通过select函数来判断有无客户连接,有就调用_handle_request _noblock ->get_request ->process_request ->finish_request ->RequestHandlerClass生成一个RequestHandler对象,该对象又会调用自己的handle()->handle_one_request->parse_request->找到相应的处理方法,然后调用方法,完成一个请求。在wsgirequesthandler中重载了handle函数,它构造了serverhandler对象,serverhandler调用run来完成请求,run又调用到app对象,由app干活,返回response。
wsgiref分析的更多相关文章
- python 从SocketServer到 WSGIServer 源码分析、
python 下有个wsgi的封装库.wsgiref. WSGI 指的是 Web服务器网关接口(Python Web Server Gateway Interface) django的runserve ...
- nova创建虚拟机源码分析系列之四 nova代码模拟
在前面的三篇博文中,介绍了restful和SWGI的实现.结合restful和WSGI配置就能够简单的实现nova服务模型的最简单的操作. 如下的内容是借鉴网上博文,因为写的很巧妙,将nova管理虚拟 ...
- nova创建虚拟机源码分析系列之三 PasteDeploy
上一篇博文介绍WSGI在nova创建虚拟机过程的作用是解析URL,是以一个最简单的例子去给读者有一个印象.在openstack中URL复杂程度也大大超过上一个例子.所以openstack使用了Past ...
- 一个Flask运行分析
当我们安装好Flask环境之后,创建好项目,就会自动生成下面这段代码: from flask import Flask app = Flask(__name__) @app.route('/') de ...
- wsgiref源码解析
wsgiref是PEP 333定义的wsgi规范的范例实现,里面的功能包括了: wsgi的环境变量 应答头部的处理 实现简单的HTTP服务器 简单的对程序端和服务器端校验函数 我们先看一个简单的代码实 ...
- django源码分析
原文网址 https://www.jianshu.com/p/17d78b52c732?utm_campaign=maleskine&utm_content=note&utm_medi ...
- [深度分析] Python Web 开发框架 Bottle
[深度分析] Python Web 开发框架 Bottle(这个真的他妈的经典!!!) 作者:lhf2009913 Bottle 是一个非常精致的WSGI框架,它提供了 Python Web开发中需要 ...
- openstack XXX-api分析
一.概述 RESTful API: 表征状态迁移,也就是说client端使用http的基本操作(主要四种:get, post, put, delete 对应增删改查)使服务端的资源状态转化: WSGI ...
- linux性能评估与分析工具
linux是一个开源系统,其内核负责管理系统的进程,内存,设备驱动程序,文件和网络系统, 决定着系统的性能和稳定性.由于内核源码很容易获取,任何人都可以将自己认为优秀的代码 加入到其中.linux默认 ...
随机推荐
- [蓝桥杯]ALGO-51.算法训练_Torry的困惑(基本型)
题目描述: 问题描述 Torry从小喜爱数学.一天,老师告诉他,像2...……这样的数叫做质数.Torry突然想到一个问题,前10...……个质数的乘积是多少呢?他把这个问题告诉老师.老师愣住了,一时 ...
- 【windows】之查看端口占用
打开cmd界面 netstat -aon|findstr "80" 查看80端口占用PIDtasklist|findstr "2448" 找到占用程序直接杀死( ...
- 【转】hive中UDF、UDAF和UDTF使用
原博文出自于: http://blog.csdn.net/liuj2511981/article/details/8523084 感谢! Hive进行UDF开发十分简单,此处所说UDF为Tempora ...
- 阿里云服务器 ECS Linux操作系统加固
1. 账号和口令 1.1 禁用或删除无用账号 减少系统无用账号,降低安全风险. 操作步骤 使用命令 userdel <用户名> 删除不必要的账号. 使用命令 passwd -l <用 ...
- 信息安全-加密:DES 加密
ylbtech-信息安全-加密:DES 加密 DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资 ...
- [转]Android 代码自动提示功能
源地址http://blog.sina.com.cn/s/blog_7dbac12501019mbh.html 或者http://blog.csdn.net/longvslove/article/de ...
- redis集群服务启动
1 启动redis服务器 redis-server.exe redis.windows.conf 需要配置config节点的bind ip 2 启动redis集群 开启redis.xx.conf 服务 ...
- 数据库的ds命令
Mysqi 数据库: 理一下数据库的格式: mysqi 关系型数据库,(表的概念) node.js 非关系性数据库 (json) 结构:数据库存放多张表,每个表可以存放多个字段,每个字段可 ...
- MFC (如何通过点击botton打开一个文件夹/文件)
1.建一个MFC的工程,类型为基于对话框.在工具箱里拖进去一个button按键,如下图. 2.双击button1按键就可以进入到点击button1后要执行操作的代码,编写如下代码实现网页/文件夹或者文 ...
- [UE4]Set Skeletal Mesh,在蓝图中设置骨骼模型