I want to write a simple web proxy, for exercise. Here's the code I have so far:
def g = new Proxy()
g.serverPort = 9000
println "starting"
g.eachClient { Socket client ->
println "got a client"
try {
client.withStreams { input,output ->
String text = input.text
println "received $text from client"
client.close()
}
} catch(IOException io) {
println "IO error. Probably client disconnected"
//io.printStackTrace()
}
}
the thing is, the line :
String text = input.text
consumes all the available data in the Socket's InputStream. If the client isn't closing the connection, that method will just wait until it can read a end of file character ( if I remember correctly ). What do I have to prevent this from happening, and have the client's string available ASAP?
I think you'll want to check the documentation on ObjectInputStream. Do length = input.available to get the number of available bytes at the present time, then use input.read(buffer, offset, length) to read in exactly as many bytes are available. You'll probably want to launch a new thread for every new connection which transparently manages this buffer in the background, unless you're making a single-threaded proxy to begin with.
Related
I am building this program where a server sends different order to different clients. One part of the program sends the order to the server, the server processes to which client the message goes to and then it sends it to the particular client it should go.
Here is the code where the message is send:
#Override
public void run() {
boolean active = true;
String oldMsgToDron = "";
String to_print = "";
BufferedWriter bw = new BufferedWriter(osw);
while(active) {
try {
//msgToDron is declared in DronController as: public static volatile String msgToDron;
to_print = DronController.msgToDron;
if(to_print.equals(oldMsgToDron) == false) {
System.out.println("Message we are sending to the dron: " + to_print);
if(to_print.length()>45 && to_print.startsWith("!whisper") && dronId.equals(to_print.substring(9, 45))) {
bw.write("Server whispers:" + to_print.replace("!whisper " + dronId, ""));
bw.newLine();
bw.flush();
System.out.println("Message we sent to the dron: " + to_print);
}
else if (to_print.startsWith("!whisper") == false){
bw.write(to_print);
bw.newLine();
bw.flush();
System.out.println("A message for all drones has been sent.");
}
try{Thread.sleep(5);}catch(InterruptedException ex){ex.printStackTrace();}
oldMsgToDron = "";
to_print = "";
DronController.msgToDronEsclavo = "";
}
}catch(IOException e) {
try {
active = false;
if(bw != null)
bw.close();
}catch(IOException f) {e.printStackTrace();f.printStackTrace();break;}
}
}
}
My problem is that the message is processed inside the thread that controls the connection to the client and at the end of the loop the message is changed to an empty string. This is so I can send the same order twice in a row and the server isn't constantly sending the same messages to the client.
The thing is that by doing it this way if I have 3 or more connections it starts to give me problems because whenever one of the threads reaches the end they turn the variables DronController.msgToDronEsclavo, to_print and oldMsgToDron to empty strings before the other threads had time to check if the message was for the client they have assigned.
How can I avoid that the different threads change the variable before the others have finished? Are there any kind of design pattern for this kind of structures? What are some good practices with this type of programs?
Also, I've thought about making the client check if the message sent is for them or not but I find this solution unsecure.
Usually it is the client who connects to the server via network - to request data or to send data. The server has no reliable way to know when the client would connect the next time, or trigger a connection itself.
If you want to send data from the server to the client there used to be patterns that the client would poll for data, or have always one request waiting for the next packet from the server. You may want to read about AJAX and Websocket
Another pattern would be to install a webhook, which essentially gives the server a URL at which the client can be reached. This in essence swaps the server to acting as client and the client to acting as server for this data transfer.
Well, the above was written related to your question title. Now looking at the content, you are asking how to prevent that threads impact each other.
Learn Java's concepts on thread synchronization. Here is a nice tutorial.
Following scenario that explains my problem.
I've a PLC that acts as a server socket program. I've written a Client Java program to communicate through socket communication with the PLC.
Steps that take place in this process are:
1) For each second my Client program happen to communicate with the PLC, read the data in stream, store the data temporarily in a ByteArrayOutputStream and closing both input stream and socket. Following snippet gives the idea
try {
socket = new Socket(host, port);
is = socket.getInputStream();
outputBuffer = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
System.out.println("Before closing the socket");
try {
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("After closing the socket");
} catch (Exception e) {
e.printStackTrace();
}
}
2) Processing stored data according to my requirement is what I'm trying to do. So for every 1 second, client program connects to Server, read the data(if data is present), store the data, close socket and process it. And it has to happen for a very long run, probably till the Server program is on. And that may happen till for every few weeks.
3) Problem what I'm facing is, I'm able to run the above show for 1-2 hours, but from then, Client Program unable to fetch the data from the Server Program(PLC in this case), though both are connected through socket. I.e 128 bytes of data present, but Client program isn't able to read that data. And this started happening after program run successfully for almost 2hours
4) Please find the brief code which may help for you to look into.
public class LoggingApplication {
public static void main(String[] args) throws NumberFormatException {
if (args.length > 0 && args.length == 2) {
String ipAddress = mappingService.getIpAddress();
int portNo = (int) mappingService.getPortNo();
ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
} else {
throw new IllegalArgumentException("Please pass IPAddress and port no as arguments");
}
}
}
Runnable Code:
public class MyTask implements Runnable {
public ScheduledExecutorService execService;
private String ipAddress;
private int portNo;
private ConfigurationMappingService mappingService;
private MySocketSocketUtil mySocketSocketUtil;
public MyTask(ScheduledExecutorService execService, String ipAddress, int portNo, ConfigurationMappingService mappingService) {
this.execService = execService;
this.ipAddress = ipAddress;
this.portNo = portNo;
this.mappingService = mappingService;
}
public void run() {
MySocketSocketUtil mySocketSocketUtil = new MySocketSocketUtil(ipAddress, portNo);
execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
mySocketSocketUtil.getData(); //It's able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on.
/*
*
*Some code
*/
}
}
Here's where, I'm having the problem
mySocketSocketUtil.getData(); is able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on. It's a big question I know, And I want to understand what might have gone wrong.
Edit: I'm ignoring the condition to check end of the stream and closing a socket based on it is because, I knew I'm going to read first 1024 bytes of data only always. And So, I'm closing the socket in finally block
socket = new Socket(host, port);
if(socket != null && socket.isConnected())
It is impossible for socket to be null or socket.isConnected() to be false at this point. Don't write pointless code.
if((read = is.read(buffer)) != -1) {
outputBuffer.write(buffer, 0, read);
};
Here you are ignoring a possible end of stream. If read() returns -1 you must close the socket. It will never not return -1 again. This completely explains your 'empty data':
from then, it's just getting empty data and it's keep on giving empty data from then, and so on
And you should not create a new Socket unless you have received -1 or an exception on the previous socket.
} else {
System.err.println("Socket couldn't be connected");
}
Unreachable: see above. Don't write pointless code.
You should never disconnect from the established connection. Connect once in the LoggingApplication. Once the socket is connected keep it open. Reuse the socket on the next read.
I think there are couple of points you need to fix before getting to the solution to your problem. Please try to follow the following suggestions first:
As #EJP said this code block is not needed.
if(socket != null && socket.isConnected()) {
also you are using a byte array of length 1024 and not using while or for loop to read the data stream. Are you expecting only a block of data which will never exceed 1024 bytes?
byte[] buffer = new byte[1024];
int read;
if((read = is.read(buffer)) != -1) {
This is also not needed as it is unreachable.
} else {
System.err.println("Socket couldn't be connected");
}
Can you explain the data stream behavior you are expecting?
Last but not the least is.read(buffer) is a blocking call so if there is no data to read yet, it will hold the thread execution at that point.
Please try to answer the questions I have asked.
#KishoreKumarKorada from your description in the comment section, it seems like you are monitoring the data change on server side. Socket stream works in a read-once fashion. So,
First thing is, you need to request from server every time and the server needs to RESEND the data on every request.
Second, the way you presented is more like you are operating on byte level, which is not very good way to do that unless you have any legitimate reason to do so. The good way is to wrap the data in JSON or XML format and send it over the stream. But to reduce bandwidth consumption, you may need to operate on byte stream sometimes. You need to decide on that.
Third, for monitoring the data change, the better way is to use some timestamp to compare when the data has changed on the server side and what is the timestamp stored on the client side, if they match, data has not changed. Otherwise fetch the data from the server side and update the client side.
Fourth, when there is data available that you are not able to read, can you debug the ins.read(...) statement to see if its getting executed and the execution goes inside the if block or if statement is evaluated to false? if true then examine the read value and let me know what you have found?
Thanks.
I have wrote an event listener that suppose to read any messages of a specific type from a receiver.
here is my event listener:
class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if (event.isRXCHAR() && event.getEventValue() > 0) {
try {
byte[] buffer = SP.readBytes(6);
String type = new String(buffer);
if (type.equals("$GPGGA")){
String line = "";
line = line + type;
buffer = SP.readBytes(66);
String values = new String(buffer);
line = line + values;
writer.write(line + "\n");
}
}
catch (SerialPortException ex) {System.out.println(ex);}
catch (IOException ex) {System.out.println(ex);}
}
}
}
right now after i check that the message is of the correct type i just read 80 bytes off data, which is roughly the size of the message.
however, sometimes the message is not full and there for it is shorter then usual.
this is the message structure:
as you can see, the message end s with <CR><FL>.
i would like to modify my method so it would read each byte at a time and stop reading once it hits the end of the message. how can i catch the <CR><FL> inside the byte array?
any help would be appreciated. thank you.
It depends on the definition of "messages": are they fixed-length or delimited by a certain sequence? In your current code, you're reading a "header" that is 6 bytes long and a "message" that is 66 bytes long. However, it appears that you actually don't know the length a priori, and instead the message is newline-terminated. A couple of pointers:
You're reading bytes from the stream, then turning them into a String by using the String(byte[]) ctor. The documentation states that this uses the default charset for your platform, which may be UTF-8, Latin-1 or whatever regional default. If you are communicating with a device over a serial port, this is probably not what you want since the device is likely to have a single, specific charset for messages (maybe ASCII?). Investigate that point and use either this String ctor or, if you want to be notified when the input contains undecodable garbage, the CharsetDecoder class.
If the messages are text-based and newline-delimited, you should definitely use a BufferedReader to read from the stream. Assuming that your SP serial port is an InputStream, you could create a BufferedReader over it, and then call the readLine() method on the reader. The reader will keep requesting bytes from the stream until it sees a newline, then return the whole line to you as a String. Reader objects also encapsulate the Charset I was talking about before.
I have managed to solve my problem.
pretty easy solution:
String tmp = SP.readString();
String[] msgs = tmp.split("\r\n");
after reading the string from the serial port, i just split it by the end of line.
I am doing client server Java program using Java NIO. Basically for the server codes, I took from here. And for the client side, I took from here. Now it seems good. What I want to achieve now is send data from client to server,and server will send back to the client.
But I am having a problem with the logic. Lets say I put "AMessage", then I have to put "BMessage" in order to retrieve "AMessage" from the server. I did the debugging, and seems like my key.isConnectable() is always return true. I try to set the key interest, reregister it, but I didn't found any solution yet.
I have tried this one key.interestOps(0);, myChannel.register(selector, SelectionKey.OP_READ);, but seems nothing happen. isConnectable still returned true. I found some issues informed by other people saying that it is localhost issue. I have no idea. But now I am running the server and client on localhost. Anyone has any idea?
Thanks :)
Edited: This is part of my codes:-
if (key.isConnectable()) {
if (myChannel.isConnectionPending()) {
try{
myChannel.finishConnect();
}
catch(IOException e){
System.out.println(e);
}
System.out.println("Status of finishCOnnect(): " + myChannel.finishConnect() );
System.out.println("Connection was pending but now is finished connecting.");
}
ByteBuffer bb = null;
ByteBuffer incomingBuffer = null;
Scanner input = new Scanner(System.in); // Declare and Initialize the Scanner
while (true) {
System.out.println("Status isReadable is " + key.isReadable() + " and isWritable is " + key.isWritable() +
" and isConnectable is " + key.isConnectable());
readMessage(key); //read if server send data
//send data to server here
String inputFromClient = input.nextLine(); //Get the input from client
System.out.println("debugging after get input...");
bb = ByteBuffer.allocate(inputFromClient.length()); //Allocate buffer size according to input size
byte[] data = inputFromClient.getBytes("UTF-8"); //convert the input to form of byte
bb = ByteBuffer.wrap(data); //wrap string inside a buffer
myChannel.write(bb); //Write the buffer on the channel to send to the server
bb.clear();
}
}
if (key.isConnectable()) {
if (myChannel.isConnectionPending()) {
try{
myChannel.finishConnect();
}
catch(IOException e){
System.out.println(e);
}
System.out.println("Status of finishCOnnect(): " + myChannel.finishConnect() );
System.out.println("Connection was pending but now is finished connecting.");
}
There are several problems here.
The isConnectionPending() test is redundant. It must be pending, otherwise you wouldn't have got the event, but you may be tempting Providence by testing it. Get rid of this test.
You aren't doing the right thing with the finishConnect() call. If finishConnect() returns true then it is OK to deregister OP_CONNECT and register OP_READ or whatever. If it returns false, it isn't OK.
If finishConnect() throws an exception, the connect has failed and you must close the channel.
You are calling finishConnect() twice: once in the try block and once when logging the state. Get rid of the second call and use the result of the first call, if there is one. I would reorganize this to log (a) success from finishConnect(), (b) failure from finishConnect(), and (c) exception from finishConnect(), all separately.
Your final System.out.println() is just a lie in two out of the three cases. Don't tell yourself things that you don't know to be true. It just confuses the picture. Log each case separately as above.
You are assuming that the connection is readable, instead of testing isReadable().
I have run into an interesting issue trying to upgrade one of my applications from the Java 6 to Java 7. It is a simple Java socket program. It sends a command to a COM socket and receives a response. It works perfectly in a Java 6 environment, but when I try to run the same code in a Java 7 environment, the socket appears to receive nothing in the InputStream.
I can confirm that the COM socket it's connecting to does receive the command and sends the response. This is run on the exact same machine in both cases with the firewall disabled, and it's the exact same code ran both times.
Has something changed in Java 7, do I have some deeper flaw, or is this simply a Java bug?
Here is a slightly stripped version of the code.
public static void main(String[] arguments) throws Exception {
InetAddress server = InetAddress.getByName(serverAddress);
Socket sock = SSLSocketFactory.getDefault().createSocket(server.getHostAddress(), port);
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();
out.write(command.getBytes()); //Is valid command
String token = "";
responseReader: while (true) {
try {
Thread.sleep(1);
}
catch (InterruptedException exception) {}
byte[] d = new byte[in.available()];
int avail = in.read(d);
for (int i = 0; i < avail; i++) {
if (d[i] == fieldSeperator) {
token = "";
}
else if (d[i] == commandSeperator) {
break responseReader;
}
else {
token += (char) d[i];
}
}
}
}
I've tried as much as I can think of, most of the time knowing it shouldn't matter. Using different methods of reading the stream, casting to SSLSocket and making different calls, adding some sleeps.
The code is wrong. You shouldn't use available() like that. If there is no data available you will allocate a zero length buffer and execute a zero length read, which will retun zero without blocking. Use a constant like 8192 for the buffer size, and allocate the buffer outside the loop. And get rid of the sleep() too.
There are few if any correct uses of available(), and this isn't one of them.
And note that available() always returns zero for an SSLSocket, and has always done so right back to Java 1.3 and the separate JSSE download. So I am unable to accept that the same code worked in Java 6.