TCP socket函数recv()阻塞程序
Posted
技术标签:
【中文标题】TCP socket函数recv()阻塞程序【英文标题】:TCP socket function recv() blocking program 【发布时间】:2015-05-06 15:00:12 【问题描述】:我正在编写一个简单的 TCP 服务器程序。一切正常,但函数recv()
却不行。
import socket
import threading
def connectionHandler(sock):
data="#1111#Welcome on Server!"
sock.sendall(data.encode('ascii'))
username = sock.recv(1024)
password = sock.recv(1024)
print(', '.format(username, password))
conn.close()
HOST = socket.gethostname()
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(10)
while True:
conn, addr = s.accept()
print('Connected by', addr)
t = threading.Thread(target=connectionHandler, args=(conn,))
t.start()
conn.close()
当我评论所有对recv()
的调用时,程序运行正常,但是当我想从我的客户端(智能手机上的 android 客户端)接收答案时,程序会自行阻塞(我认为 recv()
是等待消息)。我知道我必须设置超时,但这并不能解决我的问题。我想先发送消息,然后接收一些东西。为什么recv()
会屏蔽sendall()
?
Android监听函数:
public String listener(Socket x) throws IOException
try
Log.d("Listener","Started");
String inp;
BufferedReader in = new BufferedReader(new InputStreamReader(x.getInputStream()));
inp = in.readLine();
Log.d("Listener","Ended");
return inp;
catch (UnknownHostException e1)
e1.printStackTrace();
return "ERROR";
catch (IOException e1)
e1.printStackTrace();
return "ERROR";
`
【问题讨论】:
首先,虽然我不认为这是您要问的问题(尽管可能是),但它是您需要解决的问题:@987654321 @。一个recv
可能得到半个send
,或者三个send
s 合并到一个缓冲区中。
更仔细地查看您的代码,这绝对是可能的问题。客户端向您发送用户名和密码。你的第一个 recv
得到了两者。你的第二个recv
永远等待更多数据,但客户端不再发送,因为你已经得到了一切。
要诊断此问题,请尝试print
username
;如果是用户名和密码挤在一起,那就是整个问题。 (同样,即使这不是问题的全部,它仍然是你必须解决的问题。)
附带说明,这显然是 Python 3。这意味着recv
给你的是bytes
,而不是str
;你必须 decode
它做任何有用的事情。即使只是print
也会给你b'Franky'
而不是你想要的Franky
。
我知道 tcp 套接字是字节流。在我的客户上,我没有收到任何东西。要停止程序,我必须按两次 ctrl+c 而不是一次。在我停止程序后,我会在 android 客户端上收到欢迎消息。
【参考方案1】:
在 Python 服务器上,你发送这个:
data="#1111#Welcome on Server!"
sock.sendall(data.encode('ascii'))
在 Java 客户端上,您可以这样阅读:
inp = in.readLine();
readLine
一直读取直到找到换行符。但是你永远不会发送换行符。所以它会一直读下去。
您还有其他问题需要在这里解决。
例如,当they're actually byte streams 时,您的 Python 代码假定 TCP 套接字是消息流,因此您的 username = sock.recv(1024)
可能会同时获得用户名和密码,导致下一个 recv
永远阻塞,或者它可能会获得一半用户名并导致虚假登录失败,或者您可以想象的任何其他事情。 (当然,Android 代码甚至不发送它们中的任何一个这一事实是一个更大的问题,但我假设您知道这一点,只是还没有编写该代码。)
这个问题实际上指向了解决这个问题的一种方法:如果您的任何消息都不允许包含换行符,您可以只使用换行符作为消息的终止符。您已经在 Java 端这样做了;您只需要记住在发送时添加\n
。在 Python 方面,套接字上的 makefile
方法为您提供了一个类似文件的对象,这与您在 Java 中所做的非常相似,后者具有 readline
方法,因此您可以在另一个方向上做同样的事情.
【讨论】:
我在问这里之前写了这个协议。但它并没有像我在这里展示的代码那样工作。我评论了第二个 recv(),但它没有帮助。仍然当程序运行时,我的手机上没有收到任何东西,但是当我关闭 python 程序(按 ctrl+c 两次)时,我立即收到“#1111#Welcome on Server!” @Franky:我不明白你的意思。你在这里问之前到底写了什么?当您在此处显示的代码根本不起作用时,它怎么不能像您在此处显示的代码那样工作? @Franky:同时,您在点击 ^C^C 后在 Android 上看到数据的原因是套接字已关闭,readline
将在 EOF 返回最后一个不完整的行。除非您想为每条消息断开连接并重新连接,否则这不会帮助您解决此问题。您需要在来自服务器的消息上添加\n
。
这是字符串末尾缺少 '\n' 的问题,谢谢 ;)以上是关于TCP socket函数recv()阻塞程序的主要内容,如果未能解决你的问题,请参考以下文章
[转]socket使用TCP协议时,sendrecv函数解析以及TCP连接关闭的问题