Bea*_*ear 5 sockets tornado websocket handshake python-3.3
我正在尝试学习套接字编程以及WebSocket协议.我知道存在python web socket客户端,但我希望只为自己的学习构建一个玩具版本.为此,我创建了一个非常简单的Tornado websocket服务器,我正在运行localhost:8888
.它只是在客户端连接时打印一条消息.
这是整个服务器 - 它的工作原理(我在浏览器中用一个小的javascript脚本测试过它)
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print('new connection')
self.write_message("Hello World")
def on_message(self, message):
print('message received %s' % message)
def on_close(self):
print('connection closed')
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Run Code Online (Sandbox Code Playgroud)
所以一旦我启动服务器,我尝试运行以下脚本
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((socket.gethostbyname('localhost'), 8888))
msg = '''GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13'''.encode('ascii')
print(len(msg))
sent_count = sock.send(msg)
print('sent this many bytes:', sent_count)
recv_value = sock.recv(1)
print('recvieved:', recv_value)
Run Code Online (Sandbox Code Playgroud)
我希望服务器将发回RFC中指定的响应头.相反,sock.recv挂了.这让我相信服务器没有确认websocket初始握手.此握手也是从RFC中撤出的.我知道websocket密钥应该是随机的一切,但我认为这不会导致服务器忽略握手(websocket密钥有效).我想,一旦我能够发起握手,我就能解决其余问题,所以我希望在websockets的工作方式或如何发送初始握手方面存在一些误解.
7st*_*tud 10
1)当您通过套接字发送消息时,您不知道它将被分成多少块.它可能都会立即发送; 或者可以发送前3个字母,然后发送剩余的信息; 或者消息可以分成10个部分.
2)给定1)服务器如何知道何时收到客户端发送的所有块?例如,假设服务器收到客户端消息的1个块.服务器如何知道这是整个消息还是还有9个以上的块?
3)我建议你读这个:
http://docs.python.org/2/howto/sockets.html
(加上评论中的链接)
4)现在,为什么不使用python来创建HTTP服务器?
python3:
import http.server
import socketserver
PORT = 8000
handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", PORT), handler)
print("serving at port", PORT)
httpd.serve_forever()
Run Code Online (Sandbox Code Playgroud)
python2:
import SimpleHTTPServer
import SocketServer
PORT = 8000
handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), handler)
print "serving at port", PORT
httpd.serve_forever()
Run Code Online (Sandbox Code Playgroud)
SimpleHTTPRequestHandler提供服务器程序目录及其下的文件,将请求URL与您创建的目录结构相匹配.如果请求'/',服务器将从服务器所在的目录中提供index.html文件.以下是python 3的客户端套接字示例(下面是python 2示例):
import socket
import sys
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print('Failed to create socket')
sys.exit()
print('Socket Created')
#To allow you to immediately reuse the same port after
#killing your server:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = 'localhost';
port = 8000;
s.connect((host , port))
print('Socket Connected to ' + host + ' on port ', port)
#Send some data to server
message = "GET / HTTP/1.1\r\n\r\n"
try :
#Send the whole string(sendall() handles the looping for you)
s.sendall(message.encode('utf8') )
except socket.error:
print('Send failed')
sys.exit()
print('Message sent successfully')
#Now receive data
data = []
while True:
chunk = s.recv(4096) #blocks while waiting for data
if chunk: data.append(chunk.decode("utf8"))
#If the recv() returns a blank string, then the other side
#closed the socket, and no more data will be sent:
else: break
print("".join(data))
--output:--
Socket Created
Socket Connected to localhost on port 8000
Message sent successfully
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.2.3
Date: Sat, 08 Jun 2013 09:15:18 GMT
Content-type: text/html
Content-Length: 23
Last-Modified: Sat, 08 Jun 2013 08:29:01 GMT
<div>hello world</div>
Run Code Online (Sandbox Code Playgroud)
在python 3中,你必须使用带有套接字的字节字符串,否则你会得到可怕的:
TypeError: 'str' does not support the buffer interface
Run Code Online (Sandbox Code Playgroud)
这是在python 2.x中:
import socket
import sys
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print('Socket Created')
#To allow you to immediately reuse the same port after
#killing your server:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = 'localhost';
port = 8000;
s.connect((host , port))
print('Socket Connected to ' + host + ' on port ', port)
#Send some data to server
message = "GET / HTTP/1.1\r\n\r\n"
try :
#Send the whole string(handles the looping for you)
s.sendall(message)
except socket.error:
print 'Send failed'
sys.exit()
print 'Message sent successfully'
#Now receive data
data = []
while True:
chunk = s.recv(4096) #blocks while waiting for data
if chunk: data.append(chunk)
#If recv() returns a blank string, then the other side
#closed the socket, and no more data will be sent:
else: break
print("".join(data))
--output:--
Message sent successfully
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.7.3
Date: Sat, 08 Jun 2013 10:06:04 GMT
Content-type: text/html
Content-Length: 23
Last-Modified: Sat, 08 Jun 2013 08:29:01 GMT
<div>hello world</div>
Run Code Online (Sandbox Code Playgroud)
请注意,GET请求的标头告诉服务器HTTP 1.1将是协议,即管理会话的规则.正如HTTP 1.1的RFC所描述的那样,请求中必须有两个'\ r \n'序列.所以服务器正在寻找第二个'\ r \n'序列.如果从请求中删除其中一个'\ r \n'序列,客户端将挂起recv(),因为服务器仍在等待更多数据,因为服务器还没有读取第二个'\ r \n'序列.
另请注意,您将以字节形式发送数据(在python 3中),因此不会有任何自动'\n'转换,并且服务器将期望序列'\ r \n'.
归档时间: |
|
查看次数: |
18298 次 |
最近记录: |