# Written by Bram Cohen
# See license.txt for license information
# File name: rewserver. py
# Code reading diary:
# Pen: zfive5
#
# Analysis rawserver class is mainly responsible for socket communication
-
-
# Polls the set of registered file descriptors, and returns a possibly-empty list containing
(fd,
-
#event)2-tuples for the descriptors that have events or errors to report. FDIs the file # descriptor, and
EventIs a bitmask with bits set for the reported events for that descriptor --
- # PollinFor waiting input, PolloutTo indicate that the descriptor can be written to, and so # forth. An empty list indicates that the call timed out and no file descriptors had any events
-
# Report. If TimeoutIs given, it specifies the length of time in milliseconds which the system will
-
# Wait for events before returning. If TimeoutIs omitted, negative, or None, The call will block
-
# Until there is an event for this poll object.
From bisect import insort
Import socket
From cstringio import stringio
From traceback import print_exc
From errno import ewouldblock, eintr
Try:
From select import poll, error, Pollin, pollout, pollerr, pollhup
Timemult = 1000
Failed t importerror:
From selectpoll import poll, error, Pollin, pollout, pollerr, pollhup
Timemult = 1
From threading import thread, event
From time import time, sleep
Import sys
From Random import randrange
All = Pollin | pollout
# Socket class: encapsulates the basic socket class, which is also the basis of communication
Class singlesocket:
Def _ init _ (self, raw_server, Sock, Handler ):
Self. raw_server = raw_server
Self. Socket = sock
Self. Handler = Handler
Self. Buffer = []
Self. last_hit = Time ()
Self. fileno = sock. fileno ()
Self. Connected = false
# Obtain the IP address of the connection peer
Def get_ip (Self ):
Try:
Return self. Socket. getpeername () [0]
Failed t socket. Error:
Return 'no connection'
# Close the socket connection. This is a bit like the closesocket () function of window.
Def close (Self ):
Sock = self. Socket
Self. Socket = none
Self. Buffer = []
Del self. raw_server.single_sockets [self. fileno]
Self. raw_server.poll.unregister (sock)
Sock. Close ()
# This is needless to say. It's shutdown ().
Def Shutdown (self, Val ):
Self. Socket. Shutdown (VAL)
# Determine whether the buffer list is empty
Def is_flushed (Self ):
Return Len (self. buffer) = 0
# The function is to write data to the buffer list. When the list element is 1, data is sent.
# Connect to the other party
Def write (self, S ):
Assert self. socket is not none
Self. Buffer. append (s)
If Len (self. buffer) = 1:
Self. try_write ()
# Send data to the recipient
Def try_write (Self ):
If self. Connected:
Try:
While self. buffer! = []:
Amount = self. Socket. Send (self. Buffer [0])
If amount! = Len (self. Buffer [0]):
If amount! = 0:
Self. Buffer [0] = self. Buffer [0] [amount:]
Break
Del self. Buffer [0]
Failed t socket. error, E:
Code, MSG = E
If code! = Ewouldblock:
Self. raw_server.dead_from_write.append (Self)
Return
# If the buffer is empty, only read data events are registered.
If self. Buffer = []:
Self. raw_server.poll.register (self. socket, Pollin)
Else:
# Register both read and write
Self. raw_server.poll.register (self. socket, all)
# Server type
Class rawserver:
Def _ init _ (self, doneflag, timeout_check_interval, timeout, noisy = true, errorfunc = none ):
Self. timeout_check_interval = timeout_check_interval
Self. Timeout = timeout
Self. Poll = poll ()
# {Socket: singlesocket}
Self. single_sockets = {}
Self. dead_from_write = []
Self. doneflag = doneflag
Self. Noisy = noisy
Self. errorfunc = errorfunc
Self. funcs = []
Self. externally_added = []
Self. add_task (self. scan_for_timeouts, timeout_check_interval)
# Add a task to the task list. The last running time is time () + delay.
Def add_task (self, func, delay ):
Insort (self. funcs, (Time () + delay, func ))
# Add an additional task to the task list. The last running time is time () + delay.
Def external_add_task (self, func, delay = 0 ):
Self. externally_added.append (func, delay ))
# Check the server timeout socket function. If the timeout is reached, disable the handler function.
Def scan_for_timeouts (Self ):
Self. add_task (self. scan_for_timeouts, self. timeout_check_interval)
T = time ()-self. Timeout
Tokill = []
For s in self. single_sockets.values ():
If S. last_hit <t:
Tokill. append (s)
For k in tokill:
If K. socket is not none:
Self. _ close_socket (k)
# Bind a port and set the non-blocking mode. The server socket corresponds to the event registration
Def BIND (self, port, bind = '', reuse = false ):
Server = socket. socket (socket. af_inet, socket. sock_stream)
If reuse:
Server. setsockopt (socket. sol_socket, socket. so_reuseaddr, 1)
Server. setblocking (0)
Server. BIND (bind, Port ))
Server. Listen (5)
Self. Poll. Register (server, Pollin)
Self. Server = Server
# Connect to the other party and set the non-blocking mode. The socket corresponds to event registration.
Def start_connection (self, DNS, Handler = none ):
If handler is none:
Handler = self. Handler
Sock = socket. socket (socket. af_inet, socket. sock_stream)
Sock. setblocking (0)
Try:
Sock. connect_ex (DNS)
Failed t socket. Error:
Raise
Except t exception, E:
Raise socket. Error (STR (e ))
Self. Poll. Register (sock, Pollin)
S = singlesocket (self, Sock, Handler)
Self. single_sockets [sock. fileno ()] = s
Return s
# Process the server and all data requests connected to the server. events is the list of socket and event-related requests.
Def handle_events (self, events ):
For sock, event in events:
If sock = self. server. fileno ():
# Disabling the server by mistake
If event & (pollhup | pollerr )! = 0:
Self. Poll. unregister (self. Server)
Self. server. Close ()
Self. errorfunc ('lost server socket ')
Else:
# Server Accept
Try:
Newsock, ADDR = self. server. Accept ()
Newsock. setblocking (0)
NSS = singlesocket (self, newsock, self. Handler)
Self. single_sockets [newsock. fileno ()] = NSS
# Register a read data event
Self. Poll. Register (newsock, Pollin)
Self. handler. external_connection_made (NSS)
Failed t socket. Error:
# Accept failed sleep (1), and then continue
Sleep (1)
Else:
S = self. single_sockets.get (sock)
If S is none:
Continue
S. Connected = true
# Disable socket by mistake
If (event & (pollhup | pollerr ))! = 0:
Self. _ close_socket (s)
Continue
# Read Data Processing
If (event & Pollin )! = 0:
Try:
S. last_hit = Time ()
Data = S. Socket. Recv (100000)
If data = '':
Self. _ close_socket (s)
Else:
# Call a processing function
S. handler. data_came_in (S, data)
Failed t socket. error, E:
Code, MSG = E
If code! = Ewouldblock:
Self. _ close_socket (s)
Continue
# Write Data Processing Process
If (event & pollout )! = 0 and S. socket is not none and not S. is_flushed ():
S. try_write ()
If S. is_flushed ():
S. handler. connection_flushed (s)
# Pop-up additional tasks
Def pop_external (Self ):
Try:
While true:
(A, B) = self. externally_added.pop ()
Self. add_task (A, B)
Failed t indexerror:
Pass
# The processing function called in download, which is mainly used to complete data processing and call processing.
Def listen_forever (self, Handler ):
Self. Handler = Handler
Try:
# Exit if the completion mark is executed
While not self. doneflag. isset ():
Try:
# Add an additional task
Self. pop_external ()
# The task list is empty.
If Len (self. funcs) = 0:
Period = 2 ** 30
Else:
# The task list is not empty.
Period = self. funcs [0] [0]-Time ()
If the interval is less than zero, the interval is zero.
If period <0:
Period = 0
# Setting registration event timeout
Events = self. Poll. Poll (period * timemult)
# Exit if the completion mark is executed
If self. doneflag. isset ():
Return
# Call the task processing function
While Len (self. funcs)> 0 and self. funcs [0] [0] <= Time ():
Garbage, func = self. funcs [0]
Del self. funcs [0]
Try:
Func ()
Except t keyboardinterrupt:
Print_exc ()
Return
Except t:
If self. Noisy:
Data = stringio ()
Print_exc (file = data)
Self. errorfunc (data. getvalue ())
# Disable socket without reflection
Self. _ close_dead ()
# Receiving and sending socket requests or data
Self. handle_events (events)
# Exit if the completion mark is executed
If self. doneflag. isset ():
Return
# Disable socket without reflection
Self. _ close_dead ()
Failed T error:
If self. doneflag. isset ():
Return
Except t keyboardinterrupt:
Print_exc ()
Return
Except t:
Data = stringio ()
Print_exc (file = data)
Self. errorfunc (data. getvalue ())
Finally:
For SS in self. single_sockets.values ():
SS. Close ()
Self. server. Close ()
# Closing dead connections
Def _ close_dead (Self ):
While Len (self. dead_from_write)> 0:
Old = self. dead_from_write
Self. dead_from_write = []
For s in old:
If S. socket is not none:
Self. _ close_socket (s)
# Disable socket connection
Def _ close_socket (self, S ):
Sock = S. Socket. fileno ()
S. Socket. Close ()
Self. Poll. unregister (sock)
Del self. single_sockets [sock]
S. Socket = none
S. handler. connection_lost (s)
# The following is a test case. If this parameter is left blank, the storage class is left for analysis next time .....