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,或者三个sends 合并到一个缓冲区中。 更仔细地查看您的代码,这绝对是可能的问题。客户端向您发送用户名和密码。你的第一个 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 代码甚至不发送它们中的任何一个这一事实是一个更大的问题,但我假设您知道这一点,只是还没有编写该代码。)

这个问题实际上指向了解决这个问题的一种方法:如果您的任何消息都不允许包含换行符,您可以只使用换行符作为消息的终止符。您已经在 J​​ava 端这样做了;您只需要记住在发送时添加\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 recv阻塞与非阻塞error总结

[转]socket使用TCP协议时,sendrecv函数解析以及TCP连接关闭的问题

windows socket编程阻塞模式下,recv函数返回0?

socket 的recv函数返回0应该怎样处理

socket模块其他用法

Winsock recv() 函数阻塞其他线程