Python套接字问题:无论使用什么浏览器,如何获取可靠的POST数据?
时间:2020-03-06 15:04:53 来源:igfitidea点击:
我编写了带有套接字模块的小型Python + Ajax程序(最后列出),以研究COMET异步通信的概念。
这个想法是允许浏览器通过我的python程序彼此实时发送消息。
诀窍是让" GET messages / ..."连接打开,等待消息回复。
我的问题主要在于通过socket.recv获得的可靠性...
当我从Firefox发布时,它运行良好。
当我从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 + Javascript中的client.html:
<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>
解决方案
我建议在客户端使用JS / Ajax库,以消除代码中跨浏览器问题的可能性。出于同样的原因,如果前者不允许进行低级控制,我建议我们使用python HTTP服务器库(例如SimpleHTTPServer或者Twisted的东西)。
另一个想法是使用Wireshark之类的东西来检查浏览器发送的内容。
你的问题是
- tcp套接字处理读取的数据不应该足够
- http处理不完整
我推荐以下讲座:
- rfc2616
- 史蒂文斯的套接字网络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()
非常感谢Florian,代码正在运行!!!!
我重复使用了模板,并使用我的COMET机制完成了主模板,并且效果更好
Chrome和Firefox运作良好
IE仍存在"长GET"系统问题
当它收到GET的答案时,它不会停止重新执行循环以打印消息。
现在调查问题
这是我针对非常基本的JQuery + Python跨浏览器系统的更新代码。
Python程序,基于Florian的代码:
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>