Python 套接字的问题:无论浏览器如何获取可靠的 POST 数据
Issue With Python Sockets: How To Get Reliably POSTed data whatever the browser?
我用套接字模块编写了小型的Python+Ajax程序(列在末尾)来研究COMET的异步通信概念。
这个想法是允许浏览器通过我的python程序实时发送消息。
诀窍是让"获取消息/..."连接已打开,等待消息回复。
的问题主要是我通过socket.recv拥有的可靠性...
当我从火狐发布时,它运行良好。
当我从Chrome或IE开机自检时,我在Python中得到的"数据"是空的。
有人知道浏览器之间的这个问题吗?
某些浏览器是否注入了一些EOF或字符杀死了"recv"的接收?
这个问题有什么解决方案吗?
Python 中的 server.py:
import socket
connected={}
def inRequest(text):
content=''
if text[0:3]=='GET':
method='GET'
else:
method='POST'
k=len(text)-1
while k>0 and text[k]!=''n' and text[k]!=''r':
k=k-1
content=text[k+1:]
text=text[text.index(' ')+1:]
url=text[:text.index(' ')]
return {"method":method,"url":url,"content":content}
mySocket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
mySocket.bind ( ( '', 80 ) )
mySocket.listen ( 10 )
while True:
channel, details = mySocket.accept()
data=channel.recv(4096)
req=inRequest(data)
url=req["url"]
if url=="/client.html" or url=="/clientIE.html":
f=open('C:''async'''+url)
channel.send ('HTTP/1.1 200 OK'n'n'+f.read())
f.close()
channel.close()
elif '/messages' in url:
if req["method"]=='POST':
target=url[10:]
if target in connected:
connected[target].send("HTTP/1.1 200 OK'n'n"+req["content"])
print req["content"]+" sent to "+target
connected[target].close()
channel.close()
elif req["method"]=='GET':
user=url[10:]
connected[user]=channel
print user+' is connected'
客户端.html在HTML+Javascript中:
<html>
<head>
<script>
var user=''
function post(el) {
if (window.XMLHttpRequest) {
var text=el.value;
var req=new XMLHttpRequest();
el.value='';
var target=document.getElementById('to').value
}
else if (window.ActiveXObject) {
var text=el.content;
var req=new ActiveXObject("Microsoft.XMLHTTP");
el.content='';
}
else
return;
req.open('POST','messages/'+target,true)
req.send(text);
}
function get(u) {
if (user=='')
user=u.value
var req=new XMLHttpRequest()
req.open('GET','messages/'+user,true)
req.onload=function() {
var message=document.createElement('p');
message.innerHTML=req.responseText;
document.getElementById('messages').appendChild(message);
get(user);
}
req.send(null)
}
</script>
</head>
<body>
<span>From</span>
<input id="user"/>
<input type="button" value="sign in" onclick="get(document.getElementById('user'))"/>
<span>To</span>
<input id="to"/>
<span>:</span>
<input id="message"/>
<input type="button" value="post" onclick="post(document.getElementById('message'))"/>
<div id="messages">
</div>
</body>
</html>
你遇到的问题是
- 您的 TCP 套接字处理没有达到应有的读取 量
- 您的 HTTP 处理不完整
我推荐以下讲座:
- 射频2616
- Stevens 的套接字网络 API
请参阅以下示例,了解可以处理帖子的工作 http 服务器
index = '''
<html>
<head>
</head>
<body>
<form action="/" method="POST">
<textarea name="foo"></textarea>
<button type="submit">post</button>
</form>
<h3>data posted</h3>
<div>
%s
</div>
</body>
</html>
'''
bufsize = 4048
import socket
import re
from urlparse import urlparse
class Headers(object):
def __init__(self, headers):
self.__dict__.update(headers)
def __getitem__(self, name):
return getattr(self, name)
def get(self, name, default=None):
return getattr(self, name, default)
class Request(object):
header_re = re.compile(r'([a-zA-Z-]+):? ([^'r]+)', re.M)
def __init__(self, sock):
header_off = -1
data = ''
while header_off == -1:
data += sock.recv(bufsize)
header_off = data.find(''r'n'r'n')
header_string = data[:header_off]
self.content = data[header_off+4:]
lines = self.header_re.findall(header_string)
self.method, path = lines.pop(0)
path, protocol = path.split(' ')
self.headers = Headers(
(name.lower().replace('-', '_'), value)
for name, value in lines
)
if self.method in ['POST', 'PUT']:
content_length = int(self.headers.get('content_length', 0))
while len(self.content) < content_length:
self.content += sock.recv(bufsize)
self.query = urlparse(path)[4]
acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.setsockopt(
socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1,
)
acceptor.bind(('', 2501 ))
acceptor.listen(10)
if __name__ == '__main__':
while True:
sock, info = acceptor.accept()
request = Request(sock)
sock.send('HTTP/1.1 200 OK'n'n' + (index % request.content) )
sock.close()
我建议在客户端使用 JS/Ajax 库,以消除代码跨浏览器问题的可能性。出于同样的原因,我建议使用python http服务器库,如SimpleHTTPServer或Twisted中的东西,如果前者不允许低级控制。
另一个想法 - 使用类似Wireshark的东西来检查浏览器发送的内容。
非常感谢弗洛里安,你的代码正在工作!!!
我重用模板并用我的彗星机制完成主要模板,它工作得更好
Chrome和Firefox运行良好
IE在"长GET"系统
仍有问题当它收到GET的答案时,它不会停止重新执行循环以打印消息。
现在正在调查这个问题
这是我为非常基本的JQuery+Python跨浏览器系统更新的代码。
基于Florian代码的Python程序:
bufsize = 4048
import socket
import re
from urlparse import urlparse
connected={}
class Headers(object):
def __init__(self, headers):
self.__dict__.update(headers)
def __getitem__(self, name):
return getattr(self, name)
def get(self, name, default=None):
return getattr(self, name, default)
class Request(object):
header_re = re.compile(r'([a-zA-Z-]+):? ([^'r]+)', re.M)
def __init__(self, sock):
header_off = -1
data = ''
while header_off == -1:
data += sock.recv(bufsize)
header_off = data.find(''r'n'r'n')
header_string = data[:header_off]
self.content = data[header_off+4:]
furl=header_string[header_string.index(' ')+1:]
self.url=furl[:furl.index(' ')]
lines = self.header_re.findall(header_string)
self.method, path = lines.pop(0)
path, protocol = path.split(' ')
self.headers = Headers(
(name.lower().replace('-', '_'), value)
for name, value in lines
)
if self.method in ['POST', 'PUT']:
content_length = int(self.headers.get('content_length', 0))
while len(self.content) < content_length:
self.content += sock.recv(bufsize)
self.query = urlparse(path)[4]
acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.setsockopt(
socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1,
)
acceptor.bind(('', 8007 ))
acceptor.listen(10)
if __name__ == '__main__':
while True:
sock, info = acceptor.accept()
request = Request(sock)
m=request.method
u=request.url[1:]
if m=='GET' and (u=='client.html' or u=='jquery.js'):
f=open('c:''async'''+u,'r')
sock.send('HTTP/1.1 200 OK'n'n'+f.read())
f.close()
sock.close()
elif 'messages' in u:
if m=='POST':
target=u[9:]
if target in connected:
connected[target].send("HTTP/1.1 200 OK'n'n"+request.content)
connected[target].close()
sock.close()
elif m=='GET':
user=u[9:]
connected[user]=sock
print user+' is connected'
带有Jquery的HTML压缩了:
<html>
<head>
<style>
input {width:80px;}
span {font-size:12px;}
button {font-size:10px;}
</style>
<script type="text/javascript" src='jquery.js'></script>
<script>
var user='';
function post(el) {$.post('messages/'+$('#to').val(),$('#message').val());}
function get(u) {
if (user=='') user=u.value
$.get('messages/'+user,function(data) { $("<p>"+data+"</p>").appendTo($('#messages'));get(user);});
}
</script>
</head>
<body>
<span>From</span><input id="user"/><button onclick="get(document.getElementById('user'))">log</button>
<span>To</span><input id="to"/>
<span>:</span><input id="message"/><button onclick="post()">post</button>
<div id="messages"></div>
</body>
</html>
相关文章:
- Ajax-如何获取数据
- 从键值结构中获取数据,并将其与AngularJS中ng重复的值进行比较
- 从数据库中获取数据并插入JavaScript变量
- 从单击的行上的列中获取数据
- Solr查询以按日期月份获取数据&年
- React路由器服务器端渲染和ajax获取数据
- 使用JavaScript在IE9中获取数据列表选项
- 从json子数组获取数据
- 使用angularjs中的rest调用通过id获取数据
- 正在从ruby应用程序中的数据库中获取数据
- 如何从servlet获取数据到ajax成功
- 从选择下拉菜单中获取数据
- 异步获取数据使用JavaScript同步获取数据
- 从服务器获取数据并在选择控件中使用ng选项无法显示选项
- 如何在Angular.js中循环动态添加Fields并获取数据并将其发送到服务器
- JavaScript-获取数据属性的值返回未定义的值
- 如何从文本区域获取数据并使用javascript进行解密
- 在put方法之前从作用域获取数据
- 事件循环的MEAN.JS setInterval进程(从另一个服务器获取数据)
- 使用ReactJS和Flux架构从服务器获取数据的正确方法是什么