Recently, I finally have some empty, ready to write a series of articles about Python's network programming, start here from Medusa here. As an excellent explanatory language, Python has now received more and more attention. BitTorrent This is now very popular with Python, such as Zope, the web server software is also written with Python. The Zope's processing network request part is used by Medusa. From the current Zope, Python can support high network connections in this area. This article will help you have some basic understanding of it with it to write a small scalable scalable, configurable FTP server program that cross-platform.
Let the single process simultaneously more than one thing: one is multithreading, this is the most popular practice, the other is I / O multiplex, it basically makes your program with multi-threading ability And in fact does not use multithreaded. If your program CPU is not a bottleneck, the I / O multiplex is very suitable, otherwise you should use multiple threads. In fact, the network server has little CPU is a bottleneck, and the general case I / O is only. The HTTP_SERVER and FTP_SERVER in Medusa are used by I / O multiplexing, which is implemented using SELECT.
Medusa itself includes a lot of modules, but most of the modules are imported asyncore or async_chat, which is part of the Python Standard Library that provides support for asynchronous, non-blocking web applications. So just familiar with Asyncore and Async_Chat, you can basically tell the core part of Medusa. Here we have to use the module mainly use the counter of the curler, which is used to operate file system's filesys, process_loop that process event loops, logs log's Logger, simple FTP server ftp_server. In fact, there is also a module that supports HTTP, and only the modules we currently care here. Here we mainly use the MEDUSA's FTP_Server module, which provides the most important part, including handling connection from the FTP client, and verification, the FileSys for the local file system is used, and then logs the logger used by the log.
The following ftp_server, passive_acceptor, ftp_channel, anon_authorizer, file_producer are all content of ftp_server.py, that is, part of the FTP_Server module. It can be seen that the main part is to inherit the standard module from Asyncore.
When the request from the network arrives, first is processed by the ftp_server object, and FTP_Server will create a separate FTP_Channel object to each request, and all requests for the connection will be processed by this FTP_Channel object.
A simplest FTP server program can be written:
#! / usr / bin / python
IMPORT Asyncore
From Medusa Import FTP_Server, FileSys, Logger
DEF StartServer ():
FTPSERV = ftp_server.ftp_server (ftp_server.aon_authorizer ("g: //"), IP = '127.0.0.1', port = 21, logger_object = logger.file_logger ("log.txt"))
asyncore.loop ()
IF __NAME__ == "__main__":
Print "Starting FTP Server .."
StartServer ()
The code above the Print "Server IS Running ..." is to start the FTP server and set the G disk to the root directory, and generate a log file called log.txt in the current directory. Its structure is very simple, mainly asyncore.loop () to determine which descriptor readable, which writer readable, which writes can be writable, read directly to Handle_Read (first time is usually Calling Handle_Accept), writable, will call Handle_WRITE (whenever a connection will create a new FTP_CHANNEL object, and its Socket's descriptor will also be added to SELECT). Here only allows anonymous access, you need to change the authentication method to redefine this authentication class, you can do it later. If you want to support the virtual directory, you need to derive new classes from Os_FileSystem in FileSys.py.
Here we also give a certification class that supports the user and password from the file. There is no encryption process for information. If necessary, it is necessary to use some coding to password encryption, and directly provide database interface to store information storage. In the database. code show as below:
IMPORT STRING
Class File_authorizer:
DEF __INIT__ (Self, Root = '/'):
Self.Root = root
DEF Authorize (Self, Channel, Username, Password):
f = Open ('user.txt')
INFO = f.readlines ()
f.close ()
IF username in ('ftp', 'anonymous'):
CHANNEL.PERSONA = -1, -1
CHANNEL.READ_ONLY = 1
Return 1, 'OK.', Filesys.os_FileSystem (Self.Root)
Else:
For i in info:
User, passwd, user_path = string.split (i, '')
If UserName == User and password == passwd:
CHANNEL.READ_ONLY = 0
Return 1, 'ok.', filesys.os_filesystem (String.Strip (user_path, '/ n')))
Return 0, 'Password INVALID.', NONE
Anon_Authorizer's code in ftp_server.py, just add a block of reading the file content, where user.txt's format is user name space password space the user home directory, one line of user information. At the same time, here we believe that users in user.txt have permission to upload files, just set up a variable chennel.read_only = 0. Of course, you need to use new authentication methods to put the original code.
FTPSERV = ftp_server.ftp_server (ftp_server.aon_authorizer ("g: //"), IP = '127.0.0.1', port = 21, logger_object = logger.file_logger ("log.txt"))
change into:
FTPSERV = ftp_server.ftp_server (file_authorizer), port = 21, ip = '127.0.0.1', port = 21, logger_object = logger.file_logger ("log.txt"))
Now the authentication is basically completed, of course, the information controlled is not a lot, but it can be expanded again! We can use the server's configuration information to put it in a separate file and use it as a configuration file. For example, we create a new file called config.py to store. You can then extract the root directory of the server's IP, port, anonymous user. Below is Config.py content.
#! / usr / bin / python
IP = '127.0.0.1'
Port = 21
Anonymous_root = 'g: //'
This will import this module directly in the main program, access to the IP via "Module Name. Variable Name", such as access to IP via config.IP. Is this very convenient? Then replace all the corresponding variable names in the main program to this way of writing.
Ok, I have completed an extensible, configurable FTP server here, I didn't expect to write a FTP server. Is it so simple? This is the characteristics of Python. Of course, there are also defects, such as without traffic control, there is no restrictions on the number of connections to each user, etc., which is to be interested in friends to expand.
Relevant information:
The Python interpreter can be downloaded from http://www.python.org.
Medusa can be downloaded from http://www.amk.ca/files/python/medusa-0.5.4.tar.gz.