Hey I just started to learn android and my task was to make an application that sends and receives data from a python server. it sends the data perfectly but I can't make the client receive the data. please go easy on me I'm new here is my code:
Android Code:
class MyTask extends AsyncTask<Void, Void, Void> {
@SuppressLint(("Wrong Thread"))
@Override
protected Void doInBackground(Void... voids) {
try {
Log.d("ORI", "1- before connect");
sock = new Socket(LOCAL_HOST, PORT);
Log.d("ORI", "2 - after connect" );
prWriter = new PrintWriter(sock.getOutputStream());
prWriter.write(msg);
prWriter.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG);
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
And here is my Python server:
import socket
server_sock = socket.socket()
server_sock.bind(("0.0.0.0", 5024))
server_sock.listen(1)
client, addr = server_sock.accept()
print(addr[0])
flag = False
while True:
try:
data = client.recv(1024).decode()
except Exception as e:
print(str(e))
break
else:
if not flag:
if data == '':
pass
print(data)
try:
client.send("K".encode())
except Exception as e:
print(e)
else:
print("OK")
flag = True
server_sock.close()
CodePudding user response:
Here's an idea for a more flexible and reliable socket server in Python.
Reading from a socket can be challenging if you can't be certain just how much data to read. If one assumes, for example, that no messages will ever be longer than 1K then you might be tempted to recv(1024) but that's not reliable. To be specific, a client could send 800 bytes but the server might "see" fewer bytes with one call to recv().
So, what you need is a protocol that enables to server to know precisely how much data to expect.
One way to do this is to use a fixed length preamble to the message. We can utilise the pack/unpack functions (from the struct module) to build network independent integers which are sent before the actual message. The server knows to expect that preamble (which is of fixed length) and by unpacking that value can perform a recv() for a precise number of bytes.
The following example makes use of this paradigm by implementing an echo process whereby the server runs in its own thread, the client sends a message and the server immediately replies with whatever it received in the first place. In this example, the client ends with a "kill switch".
I'm probably opening myself up to all sorts of criticism but here goes anyway:
import socket
import threading
from struct import pack, unpack
HOST = 'localhost'
PORT = 7070
FORMAT = ('!Q', 8)
MSG = '''The Owl and the Pussy-cat went to sea
In a beautiful pea-green boat,
They took some honey, and plenty of money,
Wrapped up in a five-pound note.
The Owl looked up to the stars above,
And sang to a small guitar,
"O lovely Pussy! O Pussy, my love,
What a beautiful Pussy you are,
You are,
You are!
What a beautiful Pussy you are!"'''
def sendbuffer(s, b):
buffer = pack(FORMAT[0], len(b)) b
offset = 0
while offset < len(buffer):
offset = s.send(buffer[offset:])
def recvbuffer(s):
p = s.recv(FORMAT[1], socket.MSG_WAITALL)
n = unpack(FORMAT[0], p)[0]
return None if n == 0 else s.recv(n, socket.MSG_WAITALL)
def server():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, _ = s.accept()
with conn:
while (data := recvbuffer(conn)):
sendbuffer(conn, data)
def client(msg):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
sendbuffer(s, msg.encode())
data = recvbuffer(s)
print(data.decode())
sendbuffer(s, b'') # kill switch
def main():
threading.Thread(target=server).start()
client(MSG)
if __name__ == '__main__':
main()
N.B. This has been tested on macOS and may not work as expected on Windows
CodePudding user response:
Caused by: libcore.io.ErrnoException: connect failed: ETIMEDOUT (Connection timed out)
Your client tries to read a line using .readLine()
.
But.. is your server sending a line? Your server sends:
client.send("K".encode())
(That is only one character. Why not a big sentence?)
But anyhow it is only a line when the string ends with \n
.
So change to:
client.send("Hello World\n".encode())