I have a problem with my TCP connection. I send data (a simple string) via a smartphone to a tablet by a TCP socket connection. The connection works fine and data is transmitted as expected. But when I do a loop and in every iteration dos.write() is fired only one packages arrive on the tablets data receiver. What am I doing wrong?
Here's the sending part of my connection. It iterates through the list and writes every data to the DataOutputStream.
for(int i = 0; i <= logList.length - 1; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos = new DataOutputStream(s.getOutputStream());
dos.writeUTF(backupPayload);
dos.flush();
dos.close();
On the tablet I receive the data via this code snippet:
#Override
public void run() {
try {
while(true){
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
As I said the connection works fine when I send only one data package. But if I want to send multiple packages inside the loop only the first package will arrive at the destination.
Can anyone help me? :)
Calling close() on a DataOutputStream closes its associated OutputStream, and closing a socket's OutputStream closes the socket. This is documented behavior.
But, that should be OK, because your receiver code is only expecting to receive 1 single string anyway. You are calling dis.readUTF() only one time per TCP connection.
If you want to send multiple strings in a single connection, DON'T call dos.close() on the sending side (at least until all of the strings have been sent), and DO call dis.readUTF() in a loop on the receiving end until all strings have been received.
dos = new DataOutputStream(s.getOutputStream());
for(int i = 0; i < logList.length; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos.writeUTF(backupPayload);
}
dos.flush();
dos.close();
#Override
public void run() {
try {
while (true) {
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
try {
while (true) {
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
} catch (IOException e) {
}
dis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Alternatively, send the list length before sending the actual strings, and then read the length before reading the strings:
dos = new DataOutputStream(s.getOutputStream());
// maybe other things first...
dos.writeInt(logList.length);
for(int i = 0; i < logList.length; ++i){
String backupPayload = invertLogStringToJson(logList[i]);
dos.writeUTF(backupPayload);
}
dos.flush();
// maybe other things next...
dos.close();
#Override
public void run() {
try {
while (true) {
mySocket = ss.accept();
dis = new DataInputStream(mySocket.getInputStream());
try {
// maybe other things first...
int length = dis.readInt();
for (int i = 0; i < length; ++i) {
message = dis.readUTF();
handler.post(() -> {
bufferIntentSendCode.putExtra("data", message);
ctx.sendBroadcast(bufferIntentSendCode);
});
}
// maybe other things next...
} catch (IOException e) {
}
dis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Related
I need to send two (2) requests do an hardware device requestA and requestB, these have to be executed consecutively in a thread while loop but have encountered a problem that I do not understand yet, I am still very new to java and android, the main hurdle I had is resolved and working very well atm so, on to the next hurdle.
This is my code for the thread..
public void ExecThread(String requestA, String requestB, TextView tv ) {
TextView te = tv;
Runnable runnable = new Runnable()
{
String readA = null;
String readB = null;
int count = 5;
byte[] BytesOf = new byte[255];
#Override
public void run()
{
try {
while(count != 0)
{
DataInputStream dis;
Socket socket = new Socket(ip, port);
OutputStream out = socket.getOutputStream();
PrintWriter output = new PrintWriter(out, true);
output.println(requestA);
// get response from socket
dis = new DataInputStream(socket.getInputStream());
dis.readFully(BytesOf, 0, 255);
dis.close();
// convert BytesOf to String readA
readA = new String(BytesOf,0,255);
socket = new Socket(ip, port);
output.println(requestB);
// get response from socket
dis = new DataInputStream(socket.getInputStream());
**dis.readFully(BytesOf, 0, 255); -----> hangs here (I assume waiting for response from device)**
dis.close();
readB = new String(BytesOf, 0, 255);
if (readA != null && readA.length() >= 250)
{
te.setText( String.valueOf(count) + " - " + (CharSequence) readA.substring(4, 16));
_fields.SetEkmFieldValueStrings(readA, readB);
}
socket[0].close();
count--;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
The question I have is, what do I need to do to keep a socket open and get 2 responses from 2 requests, is there a best practice approach for what I am wanting to do?
I accept that I may be doing things wrong so, please point me in the right direction.
Thanks in advance
Problem solved, solution to problem was simply to set out = socket.getOutputStream()
My modified code that works for sending 2 requests consecutively and receiving correct response strings from the hardware device is shown
Runnable runnable = new Runnable()
{
String readA = null;
String readB = null;
int count = 5;
byte[] BytesOf = new byte[255];
String endRequest = "01!\r\n";
#Override
public void run()
{
try {
while(count != 0)
{
DataInputStream dis;
Socket socket = new Socket(ip, port);
OutputStream out = socket.getOutputStream();
PrintWriter output = new PrintWriter(out, true);
output.println(requestA);
// get response from socket
dis = new DataInputStream(socket.getInputStream());
dis.readFully(BytesOf, 0, 255);
output.flush();
output.println(endRequest);
// convert BytesOf to String readA
readA = new String(BytesOf,0,255);
out = socket.getOutputStream(); // HERE
output.flush();
output.println(requestB);
// get response from socket
dis.readFully(BytesOf, 0, 255);
dis.close();
readB = new String(BytesOf, 0, 255);
if (readA != null && readA.length() >= 250)
{
te.setText( String.valueOf(count) + " - " + (CharSequence) readA.substring(4, 16));
_fields.SetEkmFieldValueStrings(readA, readB);
}
socket.close();
count--;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
Onto the next problem confirming the checksum value of readB is correctly calculated, readA has already been confirmed correct.
Slowly getting to understand java.
I am working on my assignment to make UDP reliable using java. How can i add Timeout and re-transmission to handle data-grams that are discarded and add Sequence numbers so the client can verify that a reply is for the appropriate request ??
this is client code
import java.net.*;
import java.io.*;
public class EchoClient {
// UDP port to which service is bound
public static final int SERVICE_PORT = 7;
// Max size of packet
public static final int BUFSIZE = 256;
public static void main(String args[]){
if (args.length != 1)
{
System.err.println ("Syntax - java EchoClient hostname");
return;
}
String hostname = args[0];
// Get an InetAddress for the specified hostname
InetAddress addr = null;
try
{
// Resolve the hostname to an InetAddr
addr = InetAddress.getByName(hostname);
}
catch (UnknownHostException uhe)
{
System.err.println ("Unable to resolve host");
return;
}
try
{
// Bind to any free port
DatagramSocket socket = new DatagramSocket();
// Set a timeout value of two seconds
socket.setSoTimeout (2 * 1000);
for (int i = 1 ; i <= 10; i++)
{
// Copy some data to our packet
String message = "Packet number " + i ;
char[] cArray = message.toCharArray();
byte[] sendbuf = new byte[cArray.length];
for (int offset = 0; offset < cArray.length ; offset++)
{
sendbuf[offset] = (byte) cArray[offset];
}
// Create a packet to send to the UDP server
DatagramPacket sendPacket = new DatagramPacket(sendbuf, cArray.length, addr, SERVICE_PORT);
System.out.println ("Sending packet to " + hostname);
// Send the packet
socket.send (sendPacket);
System.out.print ("Waiting for packet.... ");
// Create a small packet for receiving UDP packets
byte[] recbuf = new byte[BUFSIZE];
DatagramPacket receivePacket = new DatagramPacket(recbuf, BUFSIZE);
// Declare a timeout flag
boolean timeout = false;
// Catch any InterruptedIOException that is thrown
// while waiting to receive a UDP packet
try
{
socket.receive (receivePacket);
}
catch (InterruptedIOException ioe)
{
timeout = true;
}
if (!timeout)
{
System.out.println ("packet received!");
System.out.println ("Details : " + receivePacket.getAddress() );
// Obtain a byte input stream to read the UDP packet
ByteArrayInputStream bin = new ByteArrayInputStream (
receivePacket.getData(), 0, receivePacket.getLength() );
// Connect a reader for easier access
BufferedReader reader = new BufferedReader (
new InputStreamReader ( bin ) );
// Loop indefinitely
for (;;)
{
String line = reader.readLine();
// Check for end of data
if (line == null)
break;
else
System.out.println (line);
}
}
else
{
System.out.println ("packet lost!");
}
// Sleep for a second, to allow user to see packet
try
{
Thread.sleep(1000);
}catch (InterruptedException ie) {}
}
}
catch (IOException ioe)
{
System.err.println ("Socket error " + ioe);
}
}
}
What you can do is adding import TCP headers like sequence number, windows into the UDP message body to make it more like TCP. Here is the a solution that might help you.
I have 2 buttons in my client with a button listener each.
In my firt button listener I am sending a String over the socket and I am getting back an array of integers after it is spanwed. No problem there. Here is my code.
public void rollDice() {
try {
DataOutputStream sout1 = new DataOutputStream(socket.getOutputStream());
String line = "dice";
PrintStream out1 = new PrintStream(sout1);
out1.println(line);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
With the second listener I want t send first a string to put the server into the right state, and after I want to send an integer to continue the process. Here is my code but it doesn't seem to work. Server is printing a random number, even if I send a "2".
public void sendDice() {
try {
DataOutputStream sout2 = new DataOutputStream(socket.getOutputStream());
String line = "pick";
PrintStream out2 = new PrintStream(sout2);
out2.println(line);
out2.write(diceListLength);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
Here is the server's side.
public void run() {
boolean running = true;
try {
// Create streams for reading / writing lines of text to the socket
DataInputStream input = new DataInputStream(s.getInputStream());
DataInputStream inputInt = new DataInputStream(s.getInputStream());
ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());
// Print a message:
System.out.println("\nClient from: " + s.getInetAddress() + " port " + s.getPort());
while(running) {
String st = input.readLine();
if (st.equals("dice")) {
for (int i = 0; i < diceRolled.length - number; i++) {
diceRolled[i] = (int) ( 1 + Math.random() * 6);
System.out.print(diceRolled[i] + " ");
}
output.writeObject(diceRolled);
output.reset();
} else if (st.equals("pick")) {
number = inputInt.readInt();
System.out.print(number);
}
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
// Always be sure to close the socket
} finally {
try {
if (s != null) {
System.out.println(s.getLocalSocketAddress() + " closed.");
s.close();
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Try setting autoFlush on the PrintStream when you create it... a single integer will not be sent until newline or buffer full.
From java's documentation
autoFlush - A boolean; if true, the output buffer will be flushed whenever a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written
Also useful:
Use line-based messaging, i.e. the second message type can be "pick:4" (check with st.startsWith("pick")) and then parse the integer. With your code, you can easily end up loosing state. (Single-line messages are "pseudo-atomic").
Don't create DataInputStreams in every listener method, make them object variables (same for PrintStreams...). There's no need to (re)create objects in every click.
So, I guess that this has been answered before, but I couldn't find the question, so forgive me.
I have a rather basic chat client-server pair, of which the server is multithreaded to allow for several clients to connect at the same time. The server code looks like this...
private void loop(int port) {
// Opens a port for connections.
ServerSocket serverSocket = null;
Socket clientSocket = new Socket();
try {
serverSocket = new ServerSocket(port);
System.out.println("Server running in port " + port);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Listens for a connection
while (onlineState == true && serverSocket != null) {
if (cur_players < max_players) {
try {
clientSocket = serverSocket.accept();
System.out.println(clientSocket.getInetAddress() + " has connected to the port " + clientSocket.getPort());
cur_players++;
new Thread(new SocketThread( clientSocket, Chat.getOpenSeat() )).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Here, what Chat.getOpenSeat() does is browse an array(boolean seats[]) through for an open spot in the chat buffer array (String buffer[][]) and returns an integer for the spot, then marking it taken. However, when I access the buffer array from the threads, the thread only finds the messages it has added itself. Below is the corresponding code.
toClient = c.poll(bufferSocket); // Retrieves the top-most message from the seat's sub-array,
// then bumps the remaining messages up in the sub-array.
if (toClient != null) {
out.println(toClient); // Sends the message through the Socket.
System.out.println("Message was sent.");
toClient = null;
}
Curiously enough, the threads can access the seats[] array without any trouble, finding the currently active seats and correctly giving all the corresponding sub-arrays their messages. Here's also the bit of code I use to add a new message to the array:
public void offer(String msg) {
for (int seat = 0; seat < Server.max_players; seat++) {
if (seats[seat] == true) {
for (int i = 0; i < 100; i++) {
if (msgBuffer[seat][i] == null) {
msgBuffer[seat][i] = msg;
System.out.println("Message: '" + msg + "' was buffered for the Seat " + seat + ".");
break;
}
}
}
}
}
So, how do I add Strings to an array that is commonly read-write accessible to all of my threads?
Just ask if you need to see more of the code.
Make the array volatile, and it will behave concurrent.
More on volatile: http://www.javamex.com/tutorials/synchronization_volatile.shtml.
i am trying to send integers to Android device via Bluetooth communication. My question is how do i read array of charcters from the inpustream?
This is a partion of my server code Java:
try {
outStream = connection.openOutputStream();
int numbers = (int) (Math.random() * 10);
outStream.write(numbers);
System.out.println(numbers);
} catch (IOException e) {
e.printStackTrace();
}
The objective is to Android reads the integers that the server sends. I have also tryd to use PrintWriter method to send data(randome numbers) like this:
outStream = connection.openOutputStream();
pWriter = new PrintWriter(new OutputStreamWriter(outStream));
int numbers = (int) (Math.random() * 10);
pWriter.write(numbers);
System.out.println(numbers);
pWriter.flush();
pWriter.close();
if use this method print.write, i know that this it send only single charchters, so my question is how do i send array of charchters to Android?
this the portion of my Android code:
public void run() {
int data = in.read(buffer);
while (true) {
try {
byte[] buffer = new byte[1024];
int data;
data = in.read(buffer);
data = in.read(buffer, 0, buffer.length);
} catch (IOException ex) {
Log.e(TAG_IOThread, "disconnected", ex);
break;
}
}
}
It was indeed the DataOutpustream, i used writeInt() method and on the server i changed to readInt(); I thought it was posibble to use OutputStream to send integers and InputStream to receive it.