2015-04-29 20 views
12

Hoàn toàn mới cho websockets.Autobahn gửi tin nhắn cụ thể và phát sóng của người dùng từ ứng dụng bên ngoài

Tôi gặp một chút khó khăn khi hiểu cách tương tác với python Autobahn/bị xoắn từ ứng dụng khác và dường như không tìm thấy bất kỳ ví dụ hữu ích nào.

Tôi có ứng dụng Python đang chạy mà cần trên một số sự kiện nhất định để gửi một trong hai loại thư. Đầu tiên là tin nhắn quảng bá cho tất cả người dùng. Loại thứ hai là một người dùng cụ thể.

Sử dụng hai ví dụ sau, tôi có thể nhận tin nhắn và gửi phản hồi. Tuy nhiên, tôi không cần phải nhận bất cứ thứ gì từ các máy khách được kết nối (ngoài các máy khách kết nối với máy chủ web) chỉ gửi cho họ.

Tôi đã chơi với: https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/echo

Ngoài (không Autobahn liên quan): https://github.com/opiate/SimpleWebSocketServer

Câu hỏi:

1 - Là những gì tôi đang cố gắng để làm tốt? Tôi có thể có một ứng dụng bên ngoài kết nối với ứng dụng/máy chủ Autobahn và phát các tin nhắn đến tất cả người dùng được kết nối hoặc một người dùng.

2 - Nếu có thể, ai đó có thể chỉ cho tôi đúng hướng để tìm hiểu cách thực hiện điều này?

Cảm ơn

Trả lời

6

Trước hết dự án Autobahn cung cấp triển khai mã nguồn mở giao thức truyền thông WAMP. WAMP cung cấp hai mẫu giao tiếp RPC (Gọi thủ tục từ xa) và PUBSUB (Xuất bản-Đăng ký). Vì vậy, trong trường hợp của bạn, nó là cần thiết để tìm ra mô hình nào phù hợp với nhu cầu của bạn.

RPC

Theo WAMP FAQ RPC RPC bao gồm ba Roles. Đó là:

  • Caller
  • callee
  • Đại lý

Trong trường hợp của bạn, callee là máy chủ trong khi Caller (Client) gọi một phương pháp trên máy chủ. Đây là những gì dường như làm việc cho bạn. (Một giá trị trả lại có thể được gửi đến Callee/khách hàng). Các đại lý có trách nhiệm định tuyến và có thể được bỏ qua tại thời điểm này. Vì vậy, xem xét các mô hình trên có vẻ như không phù hợp cho vấn đề của bạn.

PubSub

Các mô hình thứ hai là PubSub.Mô hình này bao gồm ba vai trò (lấy từ WAMP FAQ PUBSUB):

  • Publisher
  • Subscriber
  • Broker

Vì vậy, những gì xảy ra là, nhà xuất bản (Server) công bố các sự kiện để chủ đề. Người đăng ký (Khách hàng) có thể đăng ký một chủ đề của Nhà xuất bản. Khi sự kiện được xuất bản, Người đăng ký sẽ nhận được sự kiện bao gồm cả tải trọng. Điều đó có nghĩa là bạn có thể cung cấp chủ đề "Phát sóng" và cho phép tất cả khách hàng đăng ký chủ đề. Nếu được yêu cầu, bạn có thể gửi tin nhắn quảng bá tới tất cả khách hàng.

Sau đó, bạn phải giải quyết vấn đề gửi tin nhắn cho các khách hàng đơn lẻ (Người đăng ký). Theo tài liệu, chức năng xuất bản để xuất bản một chủ đề có tham số tùy chọn để cung cấp danh sách "Khách hàng" đủ điều kiện nhận sự kiện. WAMP Documentation (Class Publish)

-------- EDIT --------

Nó không phải là rõ ràng những gì là có nghĩa là bởi "ứng dụng bên ngoài" và trong ngôn ngữ gì nó được coi là bằng văn bản. Vấn đề giải thích của Tác giả có thể được giải quyết nếu ứng dụng bên ngoài được viết bằng python, JavaScript hoặc Cpp hoặc Ứng dụng Android bằng cách sử dụng khung công tác Autobahn với (WAMP).

Cung cấp Autobahn, như được đề cập trong câu hỏi, cũng là triển khai giao thức websocket. Một cách tiếp cận khác để giải quyết vấn đề có thể là bằng cách sử dụng Autobahn Websockets và cho "ứng dụng bên ngoài" một Websocket thực hiện sự lựa chọn. Autobahn cung cấp cho Python và các giải pháp Websocket Android. Tất nhiên có nhiều thư viện hoặc mô-đun Websocket hơn. Java Websocket library, Python Websocket Client module và nhiều hơn nữa ...

Vì vậy, hãy cho phép Websocket Server được triển khai bằng cách sử dụng khung Autobahn. Ứng dụng bên ngoài là một ứng dụng khách khác kết nối với máy chủ và gửi một chuỗi được xác định bắt đầu bằng "send_broadcast: PAYLOAD" và tải trọng được nối thêm. Trên máy chủ, bạn có thể kiểm tra thông báo cho chuỗi và nếu msg bắt đầu bằng "send_broadcast", bạn có thể gửi phát sóng tới tất cả các máy khách được kết nối. Nếu bạn muốn gửi tin nhắn đến chỉ một khách hàng, bạn có thể xác định một chuỗi khác như "send_to_single: IP: PAYLOAD" chẳng hạn. Việc triển khai máy chủ sau đó có thể có một nhánh khác để kiểm tra "send_to_single" và gọi một phương thức khác, có thể là "def send_to_single" ?, và chuyển một đối số khác cho ip của máy khách. Thay vì gửi cho tất cả các máy khách, như trong phương thức phát sóng, bạn chỉ có thể gửi thông điệp tới máy khách đã cho. Một cách khác cho giao thức truyền thông của bạn sẽ sử dụng JSON. bạn có thể xác định msg của bạn như sau:

{ 
    "type": "broadcast", 
    "msg": "your_message" 
} 

hoặc

{ 
    "type": "single", 
    "elegible": ["IP_1", "???"], 
    "msg": "your_message" 
} 

Trên Server thì bạn nạp Payload, kiểm tra các loại và làm các bước tiếp theo.

server

import sys 

from twisted.internet import reactor 
from twisted.python import log 
from twisted.web.server import Site 
from twisted.web.static import File 

from autobahn.twisted.websocket import WebSocketServerFactory, \ 
    WebSocketServerProtocol, \ 
    listenWS 


class BroadcastServerProtocol(WebSocketServerProtocol): 

    def onOpen(self): 
     self.factory.register(self) 

    def onConnect(self, request): 
     print("Client connecting: {}".format(request.peer)) 

    def onMessage(self, payload, isBinary): 
     if not isBinary: 
      if "send_broadcast" in payload.decode('utf8'): 
       msg = "Send broadcast was ordered" 
       self.factory.broadcast(msg) 

    def connectionLost(self, reason): 
     WebSocketServerProtocol.connectionLost(self, reason) 
     self.factory.unregister(self) 


class BroadcastServerFactory(WebSocketServerFactory): 

    """ 
    Simple broadcast server broadcasting any message it receives to all 
    currently connected clients. 
    """ 

    def __init__(self, url, debug=False, debugCodePaths=False): 
     WebSocketServerFactory.__init__(self, url, debug=debug, debugCodePaths=debugCodePaths) 
     self.clients = [] 
     self.tickcount = 0 
     self.tick() 

    def tick(self): 
     self.tickcount += 1 
     self.broadcast("tick %d from server" % self.tickcount) 
     reactor.callLater(1, self.tick) 

    def register(self, client): 
     if client not in self.clients: 
      print("registered client {}".format(client.peer)) 
      self.clients.append(client) 

    def unregister(self, client): 
     if client in self.clients: 
      print("unregistered client {}".format(client.peer)) 
      self.clients.remove(client) 

    def broadcast(self, msg): 
     print("broadcasting message '{}' ..".format(msg)) 
     for c in self.clients: 
      c.sendMessage(msg.encode('utf8')) 
      print("message sent to {}".format(c.peer)) 


class BroadcastPreparedServerFactory(BroadcastServerFactory): 

    """ 
    Functionally same as above, but optimized broadcast using 
    prepareMessage and sendPreparedMessage. 
    """ 

    def broadcast(self, msg): 
     print("broadcasting prepared message '{}' ..".format(msg)) 
     preparedMsg = self.prepareMessage(msg) 
     for c in self.clients: 
      c.sendPreparedMessage(preparedMsg) 
      print("prepared message sent to {}".format(c.peer)) 


if __name__ == '__main__': 

    if len(sys.argv) > 1 and sys.argv[1] == 'debug': 
     log.startLogging(sys.stdout) 
     debug = True 
    else: 
     debug = False 

    ServerFactory = BroadcastServerFactory 
    # ServerFactory = BroadcastPreparedServerFactory 

    factory = ServerFactory("ws://localhost:9000", 
          debug=debug, 
          debugCodePaths=debug) 

    factory.protocol = BroadcastServerProtocol 
    factory.setProtocolOptions(allowHixie76=True) 
    listenWS(factory) 

    webdir = File(".") 
    web = Site(webdir) 
    reactor.listenTCP(8080, web) 

    reactor.run() 

Khách hàng Client được viết cũng bằng Python sử dụng một khác nhau thực hiện mô-đun và vẫn hoạt động.Tất nhiên là cần thiết để liên lạc với một Websocket Server bằng giao thức Websocket.

from websocket import create_connection 
ws = create_connection("ws://localhost:9000") 
print "Sending 'send_broadcast'..." 
ws.send("send_broadcast:PAYLOAD") 
print "Sent" 
print "Reeiving..." # OPTIONAL 
result = ws.recv() # OPTIONAL 
print "Received '%s'" % result # OPTIONAL 
ws.close(

)

+0

Câu hỏi đặt ra chưa được trả lời mặc dù. Ví dụ trên KHÔNG phát các tin nhắn từ một nguồn bên ngoài, chúng chỉ sử dụng một giấc ngủ để phát một tin nhắn nội bộ sau mỗi 5 giây. – someuser

+0

Vì vậy, hãy giải thích về nguồn bên ngoài của bạn. Điện thoại thông minh (IOS/Android) hoặc trình duyệt? Hoặc một máy tính/máy tính xách tay? – Ben

+0

Vâng, tôi đã chỉnh sửa câu trả lời của tôi, đưa ra một gợi ý về cách kết nối với máy chủ và yêu cầu máy chủ gửi một chương trình phát sóng hoặc tin nhắn tới một khách hàng. Nó không bao gồm thông điệp khách duy nhất nhưng giải thích cách nó có thể được quản lý. Câu hỏi đặt ra là đi đúng hướng. Tôi hy vọng câu trả lời sẽ giúp bạn biết được nơi để đi từ đây. – Ben

Các vấn đề liên quan