Send keystrokes from android device to PC without "stutter" - android

I'm working on an android app that when a button in the app is pressed, sends a key stroke to a server listing on the PC. Everything is working fine expect for a problem of the output "stuttering" when the button is pressed rapidly. If on the client is press rapidly, the server will "stutter" and sometimes simply become unresponsive. The cod I'm using is extremely simple. To simple?
Server side:
ServerSocket welcomeSocket = new ServerSocket(6789);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
keyin = inFromClient.readLine();
robby.translateAndForward(keyin);
}
}
catch (Exception ex)
....
On the client
public class ImageBoundListener implements OnTouchListener {
private ImageView view;
private static PadClient client;
The On Touch Event handler
#Override
public boolean onTouch(View view, MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;;
if (client==null)
{
client=new PadClient();
}
if (action==MotionEvent.ACTION_DOWN)
{
client.sender("A");
}
Integer actionCode = action & MotionEvent.ACTION_MASK;
Log.d(actionCode.toString()," Event occured on: "+view.getTag());
return true;
}
}
The Actual send implementation
try{
Socket clientSocket = new Socket("192.168.1.104", 6789);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
System.out.println("Writing bytes to the server..");
outToServer.writeBytes(send);
clientSocket.close();
}
Not sure where to go from here...

There are several issues with your code:
Your code is opening connection every time button is pressed. If it is pressed rapidly - a lot of connections will be opened simultaneously between client and server.
It would be better to make one persistent connection and send all the data through it.
Also you can add some sort of buffering on the client side. I mean that data from several button presses will be combined into one data packet and sent to the server.
When dealing with communication problems between client and server - network I/O logging (what was sent and what was received on either side) is very important.
You server side can look like this:
try {
ServerSocket welcomeSocket = new ServerSocket(6789);
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
while(true) {
keyin = inFromClient.readLine();
Log.d("SERVER"," received: '" + keyin + "'");
robby.translateAndForward(keyin);
}
}
catch (Exception ex) {}

Related

server socket multithreading confuses with the devices

I'm writing an Android app using sockets for communication. In a class called sever I accept clients (android devices) and open sockets for them.
Server side:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Socket socket = serverSocket.accept();
Client clientThread = new Client(socket);
System.out.println("New client: " + clientThread.getName());
new Thread(clientThread).start();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
After a succesful connection the user may create a group, which is like a room for number of clients to connect and play together.
The group creation is done here:
Server side:
Client:
private void client_create() {
this.mGroup = new Group();
mGroup.joinPlayer(this);
System.out.println("New group for: " + name);
}
Group:
public Group(int nClients){
// Clients in this group
this.clients = new ArrayList<Client>();
}
public void joinPlayer(Client player){
clients.add(player);
}
Client Side:
Connection handling:
try {
socket = new Socket(hostName, portNumber);
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
Listener listener = new Listener();
new Thread(listener).start();
} catch (IOException e) {
e.printStackTrace();
}
I ran this programm on 2 android devices and on my localhost as the server. After the connection was made, I tried creating 2 independent different groups. While debugging it all seems legit until I reached to a point where I lost it due to the 2 different running threads.
The odd thing that happened is that after the first group was created with the first client (clients contains the first device client object), and then the second group with the second player (clients contains the second device client object), the first group clients array contains the second client object (from the second device).
Have you got any thoughts on that? Did I do something wrong?
Figured it out.
Clients was mistakly defined as static, so I guess when accessing to the clients array of the static object it received the last one who was created.

Android TCP app hanging on inStream.readline()

This is a continuation of this question because it my orginal question was answered, but it did not solve the bug.
Question:
How do I fix the code hanging on this line inStream.readline()
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:
It is reading and writing better, but still not working properly
What is happening now:
If outMessage is initialized with a value, upon connection with the server, the socket:
writes and flushes the value (server receives & responds)
updates value of outMessage (to null or to "x" depending on how i have it hard-coded)
reads and shows the response message from the server
re-enters for the next loop
IF i set outMessage to null, it skips over that if statements correctly then hangs; otherwise, if i set outMessage to a string (lets say "x"), it goes through the whole if statement, then hangs.
The code it hangs on is either of the inStream.readline() calls (I currently have one commented out).
Additional info:
- once connected, I can type in the "send" box, submit (updates the outMessage value), then disconnect. Upon re-connecting, it will read the value and do the sequence again until it get stuck on that same line.
Changes since the referenced question:
- Made outMessage and connectionStatus both 'volatile'
- added end-of-line delimiters in neccesary places.
Code:
public void run() {
while (connectionStatus != TCP_SOCKET_STATUS_CONNECTED) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (connectionStatus == TCP_SOCKET_STATUS_CONNECTED) {
try {
if (outMessage != null){
OutStream.writeBytes(outMessage + "\n");
OutStream.flush();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "OUT TO SERVER: " + outMessage);
outMessage = "x";
}
Thread.sleep(100);
// if (InStream.readLine().length() > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "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() {
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) {
connectionFailed();
} catch (SocketTimeoutException e) {
connectionFailed();
} catch (IOException e) {
// Close the socket
try {
tempSocketClient.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
}
Server:
public static void main(String[] args) throws IOException {
String clientSentence;
String capitalizedSentence;
try {
ServerSocket welcomeSocket = new ServerSocket(8888);
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n Listening on IP: " + SERVERIP +"\n\n");
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
while(true)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clientSentence = inFromClient.readLine();
System.out.println("clientSentance == " + clientSentence);
String ip = connectionSocket.getInetAddress().toString().substring(1);
if(clientSentence != null)
{
System.out.println("In from client ("+ip+")("+ System.currentTimeMillis() +"): "+clientSentence);
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence + '\n');
System.out.println("Out to client ("+ip+"): "+capitalizedSentence);
}
}
} catch (IOException e) {
//if server is already running, it will not open new port but instead re-print the open ports information
SERVERIP = getLocalIpAddress();
System.out.println("Connected and waiting for client input!\n");
System.out.println("Listening on IP: " + SERVERIP +"\n\n");
}
}
Thanks in advance!
Edits:
added the server code after updating
I tried messing around with setting the SoTimout for the socket but took that back out
Your server is specifically designed to receive exactly one line from a client and send exactly one line back. Look at the code:
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");
}
Notice that inside the loop it accepts a new connection, reads exactly one line, and then writes exactly one line. It doesn't close the connection. It doesn't sanely end the conversation. It just stops reading.
A client that worked with this server would have to connect, send exactly one line, read exactly one line back, and then the client would have to close the connection. Your client doesn't do that. Why? Because you had no idea that's what you had to do. Why? Because you had no design ... no plan.
So that's your specific issue. But please, let me urge you to take a huge step back and totally change your approach. Before you write a single line of code, please actually design and specify a protocol at the byte level. The protocol should say what data is sent, how messages are delimited, who sends when, who closes the connection, and so on.
Otherwise, it's impossible to debug your code. Looking at the server code above, is it correct? Well, who knows. Because it's unclear what it's supposed to do. When you wrote the client, you assumed the server behaved one way. Was that assumption valid? Is the server broken? Who knows, because there's no specification of what the server is supposed to do.
You need to check if there is data available:
if (InStream.available > 0) {
String modifiedSentence = InStream.readLine();
sendMessageToAllUI(0, MAINACTIVITY_SET_TEXT_STATE, "appendText" , "IN FROM SERVER: " + modifiedSentence);
}
But to be honest, even that is not ideal because you have no gurantee that the eond-of-line will have been received. If the server sends a few bytes but never sends the end-of-line then you will still be blocking forever. Production socket code should never rely on readLine but instead read into a buffer and check that buffer for end-of-line (or whatever criteria your protocol needs).
Didn't read closely enough, I thought InStream was an InputStream instance. InputStream has available. InputStreamReader has ready (which in turn calls InputStream.available. As long as you keep a refernce to either of these then you can see if data is available to be read.

Handling all clients in a java Socket Server

I have a server and i am trying to send to all clients a specific input(string). My code is here:
serverSocket = new ServerSocket(SERVERPORT);
while (true)
{
// listen for incoming clients
Socket client = serverSocket.accept();
mClients.add(client);
boolean finished = false;
try
{
for (int i=0; i<mClients.size(); i++)
{
Socket well = mClients.get(i);
DataInputStream in = new DataInputStream(well.getInputStream());
PrintStream out = new PrintStream(well.getOutputStream());
// Print a message:
System.out.println("Client from : " + client.getInetAddress() + " port " + client.getPort());
// now get the input from the socket...
while(!finished)
{
String st = in.readLine();
// Send the same back to client
out.println(st);
// Write it to the screen as well
System.out.println(st);
// If the input was "quit" then exit...
if (st.equals("quit")) { finished = true; System.out.println("Thread exiting..."); }
}
}
As it seems i am doing something wrong. Anyway i am trying to store all the connected sockets to a vector and then send them the string received by one of them. Is this the right approach?
In the first while(true) statement, only listen for incoming connections and then create a separate thread to handle that client connection.
From there, you could add each outPutStream you create, within each thread, into an global ArrayList. Loop through the arrayList(create a method for this with a String Parameter) and write whatever message you want to within said method.
Check out this Oracle Tutorial on Socket Communication for help

android TCP client unable to display data sent from C Server via wi-fi

I'm kinda new to android socket programming. My android program simply connects to a server (written in c,executed in the console) and must display the content being sent from the server (something like "hi client"). I have textview's for displaying whether the connection is being established or not and another edittext for sending the client's message to the server. The system is connected via Wi-fi. The server is able to recieve messages from my android client but android client is not displaying the message sent by the server. The code snippet for the reading from server part is:
private TextView MsgFromServer; //defination
// here is the code for the connection and starting new thread etc
final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
handler.post(new Runnable() {
#Override
public void run() {
try {
while((line=in.readLine())!=null){
MsgFromServer.append(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Also I tried doing something like this:
final BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
line=in.readLine().toString(); //string type
handler.post(new Runnable() {
#Override
public void run() {
MsgFromServer.setText(line);
}
}
both approaches are not working for me.The message I send from the client to the server reaches there properly whereas the other direction communication is not happening. Also I've tested my C server with a simple C client and the message passing is happening smoothly.
How does the client behave? Is it waiting at in.readLine() ?
Be sure the server sends "Hi client\n" (with the lineend).
in.readLines() only returns when a lineend \n is found.
Is the new Runnable running? If you change the code
a little to
try {
MsgFromServer.append("going to read a line..");
while((line=in.readLine())!=null){
MsgFromServer.append(line);
}
then do you see that?

Problems sending and receiving data over TCP socket

I am having problems trying to use my android (Basic4Android) to communicate with my PC running a .net TCP server. I need to be able to have buttons that send 4byte commands to the server and receive back a response. When I run the program on the android the server does connect and receives the string "INFO", but then nothing else sends or receives until I restart the program and it only sends the command "INFO" again. I don't get any errors when I press the buttons to send commands, but the server never receives anything. The server is a Windows form multi-thread program written in VB.NET. I wrote a VB.NET client program that works that I can attach as an example of what I am trying to do. This is my first attempt at a Android application and so far I am just modifing the network examples I found in the tutorials.
The code is below...
Thanks
Sub Process_Globals
Dim Socket1 As Socket
End Sub
Sub Globals
Dim Button_ARM As Button
Dim Button_STAY As Button
Dim Button_AUTO As Button
Dim Button_OFF As Button
Dim Label_Received As Label
Dim Label_Sent As Label
Dim tr As TextReader
Dim tw As TextWriter
Dim sb As StringBuilder
End Sub
Sub Activity_Create(FirstTime As Boolean)
Activity.LoadLayout("Alarm_Control")
Socket1.Initialize("Socket1")
Socket1.Connect("#.#.#.#" , 8000, 20000) 'My IP address goes here
End Sub
Sub Socket1_Connected (Successful As Boolean)
If Successful = False Then
Msgbox(LastException.Message, "Error connecting")
Return
End If
tr.Initialize(Socket1.InputStream)
tw.Initialize(Socket1.OutputStream)
tw.WriteLine("INFO")
Label_Sent.Text = "Sent INFO"
tw.Flush
sb.Initialize
sb.Append(tr.ReadLine)
Label_Received.Text = sb.ToString
'Socket1.Close
End Sub
Sub Button_ARM_Click
tw.WriteLine("O001")
tw.Flush
Label_Sent.Text = "Sent O001"
End Sub
Sub Button_STAY_Click
tw.WriteLine("O002")
tw.Flush
Label_Sent.Text = "Sent O002"
End Sub
Sub Button_OFF_Click
tw.WriteLine("O000")
tw.Flush
Label_Sent.Text = "Sent O000"
End Sub
How are you reading the data in the server side? Note that TextWriter.WriteLine writes a line terminated with chr(10). Make sure that you are not waiting for chr(13) and chr(10).
I am using networkStream.read and networkStream.write in a thread called by the listner. The vb.net client program work correctly with the vb.net server.
Public Sub handlerThread()
Dim handlerSocket As Socket
handlerSocket = alSockets(alSockets.Count - 1)
Dim networkStream As NetworkStream = New NetworkStream(handlerSocket)
Dim bytes(4) As Byte
networkStream.Read(bytes, 0, CInt(4)) ' Read the stream into 4-byte array
Dim clientdata As String = Encoding.ASCII.GetString(bytes)
Label_Received.Text = clientdata
Dim responseString As String = "Received " + clientdata
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(responseString)
networkStream.Write(sendBytes, 0, sendBytes.Length)
Label_Sent.Text = responseString
handlerSocket = Nothing
End Sub
Chr(10) does not seem to be an issue here.
I'm having the same problem using this java server code:
import java.io.*;
import java.net.*;
public class ec192 {
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket("192.168.0.45", 2222);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: taranis.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: 2222 taranis.");
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}
}

Categories

Resources