我试图通过python 2.7上的这段代码从我的连接接收数据:
server = socket(AF_INET, SOCK_STREAM)
server.bind(('0.0.0.0', 21))
server.listen(1)
client , addr = server.accept()
data = client.recv(2048)
当我必须打印或发送到另一个连接我的数据时,它正在工作,但是我想添加这些行:
if(data == "/disconnect") :
<disconnect blha blha... you know >
else :
<print the data and send it back blha blha... >
(我没有检查if语句和“ disconnect blha blha ..”效果很好)
它只是传递代码,所以当我的客户请求断开连接时,该请求将作为“原始”消息发送给服务器(服务器不会踢他)
我该怎么办?谢谢!
答案 0 :(得分:0)
您有两个问题,需要同时解决。
首先,a TCP socket is just a stream of bytes。当您执行recv
时,不会从另一端收到send
发送的一条消息,您将获得当前缓冲区中的所有内容,可能是两个消息,半条消息或其他任何消息。当您只是在负载不重的计算机上使用本地主机连接进行测试时,在许多平台上,它将执行您希望超过99%的时间的工作,但这只会使问题难以调试,不能解决。并且,一旦您尝试通过Internet访问相同的代码,大多数情况下它就会开始失败,而不是很少。
幸运的是,客户端似乎正在以文本形式发送消息,没有任何嵌入的换行符,每条消息之间使用\r\n
Windows风格的行尾。这是一个非常好的协议。您只需要编写代码即可在接收端处理该协议。
第二个问题是,即使您碰巧恰好收到一条消息send
,该消息也会包含\r\n
行尾。 '/disconnect\r\n' == '/disconnect'
当然是错误的。因此,作为协议处理程序的一部分,您需要删除换行符。
碰巧,您可以通过使用makefile
方法为您提供可以迭代或readline
等的文件对象来解决这两个问题,就像处理文件一样您open
从磁盘上获取的信息,您可能已经知道该如何处理。
但是值得学习如何做这些事情,因此,我将向您展示如何手动进行。关键是要保留一个缓冲区,将每个recv
添加到该缓冲区中,然后将其拆分为几行,将其余部分放回缓冲区中,并将每一行作为消息处理。有更多优雅/简洁的方法可以编写此代码,但让我们简单一点吧:
buf = ''
while True:
data = client.recv(2048)
buf += data
lines = buf.split('\r\n')
buf = lines.pop()
for line in lines:
# line is now a single message, with the newline stripped
if line == "/disconnect":
# do disconnect stuff
else:
# do normal message stuff
这就是使基础知识正常工作所需要的。但是在真实服务器中,您还需要一些代码来处理其他两个条件-因为客户端并不总是干净地关闭。例如,如果客户端在断开连接才能发送/disconnect
消息之前已断开与Internet的连接,则您不想一直旋转并永远阅读任何内容,则希望将其视为断开连接。
if not data:
表示客户端已完成干净(在TCP级别)关闭。因此,您需要断开连接并中断接收循环。
if buf:
,如果是,请将buf
视为最后一条命令。 (这在许多协议中并不常见,但是在客户端中是常见的错误,因此,例如,许多Web服务器都可以处理它。)try:
/ except Exception as e:
将捕获各种错误。这些错误意味着套接字不再可用(或者代码中肯定存在严重错误),因此您要通过丢弃连接并中断接收循环来解决此问题,而无需先发送任何最终响应或阅读任何最终信息。
e
(也许只是print 'Error from', addr, repr(e)
),因此,如果遇到意外的异常,则需要调试。