I have been trying various implementations to make this work, and have searched StackOverflow and Android Developers for a solution, but I am not too experienced in programming and cannot get this block to code to work properly.
My Intent:
- This is in a thread that will loop through checking if there is an outMessage, if there is, it will send the message.
- Next it will check it if there is anything in the in-stream, if there is, it will send it to the handler in my main activity.
- Lastly, it will sleep for 1 second, then check again.
- This should allow me to read/write multiple times without needing to close and open the socket.
Problem:
- The outstream does not get flushed until I close the socket. flush() seems to have no effect.
My request:
- Please post the changes required to get this code working properly as described above (any annotations to explain WHY would be greatly appreciated. Links to other similar questions/answers would be great to help me learn, but i have been looking at those for a couple weeks and just cant get it to work, so please make sure you also include the changed this code needs in order to work as described above. Thanks in advance.
Other:
- I am wondering if my instream &/or outstream need to look for end-of-line characters?
- Would something like TCP_NODELAY be used here?
- Any extra info that can be given will be very appreciated. I want to learn this stuff well, but I currently cannot get anything to work.
Code:
public void run() {
while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
try {
if (outMessage != null){
OutStream.writeBytes(outMessage);
OutStream.flush();
outMessage = ("OUT TO SERVER: " + outMessage);
// socketClient.close();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , outMessage);
outMessage = null;
}
if (InStream != null) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "\n" + "IN FROM SERVER: " + modifiedSentence);
}
Thread.sleep(1000);
} catch (IOException e) {
connectionLost();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The thread that makes the socket:
public void run() {
if(I) Log.i(LOGTAG, "Attempt Connection with IP: " + serverIP + " ...");
setName("AttemptConnectionThread");
connectionStatus = TCP_SOCKET_STATUS_CONNECTING;
try {
SocketAddress sockaddr = new InetSocketAddress(serverIP, port);
tempSocketClient = new Socket(); // Create an unbound socket
// This method will block no more than timeoutMs. If the timeout occurs, SocketTimeoutException is thrown.
tempSocketClient.connect(sockaddr, timeoutMs);
OutStream = new DataOutputStream(tempSocketClient.getOutputStream());
InStream = new BufferedReader(new InputStreamReader(tempSocketClient.getInputStream()));
socketClient = tempSocketClient;
socketClient.setTcpNoDelay(true);
connected();
} catch (UnknownHostException e) {
if(I) Log.i(LOGTAG," ...UnknownException e: e.getMessage() shows: " + e.getMessage());
connectionFailed();
} catch (SocketTimeoutException e) {
if(I) Log.i(LOGTAG," ...SocketTimoutException e: e.getMessage() shows: " + e.getMessage());
connectionFailed();
} catch (IOException e) {
if(I) Log.i(LOGTAG," ...caught on run()");
// Close the socket
try {
tempSocketClient.close();
} catch (IOException e2) {
Log.e(LOGTAG, "unable to close() socket during connection failure", e2);
}
if(I) Log.i(LOGTAG," ...IOException e: e.getMessage() shows: " + e.getMessage());
connectionFailed();
return;
}
}
The java server I found online and am using until I port this over to the real server:
public class Server {
private static String SERVERIP;
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
String clientSentence;
String capitalizedSentence;
try {
ServerSocket welcomeSocket = new ServerSocket(8888);
getIp();
System.out.println("Connected and waiting for client input!\n");
while (true) {
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
String ip = connectionSocket.getInetAddress().toString()
.substring(1);
System.out.println("In from client (" + ip + "): "
+ clientSentence);
if (clientSentence != null) {
capitalizedSentence = clientSentence.toUpperCase() + '\n';
System.out.println("Out to client (" + ip + "): "
+ capitalizedSentence);
outToClient.writeBytes(capitalizedSentence + "\n");
}
}
} catch (IOException e) {
// if server is already running, it will not open new port but
// instead re-print the open ports information
getIp();
System.out
.println("Server connected and waiting for client input!\n");
}
}
private static void getIp() {
InetAddress ipAddr;
try {
ipAddr = InetAddress.getLocalHost();
System.out.println("Current IP address : "
+ ipAddr.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
Since these are short messages (
< MSS
), I guess the stack may be implementing Nagle's algorithm. Is the server doing some kind of delayed ACKs? If possible you should capture a trace and see if there are pending acknowledgements from the other side.In either case,
TCP_NODELAY
should help.I suspect you are reading lines at the consumer, but you aren't writing lines, so the consumer blocks until it gets EOS and delivers one big line. Add line terminators when sending as necessary.