2

I am writing a simple TCP server program. Everything is working properly, but the function recv() isn't.

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()

When I comment all calls to recv(), the program is working properly, but when I want to receive answers from my client (android client on a smartphone), the program is blocking itself (I think that recv() is waiting for the message). I know that I have to set timeout, but it doesn't solve my problem. I want to send the message first and then receive something. Why does recv() block sendall()?

Android listener function:

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";
    }
}`
10
  • 2
    First, while I don't think this is the problem you're asking about (although it might be), it is a problem you need to fix: TCP sockets are byte streams, not message streams. A recv may get half a send, or three sends combined into one buffer. Commented May 6, 2015 at 15:04
  • Looking at your code more closely, that definitely could be the issue. The client sends you username and password. Your first recv gets both. Your second recv waits forever for more data, but the client isn't sending any more because you already got everything. Commented May 6, 2015 at 15:05
  • To diagnose this, try to print the username; if it's the username and password crammed together, that's the whole problem. (And again, even if that isn't the whole problem, it's still a problem that you have to fix.) Commented May 6, 2015 at 15:06
  • As a side note, this is clearly Python 3. That means recv is giving you bytes, not str; you have to decode it to do anything useful. Even just print is going to give you b'Franky' instead of the Franky you'd want. Commented May 6, 2015 at 15:08
  • I know that tcp sockets are byte streams. On my client i dont receive anything. To stop program i have to hit ctrl+c twice instead of once. And after i stop program i receive my welcome message on android client. Commented May 6, 2015 at 15:17

1 Answer 1

2

On the Python server, you send this:

data="#1111#Welcome on Server!"
sock.sendall(data.encode('ascii'))

On the Java client, you read like this:

inp = in.readLine(); 

That readLine keeps reading until it finds a newline character. But you never send a newline character. So it keeps reading forever.


You have other problems that you need to fix here.

For example, your Python code assumes that TCP sockets are message streams when they're actually byte streams, so your username = sock.recv(1024) may get both the username and password, causing the next recv to block forever, or it may get half the username and cause a spurious login failure, or anything else you can imagine. (Of course the fact that the Android code doesn't even send either of them is an even bigger problem, but I assume you knew that and just haven't written that code yet.)

And that problem actually points to one way to solve this problem: If none of your messages are allowed to contain a newline, you can just use newlines as terminators for the messages. You're already doing this on the Java side; you just need to remember to add a \n when sending. On the Python side, the makefile method on sockets gives you a file-like object, pretty similar to what you're doing in Java, which has a readline method, so you can do the same thing in the other direction.

Sign up to request clarification or add additional context in comments.

4 Comments

I wrote this protocol before asking here. But it didnt working as well as code i showed here. I commented second recv(), but it didnt help. Still when program is working i dont receive anything on my phone, but when i close python program (by hitting ctrl+c twice) i immediately receive "#1111#Welcome on Server!"
@Franky: I don't understand what you mean. What exactly did you write before asking here? And how could it not work as well as the code you showed here, when the code you showed here doesn't work at all?
@Franky: Meanwhile, the reason you see the data on the Android after hitting ^C^C is that the socket gets closed, and readline will return the last incomplete line at EOF. That isn't going to help you solve this problem, unless you want to disconnect and reconnect for every message. You need to add the \n on the message from the server.
That was a problem with missing '\n' on the end of string, thanks ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.