Python cho người Việt

Python cho người Việt

Entries tagged “tutorial”

Lập trình web với Python (7)

written by Nguyễn Thành Nam, on Aug 11, 2011 3:00:00 PM.

Trong bài cuối của loạt bài Lập trình web với Python, chúng ta sẽ bàn đến chuẩn WSGI (Web Server Gateway Interface).

WSGI, khác với HTTP, CGI và FCGI, không phải là chuẩn giao thức liên lạc (communication protocol) mà là chuẩn giao tiếp (standard interface) giữa ứng dụng máy chủ (server) và các khung xương (framework) hay các ứng dụng web (web application). Hình tượng hóa mà nói, WSGI nằm phía trên HTTP/CGI/FCGI và phía dưới ứng dụng thật sự. Lớp WSGI giúp lớp ứng dụng trao đổi với lớp máy chủ theo một cách khả chuyển, tức là một ứng dụng WSGI có thể chạy như nhau trên máy chủ khác nhau như Apache, NGINX, hay Lighttpd, sử dụng các giao thức khác nhau như CGI, FCGI, SCGI, hay AJP. Nói một cách khác, WSGI "che" cách liên lạc qua mạng và tạo điều kiện cho ứng dụng web tập trung vào việc xử lý các vấn đề quan trọng hơn.

Một ứng dụng WSGI là một đối tượng gọi được (callable object). Một đối tượng gọi được có thể là một hàm, một phương thức, hoặc một đối tượng có hàm call. Đối tượng gọi được này phải nhận hai tham số là environstart_response. Tham số environ là một từ điển với các khóa theo chuẩn CGI và một số khóa đặc biệt mà máy chủ WSGI có thể truyền cho ứng dụng. start_response là một đối tượng gọi được do máy chủ WSGI cung cấp cho ứng dụng để ứng dụng bắt đầu việc truyền dữ liệu cho máy chủ WSGI. start_response nhận hai tham số là dòng trạng thái trả lời (status string) và một danh sách bộ-2 (list of 2-tuple) các đầu mục (header), mỗi bộ-2 bao gồm tên và giá trị của đầu mục. Giá trị trả về của ứng dụng WSGI là một bộ khả lặp (iterable) sinh ra nội dung sẽ được máy chủ WSGI truyền lại cho máy chủ HTTP hoặc trình duyệt.

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

Đầu tiên, ta thiết lập chuỗi trạng thái là 200 OK, xác định đầu mục Content-typetext/plain rồi gọi start_response với các thông tin như vậy. Giá trị trả về là một danh sách với phần tử duy nhất là chuỗi Hello world!\n. Ta cũng có thể trả về chuỗi Hello world! trực tiếp mà không cần đặt nó vào trong một danh sách vì bản thân một chuỗi cũng là một đối tượng khả lặp. Tuy nhiên, làm như vậy không được khuyến khích vì khi đó máy chủ WSGI sẽ phải làm việc nhiều hơn, lặp qua từng ký tự H, e, l, l, o... thay vì lấy thẳng chuỗi trả lời.

Chúng ta sẽ viết lại ứng dụng đếm số lần truy cập như trong kỳ trước theo dạng một ứng dụng WSGI. Chúng ta sẽ tạo tập tin C:\Program Files\Apache Software Foundation\Apache2.2\fcgi-bin\hello2.py với nội dung như sau:

#!C:\Python26\python.exe
from flup.server import fcgi

class HelloApp(object):

	def __init__(self):
		self.count = 0

	def __call__(self, environ, start_response):
		self.count += 1
		start_response('200 OK', [('Content-type', 'text/plain')])
		return ['Hello WSGI World %d' % self.count]

if __name__ == "__main__":
	webapp = HelloApp()
	fcgi.WSGIServer(webapp, bindAddress=("localhost", 8888)).run()

Thực thi ứng dụng này với lệnh python hello2.py, chạy máy chủ Apache với các thiết lập đã làm trong bài viết kỳ trước, và truy cập vào địa chỉ http://localhost/fcgi-bin/hello.py thì chúng ta sẽ thấy hình như sau:

wsgi1.png

Khi làm tươi trình duyệt thì chúng ta nhận được hình sau:

wsgi2.png

So sánh ứng dụng viết theo WSGI và ứng dụng viết theo các giao thức CGI, hay FCGI ta thấy rõ rằng ứng dụng WSGI không cần quan tâm đến việc dữ liệu sẽ được truyền cho trình duyệt bằng cách nào. Ứng dụng WSGI chỉ quan tâm đến việc tạo ra dữ liệu gì và đẩy chỗ dữ liệu đó cho lớp WSGI bên dưới. Lớp này sẽ tự động thực hiện việc truyền tới trình duyệt theo cách tốt nhất có thể.

Tuy nhiên, ứng dụng WSGI cũng phải biết rõ cách hoạt động của máy chủ WSGI. Ví dụ, một ứng dụng WSGI chạy trên máy chủ WSGI theo mô hình CGI thì sẽ không thể trông chờ đến việc sử dụng lại biến toàn cục vì mỗi yêu cầu được một tiến trình riêng xử lý. Đồng thời ứng dụng WSGI cũng phải đảm bảo rằng các chuỗi trả về phải là chuỗi byte (byte string) và không được sử dụng chuỗi unicode (unicode string). Lý do là vì giao thức HTTP không hiểu unicode. Do đó, tốt nhất là ứng dụng WSGI nên gọi encode trên các chuỗi unicode để chuyển các chuỗi unicode thành các chuỗi byte trước khi đưa xuống cho máy chủ WSGI.

Một điểm hay của giao tiếp WSGI là một ứng dụng WSGI có thể gói (wrap) một ứng dụng WSGI khác bên trong. Điều này cho phép chúng ta tạo ra các ứng dụng WSGI hoạt động như các phần giữa (middleware), hoặc bộ lọc (filter).

Ví dụ:

def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

def real_app(environ, start_response):
    r = simple_app(environ, start_response)
    return ['Tag!\n'] + r

Với đoạn mã trên, ứng dụng real_app đã gói ứng dụng simple_app và chèn vào một chuỗi Tag!\n phía trước những gì mà simple_app gửi về. Đây là một cách để tạo nên các ứng dụng web lớn từ việc ghép các ứng dụng web nhỏ lại với nhau.

Chúng ta dừng loạt bài Lập trình web với Python tại đây. Sau 7 bài viết ngắn gọn (nhưng diễn ra trong một khoảng thời gian dài), chúng ta đã xem xét qua việc cài đặt Apache, và Python, rồi các giao thức nền tảng như HTTP, CGI. Từ đó, chúng ta bàn đến các giao thức hiện đại hơn, có một số ưu điểm tốt như FCGI với ví dụ đếm số lần truy cập. Cuối cùng chúng ta dừng lại với một thảo luận ngắn về giao tiếp WSGI, là giao tiếp phổ thông nhất để viết ứng dụng web trong thế giới Python.

Tôi hy vọng sẽ gặp bạn đọc trong các bài viết khác. Để thảo luận về loạt bài này, bạn có thể sử dụng diễn đàn http://vithon.org/forum/Forum/show/7/Ung_dung_mang_web.html.

Lập trình web với Python (6)

written by Nguyễn Thành Nam, on Jul 1, 2011 5:05:00 PM.

Phần trước chúng ta đã xem xét mô hình hoạt động của một ứng dụng FCGI. Trong phần này chúng ta sẽ viết thử một chương trình FCGI như đã đề cập.

Trước tiên, chúng ta sẽ cần cài đặt thư viện flup của tác giả Allan Saddi. Làm việc này khá đơn giản, chúng ta chỉ việc tải tập tin ez_setup.py từ địa chỉ http://peak.telecommunity.com/dist/ez_setup.py về một nơi nào đó trên máy, ví dụ như C:\Python26\Scripts. Sau đó chúng ta sẽ gọi lệnh ở màn hình DOS như sau:

C:\>c:\Python26\scripts\ez_setup.py flup

Gói flup sẽ được cài đặt trong C:\Python26\lib\site-packages.

Ở bước 2, chúng ta sẽ tải về tập tin http://www.fastcgi.com/dist/mod_fastcgi-2.4.6-AP22.dll, đổi tên nó thành mod_fastcgi.dll và đặt nó trong C:\Program Files\Apache Software Foundation\Apache2.2\modules.

Kế tiếp bước 3, chúng ta sẽ cần cấu hình Apache thành một FCGI client. Chúng ta cần sửa tập tin httpd.conf để thêm vào các dòng sau ở dưới cùng:

LoadModule fastcgi_module modules/mod_fastcgi.dll
Alias "/fcgi-bin/hello.py" "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py"
<Directory "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/">
    Order allow,deny
    Allow from all
</Directory>
FastCgiExternalServer "C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py" -host localhost:8888

Dòng LoadModule bảo Apache nạp mô-đun mod_fastcgi mà chúng ta vừa làm ở bước 2. Dòng Alias cho Apache biết rằng mọi yêu cầu đến đường dẫn (URI) /fcgi-bin/hello.py thật chất là đến tập tin C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin/hello.py. Chúng ta cần dòng này bởi vì hello.py sẽ được tạo ở ngoài DocumentRoot. Cũng chính vì thư mục fcgi-bin không nằm trong DocumentRoot nên chúng ta cũng cần lệnh Directory để cho phép Apache phục những yêu cầu truy cập vào thư mục đó. Và cuối cùng lệnh FastCgiExternalServer bảo Apache rằng tập tin hello.py thật chất là một ứng dụng FCGI đã được chạy sẵn tại địa chỉ localhost ở cổng 8888. Chính câu lệnh này sẽ chuyển Apache thành một FCGI client, chuyển tiếp yêu cầu từ trình duyệt đến FCGI server do chúng ta phát triển. Vì chúng ta đang cài đặt trên Windows nên chúng ta chỉ có một lựa chọn là sử dụng FCGI theo chế độ trao đổi qua socket, do đó chúng ta phải dùng FastCgiExternalServer.

Bước 4 là tạo tập tin hello.py trong thư mục C:/Program Files/Apache Software Foundation/Apache2.2/fcgi-bin. Nếu chưa có thư mục này, bạn đọc hãy tự tạo ra nó. Tập tin hello.py sẽ có nội dung như sau:

#!C:\Python26\python.exe
from flup.server import fcgi

count = 0

class HelloApp(fcgi.WSGIServer):

	def handler(self, req):
		global count
		count += 1
		req.stdout.write('Content-Type: text/plain\n')
		req.stdout.write('\n')
		req.stdout.write('Hello World %d' % count)

if __name__ == "__main__":
	HelloApp(application=None, bindAddress=("localhost", 8888)).run()

Trước hết, chúng ta nhập mô-đun flup.server.fcgi. Kế tiếp chúng ta khai báo một biến đếm tên count với giá trị khởi tạo là 0. Sau đó chúng ta khai báo ứng dụng của chúng ta bằng cách định nghĩa lớp HelloApp kế thừa lớp WSGIServer trong mô-đun flup.server.fcgi. HelloApp sẽ định nghĩa lại hàm handler để xử lý các yêu cầu nhận được.

Hàm handler nhận vào một tham số đó là đối tượng req chứa thông tin về các biến môi trường, các dòng dữ liệu chuẩn như stdin, stdout. Chúng ta sẽ cộng một vào biến đếm toàn cục, và xuất giá trị này ra lại cho trình duyệt. Như một ứng dụng CGI (FCGI) thông thường, trước hết chúng ta cần phải xác định kiểu dữ liệu trả về thông qua Content-Type, theo sau bởi một dòng trống đánh dấu sự chấm dứt các đầu đề (header) và bắt đầu của nội dung, và cuối cùng là nội dung.

Hai dòng lệnh cuối chỉ đơn giản là chạy ứng dụng FCGI này ở địa chỉ localhost và cổng 8888.

Để kiểm tra, chúng ta sẽ cần thực hiện ba việc: chạy ứng dụng hello.py, chạy Apache, và dùng trình duyệt xem trang http://localhost/fcgi-bin/hello.py**. Để chạy ứng dụng hello.py chúng ta chỉ cần nhập lệnh sau ở màn hình DOS:

c:\Program Files\Apache Software Foundation\Apache2.2\fcgi-bin>python hello.py

Khi dùng trình duyệt vào xem trang web như trên thì chúng ta sẽ nhận được hình sau:

hello1.png

Nếu làm tươi trình duyệt thì chúng ta sẽ thấy giá trị đếm tăng lên:

hello2.png

Như vậy chứng tỏ rằng các yêu cầu đều được phục vụ bởi một tiến trình duy nhất. Đây chính là lợi điểm của FCGI so với CGI.

Trong bài sau, chúng ta sẽ xem xét cách phát triển ứng dụng web với WSGI.

Lập trình web với Python (5)

written by Nguyễn Thành Nam, on Mar 24, 2011 5:39:00 PM.

Bẵng một thời gian, chúng ta lại quay lại với loạt bài Lập trình web với Python. Trong kỳ này, chúng ta sẽ bàn đến mô hình FastCGI (FCGI).

Cái tên FCGI khiến người ta liên tưởng đến mô hình CGI như đã trình bày trong kỳ trước. Nhưng, thật tế là FCGI là một mô hình rất khác so với CGI.

Các ứng dụng FCGI là các ứng dụng bền, tức là một tiến trình FCGI có thể phục vụ nhiều yêu cầu chứ không phải chỉ một yêu cầu như ứng dụng CGI. Do đó, các ứng dụng FCGI có thể sử dụng các biến có phạm vi ứng dụng (application-scoped variable, tương đương với các biến toàn cục, global variable), tồn tại qua nhiều yêu cầu.

Xét ví dụ một chương trình web hiển thị số lần truy cập vào trang.

  • Với mô hình CGI, khi có yêu cầu gửi đến, máy chủ web (web server, httpd) sẽ tạo một tiến trình khác, chạy chương trình CGI, chương trình này khởi tạo biến đếm với giá trị 0, tăng nó lên 1, và hiển thị số 1 rồi tiến trình kết thúc. Khi có yêu cầu thứ hai đến, máy chủ lại tạo một tiến trình khác, chạy chương trình CGI, chương trình này khởi tạo biến đếm với giá trị 0, tăng nó lên 1, và hiển thị số 1, và kết thúc tiến trình. Như vậy, vì mỗi yêu cầu được một tiến trình riêng phục vụ nên chúng ta sẽ cần phải lưu biến đếm vào một tài nguyên ngoài (ví dụ như tập tin, hoặc cơ sở dữ liệu), và các tiến trình truy cập vào cùng tài nguyên này.
  • Với mô hình FCGI, một tiến trình FCGI sẽ được chạy trước. Chương trình này được gọi là một FCGI server. Chương trình này khởi tạo biến đếm với giá trị 0 và bước vào một vòng lập vô tận để nhận yêu cầu. Trình duyệt gửi yêu cầu đến máy chủ web. Khi này máy chủ web sẽ chuyển yêu cầu này đến ứng dụng FCGI đã được chạy trước đó. Như vậy, máy chủ web đóng vai trò là một FCGI client. Ở phía FCGI server, yêu cầu được chấp nhận (accept), biến đếm được tăng lên thành 1, kết quả trả về lại cho httpd, và FCGI server quay lại vòng lập nhận yêu cầu. Máy chủ web trả lại kết quả cho trình duyệt. Khi có yêu cầu kế tiếp, máy chủ httpd lại chuyển yêu cầu đó cho cùng FCGI server. Yêu cầu này được chấp nhận, biến đếm được tăng thành 2 vì đang trong cùng một tiến trình, kết quả trả về lại cho httpd và tiếp tục như đã bàn.

Vì mô hình hoạt động của FCGI khác với CGI nên việc trao đổi giữa FCGI client và FCGI server (giữa httpd và ứng dụng FCGI) không thể sử dụng cùng một giao thức đơn giản như ứng dụng CGI nữa. Việc này đòi hỏi một giao thức riêng cho FCGI.

Mô hình hoạt động đơn giản của FCGI được miêu tả trong hình dưới.

/static/web-programming/fcgi/overview_lifecycle.png

Ngoài lợi ích về tốc độ (do không phải tạo tiến trình mới để phục vụ mỗi yêu cầu, và khả năng chia sẻ tài nguyên thông qua biến có phạm vi ứng dụng), các ứng dụng FCGI còn có thể được triển khai trên hệ thống khác với hệ thống máy chủ web, giúp cho việc phân bổ tài nguyên giữa httpd và FCGI server được hiệu quả hơn. FCGI hỗ trợ hai cách giao tiếp là thông qua stream pipe, và thông qua socket. Cách giao tiếp stream pipe tương tự như việc gửi và nhận dữ liệu qua stdin, và stdout. Cách giao tiếp này được sử dụng cho các ứng dụng FCGI triển khai trên cùng hệ thống với httpd. Cách giao tiếp socket sử dụng một kết nối TCP để đóng gói và gửi dữ liệu của env-vars, stdin, stdout, và stderr tới ứng dụng FCGI. Điều này cho phép ứng dụng FCGI được triển khai trên một hệ thống khác, và httpd sẽ liên lạc với ứng dụng này dựa vào kết nối mạng TCP. Do đó, việc tối ưu tài nguyên hệ thống có thể được thực hiện dễ dàng hơn so với ứng dụng CGI. Đối với ứng dụng FCGI, FCGI server có thể được chạy trong chế độ đa tiến trình, hoặc đa tiểu trình đều được. FCGI server có thể được chạy trên một máy 8 lõi, trong khi httpd chạy trên một máy khác đơn nhân. FCGI server phục vụ các dữ liệu động, trong khi httpd phục vụ các dữ liệu tĩnh như hình ảnh, trang web tĩnh.

Chúng ta vừa xem qua mô hình hoạt động của FCGI. Đi sâu hơn vào cấu trúc từng ứng dụng FCGI thì dúng ta có ba phần chính sau:

  • Mã khởi tạo
  • Vòng lặp nhận yêu cầu
  • Xử lý yêu cầu và trả kết quả

Trong ví dụ về ứng dụng hiển thị số lượt truy cập, mã khởi tạo là việc khởi tạo biến đếm toàn cụ với giá trị 0.

Vòng lặp nhận yêu cầu thường là một vòng lặp vô hạn, tương tự như:

while True:
    fcgi_accept()
    # xử lý yêu cầu như CGI

Trong khi yêu cầu được chấp nhận, thì dữ liệu nhập cũng được tách ra thành env-vars, stdin, stdout, và stderr. Điều này khiến cho việc xử lý yêu cầu của một ứng dụng FCGI không khác bao nhiêu so với việc xử lý của một ứng dụng CGI. Tất cả đều được thực hiện trên các biến môi trường, và các luồng chuẩn. Điều khác biệt đó là sau khi xử lý xong yêu cầu thì ứng dụng FCGI lại quay lại vòng lặp nhận yêu cầu mà không chấm dứt tiến trình như một ứng dụng CGI.

Vì không phải chấm dứt tiến trình sau mỗi yêu cầu nên các tiến trình FCGI có thể được “sử dụng lại”. Một ứng dụng FCGI có thể được khởi tạo trước, với 10 tiến trình chẳng hạn, và đặt trong một bể (pool) tiến trình sẵn sàng. Khi có yêu cầu đến, thì máy chủ web có thể ngay lập tức lấy ra một tiến trình từ bể này, và gửi thông tin đến nó. Khi kết thúc xử lý yêu cầu, máy chủ web lại đưa tiến trình này vào bể. Việc khởi tạo trước tiết kiệm được thời gian khởi tạo ban đầu, nhưng sẽ chiếm bộ nhớ, ngay cả khi chưa có yêu cầu nào được nhận.

Sau đây là mô hình chi tiết của một ứng dụng FCGI.

/static/web-programming/fcgi/detailed_lifecycle.png

Hẹn gặp các bạn vào bài tới. Chúng ta sẽ viết thử một ứng dụng FCGI đơn giản với mô-đun fcgi của Allan Saddi.

Phát hành Bài chỉ dẫn Python 2.5

written by vithon, on Sep 26, 2007 4:50:00 AM.

Bài chỉ dẫn Python 2.5 tiếng Việt đã được nhóm Python cho người Việt phát hành vào ngày 26 tháng 09 năm 2007.

Ngày 26 tháng 09 năm 2007, theo đúng như dự định, nhóm Python cho người Việt đã chính thức phát hành bản dịch của tài liệu Python Tutorial với tên Bài chỉ dẫn Python. Tài liệu này giới thiệu người đọc những khái niệm nhập môn cơ bản của ngôn ngữ Python và các thư viện có sẵn của nó. Người mới học, cũng như các chuyên gia trong ngành Công Nghệ Thông Tin có thể tìm được nhiều thông tin bổ ích từ tài liệu.

Phát biểu về sự kiện này, anh Nguyễn Thành Nam (một trong các dịch giả và là thành viên của nhóm Python cho người Việt) nhận xét:

Việc có mặt một tài liệu Python tiếng Việt hoàn toàn miễn phí là một dấu mốc quan trọng trong việc đưa ngôn ngữ Python đến gần hơn với người dùng Việt Nam.

Anh cũng cho biết thêm rằng bản dịch này là sự hợp tác của nhiều dịch giả từ khắp nơi trên thế giới có cùng niềm đam mê với ngôn ngữ Python và mong muốn giới thiệu và phát triển nó rộng rãi ở Việt Nam.

Tài liệu có thể được truy cập tại địa chỉ http://www.vithon.org/tutorial/2.5/tut.html.