Echo client/server đơn giản


  • administrators

    Bài viết của Mod Trung - được chuyển từ diễn đàn cũ.

    Mình xin giới thiệu một cách viết chương trình client - server đơn giản sử dụng gevent.

    Echo server: nhận message từ client và gửi trả lại message đó cho client.
    Echo client: gửi message tới server và nhận lại message vừa gửi.

    Chương trình này mình thấy có 2 điều thú vị. Thứ nhất là chúng ta sẽ viết một server có thể phục vụ nhiều client một lúc ở mức đơn giản nhất có thể. Thứ 2 là thư viện gevent sẽ giúp chúng ta handle nhiều client mà không phải dùng tới multithreading (chạy nhiều thread - hay process nhỏ trong một chương trình). Về cơ bản lý do tránh dùng multithreading là việc chia sẻ data giữa các thread khó khăn, dễ rơi vào tình huống deadlock - tất cả các thread trong chương trình bị dừng lại, khó debug.

    Gevent cung cấp module socket giống như module socket chuẩn kèm theo Python. Chỉ khác ở chỗ module socket mà gevent cung cấp có thể chạy song song với nhau mà không dùng tới multithreading. Tính năng này sử dụng để viết server phục vụ nhiều client. Gevent còn nhiều điều thú vị nữa. Để biết thêm chi tiết, bạn có thể ghé qua http://www.gevent.org/.
    server.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    import gevent
    from gevent.socket import socket
     
     
    def client_handler(client, addr):
        '''
        Quản lý một kết nối tới server từ client
        Mỗi client sẽ được quản lý riêng biệt và độc lập
        Do đó server có thể cùng lúc phục vụ nhiều client
        '''
     
        try:
            while True:
                # nhận message từ client
                message = client.recv(1024)
                if message:
                    # nếu nhận được message thì in ra màn hình
                    client.send(message)
                    print "%s:%d -" % addr, message
                else:
                    # nếu không nhận được message thì có nghĩa là client
                    # đã bị ngắt kết nối
                    print "%s:%d -" % addr, "out!"
                    return
     
        except gevent.GreenletExit:
            # ngắt kết nối với client khi server bị đóng (bởi ctrl-c)
            print "Goodbye %s:%d" % addr
            client.close()
     
     
    def run(port):
        '''
        Chạy server tại cổng port
        '''
     
        clients = []
     
        # server lắng nghe ở cổng port
        server = socket()
        server.bind(('0.0.0.0', port))
        server.listen(0)
     
        print "Server listening at port %d..." % port
     
        try:
     
            # lặp để chờ kết nối từ client
            while True:
     
                # chấp nhật kết nối từ client
                client, addr = server.accept()
                print "Welcome new client %s:%d" % addr
     
                # tạo một handler cho client: xử lý các message từ client
                # song song với việc server chấp nhận client mới
                clients.append(gevent.spawn(client_handler, client, addr))
     
            # chờ các client hoàn thành việc chao đổi với server
            # và kết thúc chương trình
            gevent.joinall(clients)
     
        except KeyboardInterrupt:
            # ctrl-c để đóng chương trình đồng thời đóng các client đang chạy
            print "Goodbye!"
            gevent.killall(clients)
     
     
    if __name__ == '__main__':
        run(6666)
    

    client.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from gevent.socket import create_connection
     
     
    def run(addr):
        '''
        Chạy client và kết nối tới địa chỉ addr dạng tuple ví dụ ('127.0.0.1', 6666)
        '''
     
        # kết nối tới server
        client = create_connection(addr)
     
        if client:
     
            try:
                while True:
                    # nhập message để gửi tới server
                    message = raw_input("~> ")
     
                    if message:
                        # kết thúc chương trình nếu nhập 'exit'
                        if message == 'exit':
                            print "Goodbye!"
                            client.close()
                            return
     
                        try:
                            # gửi message tới server
                            client.send(message)
     
                            # chờ phản hồi từ server
                            reply = client.recv(1024)
     
                            if reply:
                                print "Server - %s" % reply
                            else:
                                # không có phản hồi tức là server đã bị ngắt kết nối
                                print "Server is down"
                                break
     
                        except Exception:
                            print "Goodbye!"
                            return
     
                    else:
                        print "You type empty input. To quit type 'exit'"
     
            except KeyboardInterrupt:
                print "Goodbye!"
     
            finally:
                # cuối cùng đóng kết nối tới server và kết thúc chương trình
                client.close()
     
     
    if __name__ == '__main__':
        run(('127.0.0.1', 6666))
    

    Để chạy chương trình có thể bạn cần delete các comment bằng tiếng Việt.

    Cài đặt Gevent:


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới Cộng đồng Python Việt Nam, vui lòng đợi một lúc để chúng tôi thử kết nối lại.