Python示例:Joe的Erlang WebSocket示例

9 投票
3 回答
11772 浏览
提问于 2025-04-15 18:35

我最近在学习Erlang的WebSocket示例,来源于Joe Armstrong的博客。因为我对Erlang还不太熟悉,所以我决定用Python写一个简单的服务器,帮助我理解WebSocket(同时也希望通过解读Joe的代码来学点Erlang)。我遇到了两个问题:

1) 我从页面收到的数据最后有个'ÿ'字符。这在Erlang版本中没有出现,我搞不清楚它是从哪里来的。解决了 - 这是因为字符串是用utf-8编码的,而我没有解码它们。

2) 我似乎从服务器(通过WebSocket)发送了数据 - 通过查看client.send()发送的字节数可以确认这一点。但页面上什么也没显示。解决了,我没有正确编码字符串。

我把所有代码放在这里。这是我的Python版本,以防我漏掉了什么明显的东西。

import threading
import socket

def start_server():
    tick = 0
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 1234))
    sock.listen(100)
    while True:
        print 'listening...'
        csock, address = sock.accept()
        tick+=1
        print 'connection!' 
        handshake(csock, tick)
        print 'handshaken'
        while True:
            interact(csock, tick)
            tick+=1

def handshake(client, tick):
    our_handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"+"Upgrade:     WebSocket\r\n"+"Connection: Upgrade\r\n"+"WebSocket-Origin:     http://localhost:8888\r\n"+"WebSocket-Location: "+" ws://localhost:1234/websession\r\n\r\n"
    shake = client.recv(255)
    print shake
    client.send(our_handshake)

def interact(client, tick):
    data = client.recv(255)
    print 'got:%s' %(data)
    client.send("clock ! tick%d\r" % (tick))
    client.send("out ! recv\r")

if __name__ == '__main__':
    start_server()

对于那些还没看过Joe示例但想帮忙的人,你只需要通过一个Web服务器提供interact.html,然后启动你的服务器(代码假设Web服务器运行在localhost:8888)。

3 个回答

0

Eventlet 自带了对 websocket 的支持,而 stargate 是一个可以让你在 pyramid 网页框架中使用 websocket 的工具包:http://boothead.github.com/stargate/

0

谢谢你分享代码。我在Windows上运行这段代码时遇到了一个问题。我觉得这可能对还在摸索的人有帮助。

  1. 我缩减了空格,所以它变成了 'Upgrade: WebSocket'

  2. 确保你的托管页面的来源(Origin)是匹配的,在这个例子中是 'http://localhost:8888'

现在对我来说运行得非常顺利。

10

对于感兴趣的朋友,这就是解决方案

import threading
import socket

def start_server():
    tick = 0
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', 1234))
    sock.listen(100)
    while True:
        print 'listening...'
        csock, address = sock.accept()
        tick+=1
        print 'connection!' 
        handshake(csock, tick)
        print 'handshaken'
        while True:
            interact(csock, tick)
            tick+=1
            
            
def send_data(client, str_):
    #_write(request, '\x00' + message.encode('utf-8') + '\xff')
    str_ = '\x00' + str_.encode('utf-8') + '\xff'
    return client.send(str_)
def recv_data(client, count):
    data = client.recv(count)    
    return data.decode('utf-8', 'ignore')

def handshake(client, tick):
    our_handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"+"Upgrade:     WebSocket\r\n"+"Connection: Upgrade\r\n"+"WebSocket-Origin: http://localhost:8888\r\n"+"WebSocket-Location: "+" ws://localhost:1234/websession\r\n\r\n"
    shake = recv_data(client, 255)
    print shake
    #We want to send this without any encoding
    client.send(our_handshake)
         
def interact(client, tick):
    data = recv_data(client, 255)
    print 'got:%s' %(data)
    send_data(client, "clock ! tick%d" % (tick))
    send_data(client, "out ! %s" %(data))

if __name__ == '__main__':
    start_server()

根据liwp的要求进行编辑:

你可以在这里查看文件的差异。简单来说,我的问题出在发送和接收之前对字符串的解码和编码方式上。我使用了一个websocket模块,这个模块在谷歌代码上正在开发,帮助我找到了错误所在。

撰写回答