Java Socket Communications Error - java

On a high level, we are using TCP to communicate between two clients on a network. The clients are operating under different languages.
Our messaging workflow is as follows:
C++ initiates a command
Java reads the command
Java does some simple logic
Java responds
We have started to see more and more discrepancies with what the C++ code is sending, and what the Java code is receiving.
In order to track down this error, we have placed multiple logging statements and a Wireshark profile to attempt to capture as much data as possible to track the message.
C++ logs show that the command is being sent as "123,abc,def,456"
Debugging the C++ shows that the byte order of the characters matches this, as the command to write to the socket is being fired.
Wireshark shows the message coming through as "123,abc,def,456"
Java reads from the socket, and shows that the message is jumbled. We have gotten messages such as:
"123,abc,def,456" (correct)
"bc,def,456"(truncated)
"1a2,3bdfec,4,56"(completely mangled)
Example of the C++ code
while ( Client->Connected && !bolExitNow){
data =S"";
Threading::Thread::Sleep(15);
bolReadStream = !bolReadStream;
if (!(bolReadStream && stream->DataAvailable )){
if (sharedInfo->CutSocketClientPort == RemotePort){
if (lbSocketMessages->read(&data)){ //the read() assigns stuff to data so that it's not an empty string anymore
bytes1 = Text::Encoding::ASCII->GetBytes( data);
stream->Write( bytes1, 0, bytes1->Length );
if (sharedInfo->curAcknowledgeItem->SendMessageType->CompareTo(data->Substring(7,2)) == 0){
sharedInfo->LastXXMsgTime = DateTime::Now ;
}
}
lbSocketMessages->acknowledge();
sharedInfo->WriteLog ( String::Format("{0} Sent msg: {1}",System::DateTime::Now.ToString("yyyyMMddHHmmss.fff"),data));//log write; This shows correct format message
}
}
continue;
}
Example of the java code
/** Shared read buffer. */
ConcurrentLinkedQueue<String> buffer = new ConcurrentLinkedQueue<String>();
//Instantiation
Socket client;
try{
client = new Socket(serverAddress, serverPort);
sock[thread] = new SocketMagic(client);
sock[thread].setMonitoring(false);
sock[thread].setHeartbeat("");
} catch (Exception e){
e.printStackTrace();
}
//Usage
while (!done){
if (socket[thread] != null && socket[thread].isAlive()){
message = socket[thread].getLine(MAX_DELAY_INTERVAL);
if(message!=null){
logger.log("RECEIVING ON {" + thread + "}: " + message);//displays incorrect message data
buffer.add(message);//Buffer for processing messages
}
}
//...
//logic
//...
if (buffer != null){
message = buffer.poll();
if (message != null){
response = processMessage(message,thread);//obviously wrong, as we read in incorrect information above.
}
}
}
SocketMagic library getline method is listed as
public String getLine()
{
return getLine(true, 0);//Always enable blocking
}
public String getLine(final boolean blocking, final int maxwait)
{
// to block, or not to block (while waiting for data)
StringBuilder buffer = new StringBuilder();
int character;
boolean messageStarted = false;
try
{
if (blocking)
{
int wait = 0;
while (maxwait <= 0 || wait < maxwait)
{
while (sockIn.ready())
{
character = sockIn.read();
if (character == STX)
{
if (!messageStarted)
{ // if no message started
messageStarted = true; // start a message
} else
{
buffer.setLength(0); // clear message buffer
}
continue; // don't add STX to buffer
}
// ignore characters prior to message start
if (!messageStarted)
{
continue;
}
// if not end of message, keep reading
if (character != ETX)
{
// append to buffer
buffer.append((char) character);
continue;
}
// if the message is a heartbeat, keep reading
if (buffer.toString().equals(heartbeat))
{
buffer.setLength(0); // clear buffer
messageStarted = false;
continue;
}
// we've got a complete message, return it
return buffer.toString();
}
// sleep loop to avoid CPU wasting
try
{
wait += SLEEPSTEP;
Thread.sleep(SLEEPSTEP);
if (monitor && (wait % (HEARTBEATINTERVAL)) == 0)
{
if (!sockOut.write(heartbeat))
{
return null;
}
}
} catch (InterruptedException ie)
{
return null;
}
} // ENDOF while ( !sock_in.ready() )
} // ENDOF if (blocking)
// set mark, if supported (which it should be)
if (sockIn.markSupported())
{
sockIn.mark(READAHEADSIZE);
}
while (sockIn.ready())
{
character = sockIn.read();
if (character == STX)
{
if (!messageStarted)
{ // if no message started
messageStarted = true; // start a message
} else
{
buffer.setLength(0); // clear message buffer
}
continue; // don't add STX to buffer
}
// ignore characters prior to message start
if (!messageStarted)
{
continue;
}
// if not end of message, keep reading
if (character != ETX)
{
buffer.append((char) character); // add char to buffer
continue;
}
// if we read a heartbeat message, keep reading
if (buffer.toString().equals(heartbeat))
{
// System.out.println("DEBUG: HEARTBEAT");
buffer.setLength(0);
messageStarted = false;
// set new mark position for input stream
if (sockIn.markSupported())
{
sockIn.mark(READAHEADSIZE);
}
continue;
}
// we've got a complete message, mission accomplished!
// return buffer.substring(1, buffer.length() - 1);
return buffer.toString();
} // ENDOF while (sockIn.ready())
// incomplete message, reset the mark, if supported
if (sockIn.markSupported())
{
sockIn.reset();
}
return null; // no message or incomplete message
} catch (IOException ioe)
{
return null;
}
} // ENDOF public String getLine(boolean blocking, int maxwait)

Related

Using the OutputStream of the Bluetooth connection in an other thread disturbs receiving of messages

I followed the Android Guide to build a Bluetooth connection.
To separate things and make them independent, I decided to take the sending part of the BT to a separated thread. To achieve this, I pass the "OutStream" of the BT-Socket to a separated Thread class. My problem is, as soon as I start this thread, the incoming messages are not well red anymore.
But I don't know why, because I do not use this Thread at the moment. It is started but no messages are written in it.
This is part of the "ConnectedToDevice"-Class which receives the messages. I use a special way to detect that my Messages are received completely.
public void run() {
byte[] buffer = new byte[1024];
int bytes;
sendPW();
int len = 0;
Communication.getInstance().setFrequentSending(OVS_CONNECTION_IN_PROGRESS);
Communication.getInstance().setSendingMessages(mmOutStream); //Passing the OutStream to the sending class.
Communication.getInstance().setReceivingMessages(queueReceivingMsg);
Communication.getInstance().startThreads(); //currently: only start sending thread.
while (true) {
try {
bytes = this.mmInStream.read(buffer, len, buffer.length - len);
len += bytes;
if (len >= 3 && buffer[2] != -1) {
len = 0;
Log.d(TAG, "run: To Short?");
} else if (len >= 5) {
int dataLength = Integer
.parseInt(String.format("%02X", buffer[3]) + String.format("%02X", buffer[4]), 16);
if (len == 6 + dataLength) {
queueReceivingMsg.add(buffer);
Log.d(TAG, "run: Added to queue");
len = 0;
}
Log.d("BSS", "dataLenght: " + Integer.toString(dataLength) + " len " + len);
}
} catch (IOException var5) {
cancel();
Communication.getInstance().interruptThreads();
return;
}
}
}
The important part of sending message Class
public static BlockingQueue<Obj_SendingMessage> sendingMessages = new LinkedBlockingQueue<>();
#Override
public void run() {
while (!isInterrupted()) {
if (bGotResponse){
try{
sendingMessage = sendingMessages.take();
send(sendingMessage.getsData());
bGotResponse = false;
lTime = System.currentTimeMillis();
} catch (InterruptedException e){
this.interrupt();
}
}
if((System.currentTimeMillis()%500 == 0) && System.currentTimeMillis() <= lTime+1000){
if(sendingMessage != null){
send(sendingMessage.getsData());
}
} else {
bGotResponse =true;
}
}
}
//Where the outStream is used
private void write(int[] buffer) {
try {
for (int i : buffer) {
this.mmOutputStream.write(buffer[i]);
}
} catch (IOException var3) {
}
}
To be clear again, the sendingMessages is empty all the time, but still the messages get not Received correctly anymore.
Here's a proposal how robust code for reading messages from the stream could look like. The code can handle partial and multiple messages by:
Waiting for more data if a message is not complete
Processing the first message and saving the rest of the data if data for more than one message is available
Searching for a the marker byte 0xff and retaining the data for the next possibly valid message if invalid data needs to be discard
While writing this code I've noticed another bug in the code. If a message is found, the data is not copied. Instead the buffer is returned. However, the buffer and therefore the returned message might be overwritten by the next message before or while the previous one is processed.
This bug is more severe than the poor decoding of the stream data.
private byte[] buffer = new byte[1024];
private int numUnprocessedBytes = 0;
public void run() {
...
while (true) {
try {
int numBytesRead = mmInStream.read(buffer, numUnprocessedBytes, buffer.length - numUnprocessedBytes);
numUnprocessedBytes += numBytesRead;
processBytes();
} catch (IOException e) {
...
}
}
}
private void processBytes() {
boolean tryAgain;
do {
tryAgain = processSingleMessage();
} while (tryAgain);
}
private boolean processSingleMessage() {
if (numUnprocessedBytes < 5)
return false; // insufficient data to decode length
if (buffer[2] != (byte)0xff)
// marker byte missing; discard some data
return discardInvalidData();
int messageLength = (buffer[3] & 0xff) * 256 + (buffer[4] & 0xff);
if (messageLength > buffer.length)
// invalid message length; discard some data
return discardInvalidData();
if (messageLength > numUnprocessedBytes)
return false; // incomplete message; wait for more data
// complete message received; copy it and add it to the queue
byte[] message = Arrays.copyOfRange(buffer, 0, messageLength);
queueReceivingMsg.add(message);
// move remaining data to the front of buffer
if (numUnprocessedBytes > messageLength)
System.arraycopy(buffer, messageLength, buffer, 0, numUnprocessedBytes - messageLength);
numUnprocessedBytes -= messageLength;
return numUnprocessedBytes >= 5;
}
private boolean discardInvalidData() {
// find marker byte after index 2
int index = indexOfByte(buffer, (byte)0xff, 3, numUnprocessedBytes);
if (index >= 3) {
// discard some data and move remaining bytes to the front of buffer
System.arraycopy(buffer, index - 2, buffer, 0, numUnprocessedBytes - (index - 2));
numUnprocessedBytes -= index - 2;
} else {
// discard all data
numUnprocessedBytes = 0;
}
return numUnprocessedBytes >= 5;
}
static private int indexOfByte(byte[] array, byte element, int start, int end) {
for (int i = start; i < end; i++)
if (array[i] == element)
return i;
return -1;
}

Slow serial transfer from Java to Arduino

I have bidirectional communication between Java and Arduino, but am finding that when sending data from Java to Arduino it takes about 3.5 seconds to show up in the sketch.
Data sent from Arduino to Java has no such latency.
Any idea why this is the case?
Arduino code.
Here's my main loop,
void loop() {
connection.sendData(systemVariables);
connection.receiveData(systemVariables);
world(systemVariables, ctr++);
}
Here's the sender,
void sendData(SystemVariables &sv) {
String msg = String(sv.getReference());
String pstr = String(sv.getPosition(), 2);
msg = msg + "," ;
msg = msg + pstr;
msg = msg + "," ;
msg = msg + sv.getOutput();
Serial.println(msg);
}
Here's the receiver,
float receiveData(SystemVariables &sv) {
String str;
while (Serial.available() > 0) {
str = Serial.readStringUntil('\n');
Serial.print('>');
Serial.println(str);
}
if (str.length() > 0)
sv.setOutput( str.toFloat());
return sv.getOutput();
}
Java
The Java loop has a 25ms delay.
receiver
public synchronized void serialEvent(SerialPortEvent oEvent) {
//System.out.println("ET " + oEvent.getEventType());
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
String inputLine = null;
try {
inputLine = input.readLine();
if (inputLine.length() > 0) {
logger.log(Level.INFO, "{0}", inputLine);
if (!inputLine.startsWith(">")) {
String[] arr = inputLine.split(",");
for (int i = 0; i < arr.length; i++) {
try {
float newf = Float.parseFloat(arr[i]);
try {
if (data.size() <= i) {
data.add(newf);
} else {
data.set(i, newf);
}
} catch (IndexOutOfBoundsException e) {
logger.warning(e.toString());
}
} catch (NumberFormatException e) {
logger.log(Level.WARNING, "{0} <{1}> <{2}>", new Object[]{e.toString(), inputLine, arr[i]});
}
}
}
}
} catch (IOException ex) {
Logger.getLogger(SerialSensorSingleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception e) {
logger.warning(e.toString() + " Data received " + inputLine == null ? "null" : "<" + inputLine + ">");
}
}
}
Sender
public void write(String s) throws IOException {
logger.log(Level.INFO, ":{0}", s);
output.write(s.getBytes());
output.flush();
}
I have resolved this now. The problem was that I was trying to implement synchronous communication with asynchronous methodology.
That is, I was using SerialEvent listener, but this is only intended for one way communication. I was trying to use the port to send data back the other way, but it was being blocked by the queue of data that built up for a certain period.
I have changed the method calls to read and writes so that each end sends only one message and than waits for incoming data. In this way each end is synchronised, and it now works like a dream.

Java Tunnel HTTPS(SSL) Requests

I am writing a java application to serve as a local proxy. I have been helped greatly by this piece of code from http://www.nsftools.com/tips/jProxy.java. See program below:
/* <!-- in case someone opens this in a browser... --> <pre> */
/*
* This is a simple multi-threaded Java proxy server
* for HTTP requests (HTTPS doesn't seem to work, because
* the CONNECT requests aren't always handled properly).
* I implemented the class as a thread so you can call it
* from other programs and kill it, if necessary (by using
* the closeSocket() method).
*
* We'll call this the 1.1 version of this class. All I
* changed was to separate the HTTP header elements with
* \r\n instead of just \n, to comply with the official
* HTTP specification.
*
* This can be used either as a direct proxy to other
* servers, or as a forwarding proxy to another proxy
* server. This makes it useful if you want to monitor
* traffic going to and from a proxy server (for example,
* you can run this on your local machine and set the
* fwdServer and fwdPort to a real proxy server, and then
* tell your browser to use "localhost" as the proxy, and
* you can watch the browser traffic going in and out).
*
* One limitation of this implementation is that it doesn't
* close the ProxyThread socket if the client disconnects
* or the server never responds, so you could end up with
* a bunch of loose threads running amuck and waiting for
* connections. As a band-aid, you can set the server socket
* to timeout after a certain amount of time (use the
* setTimeout() method in the ProxyThread class), although
* this can cause false timeouts if a remote server is simply
* slow to respond.
*
* Another thing is that it doesn't limit the number of
* socket threads it will create, so if you use this on a
* really busy machine that processed a bunch of requests,
* you may have problems. You should use thread pools if
* you're going to try something like this in a "real"
* application.
*
* Note that if you're using the "main" method to run this
* by itself and you don't need the debug output, it will
* run a bit faster if you pipe the std output to 'nul'.
*
* You may use this code as you wish, just don't pretend
* that you wrote it yourself, and don't hold me liable for
* anything that it does or doesn't do. If you're feeling
* especially honest, please include a link to nsftools.com
* along with the code. Thanks, and good luck.
*
* Julian Robichaux -- http://www.nsftools.com
*/
import java.io.*;
import java.net.*;
import java.lang.reflect.Array;
public class jProxy extends Thread
{
public static final int DEFAULT_PORT = 8080;
private ServerSocket server = null;
private int thisPort = DEFAULT_PORT;
private String fwdServer = "";
private int fwdPort = 0;
private int ptTimeout = ProxyThread.DEFAULT_TIMEOUT;
private int debugLevel = 0;
private PrintStream debugOut = System.out;
/* here's a main method, in case you want to run this by itself */
public static void main (String args[])
{
int port = 0;
String fwdProxyServer = "";
int fwdProxyPort = 0;
if (args.length == 0)
{
System.err.println("USAGE: java jProxy <port number> [<fwd proxy> <fwd port>]");
System.err.println(" <port number> the port this service listens on");
System.err.println(" <fwd proxy> optional proxy server to forward requests to");
System.err.println(" <fwd port> the port that the optional proxy server is on");
System.err.println("\nHINT: if you don't want to see all the debug information flying by,");
System.err.println("you can pipe the output to a file or to 'nul' using \">\". For example:");
System.err.println(" to send output to the file prox.txt: java jProxy 8080 > prox.txt");
System.err.println(" to make the output go away: java jProxy 8080 > nul");
return;
}
// get the command-line parameters
port = Integer.parseInt(args[0]);
if (args.length > 2)
{
fwdProxyServer = args[1];
fwdProxyPort = Integer.parseInt(args[2]);
}
// create and start the jProxy thread, using a 20 second timeout
// value to keep the threads from piling up too much
System.err.println(" ** Starting jProxy on port " + port + ". Press CTRL-C to end. **\n");
jProxy jp = new jProxy(port, fwdProxyServer, fwdProxyPort, 20);
jp.setDebug(1, System.out); // or set the debug level to 2 for tons of output
jp.start();
// run forever; if you were calling this class from another
// program and you wanted to stop the jProxy thread at some
// point, you could write a loop that waits for a certain
// condition and then calls jProxy.closeSocket() to kill
// the running jProxy thread
while (true)
{
try { Thread.sleep(3000); } catch (Exception e) {}
}
// if we ever had a condition that stopped the loop above,
// we'd want to do this to kill the running thread
//jp.closeSocket();
//return;
}
/* the proxy server just listens for connections and creates
* a new thread for each connection attempt (the ProxyThread
* class really does all the work)
*/
public jProxy (int port)
{
thisPort = port;
}
public jProxy (int port, String proxyServer, int proxyPort)
{
thisPort = port;
fwdServer = proxyServer;
fwdPort = proxyPort;
}
public jProxy (int port, String proxyServer, int proxyPort, int timeout)
{
thisPort = port;
fwdServer = proxyServer;
fwdPort = proxyPort;
ptTimeout = timeout;
}
/* allow the user to decide whether or not to send debug
* output to the console or some other PrintStream
*/
public void setDebug (int level, PrintStream out)
{
debugLevel = level;
debugOut = out;
}
/* get the port that we're supposed to be listening on
*/
public int getPort ()
{
return thisPort;
}
/* return whether or not the socket is currently open
*/
public boolean isRunning ()
{
if (server == null)
return false;
else
return true;
}
/* closeSocket will close the open ServerSocket; use this
* to halt a running jProxy thread
*/
public void closeSocket ()
{
try {
// close the open server socket
server.close();
// send it a message to make it stop waiting immediately
// (not really necessary)
/*Socket s = new Socket("localhost", thisPort);
OutputStream os = s.getOutputStream();
os.write((byte)0);
os.close();
s.close();*/
} catch(Exception e) {
if (debugLevel > 0)
debugOut.println(e);
}
server = null;
}
public void run()
{
try {
// create a server socket, and loop forever listening for
// client connections
server = new ServerSocket(thisPort);
if (debugLevel > 0)
debugOut.println("Started jProxy on port " + thisPort);
while (true)
{
Socket client = server.accept();
ProxyThread t = new ProxyThread(client, fwdServer, fwdPort);
t.setDebug(debugLevel, debugOut);
t.setTimeout(ptTimeout);
t.start();
}
} catch (Exception e) {
if (debugLevel > 0)
debugOut.println("jProxy Thread error: " + e);
}
closeSocket();
}
}
/*
* The ProxyThread will take an HTTP request from the client
* socket and send it to either the server that the client is
* trying to contact, or another proxy server
*/
class ProxyThread extends Thread
{
private Socket pSocket;
private String fwdServer = "";
private int fwdPort = 0;
private int debugLevel = 0;
private PrintStream debugOut = System.out;
// the socketTimeout is used to time out the connection to
// the remote server after a certain period of inactivity;
// the value is in milliseconds -- use zero if you don't want
// a timeout
public static final int DEFAULT_TIMEOUT = 20 * 1000;
private int socketTimeout = DEFAULT_TIMEOUT;
public ProxyThread(Socket s)
{
pSocket = s;
}
public ProxyThread(Socket s, String proxy, int port)
{
pSocket = s;
fwdServer = proxy;
fwdPort = port;
}
public void setTimeout (int timeout)
{
// assume that the user will pass the timeout value
// in seconds (because that's just more intuitive)
socketTimeout = timeout * 1000;
}
public void setDebug (int level, PrintStream out)
{
debugLevel = level;
debugOut = out;
}
public void run()
{
try
{
long startTime = System.currentTimeMillis();
// client streams (make sure you're using streams that use
// byte arrays, so things like GIF and JPEG files and file
// downloads will transfer properly)
BufferedInputStream clientIn = new BufferedInputStream(pSocket.getInputStream());
BufferedOutputStream clientOut = new BufferedOutputStream(pSocket.getOutputStream());
// the socket to the remote server
Socket server = null;
// other variables
byte[] request = null;
byte[] response = null;
int requestLength = 0;
int responseLength = 0;
int pos = -1;
StringBuffer host = new StringBuffer("");
String hostName = "";
int hostPort = 80;
// get the header info (the web browser won't disconnect after
// it's sent a request, so make sure the waitForDisconnect
// parameter is false)
request = getHTTPData(clientIn, host, false);
requestLength = Array.getLength(request);
// separate the host name from the host port, if necessary
// (like if it's "servername:8000")
hostName = host.toString();
pos = hostName.indexOf(":");
if (pos > 0)
{
try { hostPort = Integer.parseInt(hostName.substring(pos + 1));
} catch (Exception e) { }
hostName = hostName.substring(0, pos);
}
// either forward this request to another proxy server or
// send it straight to the Host
try
{
if ((fwdServer.length() > 0) && (fwdPort > 0))
{
server = new Socket(fwdServer, fwdPort);
} else {
server = new Socket(hostName, hostPort);
}
} catch (Exception e) {
// tell the client there was an error
String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" +
"Error connecting to the server:\n" + e + "\n";
clientOut.write(errMsg.getBytes(), 0, errMsg.length());
}
if (server != null)
{
server.setSoTimeout(socketTimeout);
BufferedInputStream serverIn = new BufferedInputStream(server.getInputStream());
BufferedOutputStream serverOut = new BufferedOutputStream(server.getOutputStream());
// send the request out
serverOut.write(request, 0, requestLength);
serverOut.flush();
// and get the response; if we're not at a debug level that
// requires us to return the data in the response, just stream
// it back to the client to save ourselves from having to
// create and destroy an unnecessary byte array. Also, we
// should set the waitForDisconnect parameter to 'true',
// because some servers (like Google) don't always set the
// Content-Length header field, so we have to listen until
// they decide to disconnect (or the connection times out).
if (debugLevel > 1)
{
response = getHTTPData(serverIn, true);
responseLength = Array.getLength(response);
} else {
responseLength = streamHTTPData(serverIn, clientOut, true);
}
serverIn.close();
serverOut.close();
}
// send the response back to the client, if we haven't already
if (debugLevel > 1)
clientOut.write(response, 0, responseLength);
// if the user wants debug info, send them debug info; however,
// keep in mind that because we're using threads, the output won't
// necessarily be synchronous
if (debugLevel > 0)
{
long endTime = System.currentTimeMillis();
debugOut.println("Request from " + pSocket.getInetAddress().getHostAddress() +
" on Port " + pSocket.getLocalPort() +
" to host " + hostName + ":" + hostPort +
"\n (" + requestLength + " bytes sent, " +
responseLength + " bytes returned, " +
Long.toString(endTime - startTime) + " ms elapsed)");
debugOut.flush();
}
if (debugLevel > 1)
{
debugOut.println("REQUEST:\n" + (new String(request)));
debugOut.println("RESPONSE:\n" + (new String(response)));
debugOut.flush();
}
// close all the client streams so we can listen again
clientOut.close();
clientIn.close();
pSocket.close();
} catch (Exception e) {
if (debugLevel > 0)
debugOut.println("Error in ProxyThread: " + e);
//e.printStackTrace();
}
}
private byte[] getHTTPData (InputStream in, boolean waitForDisconnect)
{
// get the HTTP data from an InputStream, and return it as
// a byte array
// the waitForDisconnect parameter tells us what to do in case
// the HTTP header doesn't specify the Content-Length of the
// transmission
StringBuffer foo = new StringBuffer("");
return getHTTPData(in, foo, waitForDisconnect);
}
private byte[] getHTTPData (InputStream in, StringBuffer host, boolean waitForDisconnect)
{
// get the HTTP data from an InputStream, and return it as
// a byte array, and also return the Host entry in the header,
// if it's specified -- note that we have to use a StringBuffer
// for the 'host' variable, because a String won't return any
// information when it's used as a parameter like that
ByteArrayOutputStream bs = new ByteArrayOutputStream();
streamHTTPData(in, bs, host, waitForDisconnect);
return bs.toByteArray();
}
private int streamHTTPData (InputStream in, OutputStream out, boolean waitForDisconnect)
{
StringBuffer foo = new StringBuffer("");
return streamHTTPData(in, out, foo, waitForDisconnect);
}
private int streamHTTPData (InputStream in, OutputStream out,
StringBuffer host, boolean waitForDisconnect)
{
// get the HTTP data from an InputStream, and send it to
// the designated OutputStream
StringBuffer header = new StringBuffer("");
String data = "";
int responseCode = 200;
int contentLength = 0;
int pos = -1;
int byteCount = 0;
try
{
// get the first line of the header, so we know the response code
data = readLine(in);
if (data != null)
{
header.append(data + "\r\n");
pos = data.indexOf(" ");
if ((data.toLowerCase().startsWith("http")) &&
(pos >= 0) && (data.indexOf(" ", pos+1) >= 0))
{
String rcString = data.substring(pos+1, data.indexOf(" ", pos+1));
try
{
responseCode = Integer.parseInt(rcString);
} catch (Exception e) {
if (debugLevel > 0)
debugOut.println("Error parsing response code " + rcString);
}
}
}
// get the rest of the header info
while ((data = readLine(in)) != null)
{
// the header ends at the first blank line
if (data.length() == 0)
break;
header.append(data + "\r\n");
// check for the Host header
pos = data.toLowerCase().indexOf("host:");
if (pos >= 0)
{
host.setLength(0);
host.append(data.substring(pos + 5).trim());
}
// check for the Content-Length header
pos = data.toLowerCase().indexOf("content-length:");
if (pos >= 0)
contentLength = Integer.parseInt(data.substring(pos + 15).trim());
}
// add a blank line to terminate the header info
header.append("\r\n");
// convert the header to a byte array, and write it to our stream
out.write(header.toString().getBytes(), 0, header.length());
// if the header indicated that this was not a 200 response,
// just return what we've got if there is no Content-Length,
// because we may not be getting anything else
if ((responseCode != 200) && (contentLength == 0))
{
out.flush();
return header.length();
}
// get the body, if any; we try to use the Content-Length header to
// determine how much data we're supposed to be getting, because
// sometimes the client/server won't disconnect after sending us
// information...
if (contentLength > 0)
waitForDisconnect = false;
if ((contentLength > 0) || (waitForDisconnect))
{
try {
byte[] buf = new byte[4096];
int bytesIn = 0;
while ( ((byteCount < contentLength) || (waitForDisconnect))
&& ((bytesIn = in.read(buf)) >= 0) )
{
out.write(buf, 0, bytesIn);
byteCount += bytesIn;
}
} catch (Exception e) {
String errMsg = "Error getting HTTP body: " + e;
if (debugLevel > 0)
debugOut.println(errMsg);
//bs.write(errMsg.getBytes(), 0, errMsg.length());
}
}
} catch (Exception e) {
if (debugLevel > 0)
debugOut.println("Error getting HTTP data: " + e);
}
//flush the OutputStream and return
try { out.flush(); } catch (Exception e) {}
return (header.length() + byteCount);
}
private String readLine (InputStream in)
{
// reads a line of text from an InputStream
StringBuffer data = new StringBuffer("");
int c;
try
{
// if we have nothing to read, just return null
in.mark(1);
if (in.read() == -1)
return null;
else
in.reset();
while ((c = in.read()) >= 0)
{
// check for an end-of-line character
if ((c == 0) || (c == 10) || (c == 13))
break;
else
data.append((char)c);
}
// deal with the case where the end-of-line terminator is \r\n
if (c == 13)
{
in.mark(1);
if (in.read() != 10)
in.reset();
}
} catch (Exception e) {
if (debugLevel > 0)
debugOut.println("Error getting header: " + e);
}
// and return what we have
return data.toString();
}
}
Problem is secure sites like "https://www.google.com" don't work. I have tried to tweak the code over and over again but all to no avail. I have gone through questions answered here and many more sites too but I just cant seem to get it to work. I would av posted links but I cant cos I dnt av enuf reputation yet.
Someone pls help me with what needs to be done to support Secure Sites(HTTPS).
Thanks in advance.
PS: Sorry if I didn't ask the question the right way.I'm a newbie. Cheers...
Default port for https is 443. This is used if no port is specified in the URL, as is the case with the google site you give as an example. Try adjusting the code with this in mind.

BufferedReader.readLine() pauses my application?

I am using this code:
while (true) {
sendData("hi");
System.out.println("Data sent!");
BufferedReader inFromServer;
try {
inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e1) {
inFromServer = null;
e1.printStackTrace();
}
System.out.println("Recieved!"); //I see this de-bug message.
try {
modifiedSentence = inFromServer.readLine();
System.out.println("FROM SERVER: " + modifiedSentence); //I do NOT see this de-bug message!
} catch (IOException e) {
e.printStackTrace();
}
}
It successfully sends data to a server - And the server successfully sends data back:
public void run () {
//handle the session using the socket (example)
try {
sendData("Hi");
System.out.println("Data sent!"); //I see this de-bug message.
} catch (Exception e) {
e.printStackTrace();
}
}
However for some reason, the application seems to pause at the inFromServer.readLine() method. I see the "Recieved!" de-bug message, but not the "FROM SERVER" de-bug message.
There are no errors at all. It just seems to hang there.
Why is it hanging, and how can I fix that?
Well this simply means that inFromServer does not receive any line.
Make sure you really send a line,
Reads a line of text. A line is considered to be terminated by any one
of a line feed ('\n'), a carriage return ('\r'), or a carriage return
followed immediately by a linefeed.
Have a look at the readLine method :
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
Note that this one receive a boolean, but calling readLine simply call this one with false passed, unless on Linux.
Notice the for(;;) loop, which is an infinite loop.
Try concatening to the "line" sent from the server
System.getProperty("line.separator");

Java Threads - for two while loops

I am a begginer and i went over tutorials for this but still dont know how exactly to implement this.
I have two while loops one in main() method and one in send() method both need to be executing at the same time how do i go about this.
public static void main(String[] args) throws Exception
{
socket = new DatagramSocket(13373); // 69 Reserved for TFTP
// Listen for incoming packets
while(true) {
// Do things
}
}
private static void sendDATA() {
while(true) {
// Do things
}
}
While loop in sendDATA works by reading 512 bytes from a file then sending them to client class. While loop in main method receives packets from client and updates a variable if variable is true then sendDATA reads next 512 bytes and sends them and so on but i cant work in two threads.
I have done this with one while loop and program works, well sort of it transfers all the packets but the last one. Client never gets the last packet.
Server:
public static void main(String[] args) throws Exception
{
socket = new DatagramSocket(13373); // 69 Reserved for TFTP
// Listen for incoming packets
while(true) {
DatagramPacket packet = new DatagramPacket(incoming, incoming.length);
socket.receive(packet);
clientip = packet.getAddress().toString().replace("/", "");
clientport = packet.getPort();
System.out.println(clientport);
if(incoming[0] == 1 || incoming[0] == 2) {
handleRequest(incoming);
}
}
}
// sends DATA opcode = 3 : | opcode | block # | data |
private static void sendDATA() {
try {
ByteBuffer sDATA = ByteBuffer.allocate(514);
byte[] tmp = new byte[512];
DatagramPacket data = new DatagramPacket(sDATA.array(), sDATA.array().length, InetAddress.getByName(clientip), clientport);
InputStream fis = new FileInputStream(new File(FILE));
int a;
int block = 1;
while((a = fis.read(tmp,0,512)) != -1)
{
data.setLength(a);
sDATA.put((byte)3);
sDATA.put((byte)block);
System.out.println(sDATA.array().length);
sDATA.put(tmp);
System.out.println(tmp.length);
socket.send(data);
socket.setSoTimeout(60000);
while(true) {
DatagramPacket getack = new DatagramPacket(incoming, incoming.length);
try {
socket.receive(getack);
if(incoming[0] == 4 && incoming[1] == block) {
break;
} else if(incoming[0] == 4 && incoming[1] == block && tmp.length < 511) {
fis.close();
break;
}
} catch (SocketTimeoutException e) {
socket.send(data);
continue;
}
}
block++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
Client:
public static void main(String[] args) throws Exception
{
clientSocket = new DatagramSocket(8571);
// WRQ || RRQ
Scanner input = new Scanner(System.in);
int opcode = input.nextInt(); input.close();
// Pripravi paketek
outgoing = makeRequestPacket(opcode,"filename.txt","US-ASCII");
// Odposlje pakete
sendPacket(outgoing);
// Streznik vrne ACK - opcode 4 ali ERROR - opcode 5
// Pri ACK zacnemo posiljat DATA opcode 3 drugace prekinemo povezavo ob ERROR - opcode 5
while(true) {
DatagramPacket receiveResponse = new DatagramPacket(incoming, incoming.length);
clientSocket.receive(receiveResponse);
// opcode 5 - ERROR
if(incoming[0] == 5) {
getError(incoming);
}
else if(incoming[0] == 4 && incoming[1] == 0) { // opcode 4 - Prvi ACK
System.out.print("opcode: (" + incoming[0] +") ACK received operation confirmed.");
continue;
}
else if(incoming[0] == 3) {
System.out.println("Ah got a data packet.");
File initfile = new File("filename2.txt");
if(!initfile.exists()) {
initfile.createNewFile();
}
int block;
FileOutputStream fio = new FileOutputStream(initfile);
if(incoming.length > 511) {
block = incoming[1];
System.out.println("Will start to write.");
for(int i = 2; i < incoming.length; i++) {
fio.write(incoming[i]);
}
ByteBuffer recack = ByteBuffer.allocate(514);
recack.put((byte)4);
recack.put((byte)block);
System.out.println("If i came here and nothing happened something went horribly wrong.");
DatagramPacket replyACK = new DatagramPacket(recack.array(), recack.array().length, InetAddress.getByName("localhost"),13373);
clientSocket.send(replyACK);
} else if (incoming.length < 511) {
System.out.println("Last chunk.");
block = incoming[1];
for(int j = 2; j < incoming.length; j++) {
if(incoming[j] != 0) {
fio.write(incoming[j]);
} else {
break;
}
}
ByteBuffer recack = ByteBuffer.allocate(514);
recack.put((byte)4);
recack.put((byte)block);
DatagramPacket replyACK = new DatagramPacket(recack.array(), recack.array().length, InetAddress.getByName("localhost"),13373);
clientSocket.send(replyACK);
fio.close();
clientSocket.close();
break;
}
continue;
}
}
}
You have to use a blocking channel in order to synchronize communication between your processes:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(true);
More info: http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/channels/SocketChannel.html
Also, sockets are designed to send data between processes, if that's not the case your approach is wrong and you should change your design, i.e. call each loop in a new thread when (or every time) data is ready for it (each thread will process its data and then die) or just execute both blocks of instructions sequentially inside one loop if you don't need concurrent execution. A state diagram of your program can help you determine which is the best solution.
So what i have been looking for was a simple 'crude' way of runing two methods of the same class at the same time for instace two independant loops. Anyhow here is the code:
class MyClass extends Thread {
public void run() { // start new thread
otherMethod(); // will calls another method
}
void otherMethod() {
.... executed in another Thread
}
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.start(); // start other Thread
... continue in main() with actual thread
...
}
}

Categories

Resources