DataOutputStream: dos.write() in loop, Receiver receives only one data package - java

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

Using Socket in threads in java on android device when 2 requests required in a execution loop

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.

Reliable UDP in 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.

How I can send an String and an Integer over a socket?

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.

Multithreaded data transfer via an array in Java

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.

Reading inpustream

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.

Categories

Resources