I have a integration test that sends 800 messages to a client. The client receives all the messages fine. The issue is my test fails periodically because the socket (towards the end of the messages), reads no bytes (-1) from the stream, closes the socket, reopens the socket, and gets the bytes. The test 'completes' before the final bytes are read (and so fails), but I can see in the log the last messages do get to the client successfully. This is intermittent. It happens about every half dozen runs or so. In other words, maybe 5 runs straight will get no errors (the socket never had to be closed/re-opened), but the 6th run will have this issue.
So far I have tried increasing/decreasing message sending speed.
Server:
try
{
srvr = new ServerSocket(PORT);
Socket socket = srvr.accept();
...
OutputStream out = socket.getOutputStream();
for (String msg : Messages)
{
byte[] bytes = new BigInteger(msg, BASE_16).toByteArray();
out.write(bytes);
// Delay so client can keep up.
sleep(SOCKET_CLIENT_DELAY);
}
}
catch (IOException ioe)
{
fail(ioe.getMessage());
}
finally
{
handleClose(srvr);
}
Client:
#Override
public void run()
{
final long reconnectAttemptWaitTimeMillis = 5_000;
Socket socket = null;
while (true)
{
try
{
socket = new Socket(host, port);
boolean isConnected = socket.isConnected();
if (isConnected)
{
read(socket);
}
}
catch (ConnectException ce)
{
LOGGER.warn(
"Could not connect to ADS-B receiver/antenna on [" + host + ":" + port
+ "]. Trying again in 5 seconds...");
try
{
sleep(reconnectAttemptWaitTimeMillis);
}
catch (InterruptedException ie)
{
LOGGER.error(ie.getMessage(), ie);
break;
}
}
catch (IOException ioe)
{
LOGGER.error(ioe.getMessage(), ioe);
}
}
LOGGER.info("A total of " + totalEnqueued + " ADS-B messages were enqueued.");
}
/**
* Reads binary ADS-B messages from the {#link Socket}. Assumption is the given {#link Socket} is connected.
*
* #param socket
* where to read ADS-B messages from.
*/
private void read(final Socket socket)
{
LOGGER.info(getName() + " connected to " + host + ":" + port);
DataInputStream in = null;
try
{
in = new DataInputStream(socket.getInputStream());
while (true)
{
byte[] rawBuffer = new byte[MESSAGE_BUFFER_SIZE];
int bytesRead = in.read(rawBuffer);
if (bytesRead == -1)
{
LOGGER.warn("End of stream reached.");
break;
}
/*
* The Mode-S Beast receiver's AVR formatted output for every message begins with 0x1A.
*/
if (rawBuffer[0] == MODE_S_BEAST_PREFIX_NUM)
{
/*
* AdsbDecoder will expect a hexadecimal String representation of the ADS-B message
* without the prefix and suffix.
*
* First, we will convert the raw bytes into a hexadecimal String.
*
* Then, we will remove the Mode-S Beast metadata from the AVR format.
*
* For example:
* "1A33000000000000008DA44E325915B6B6A2FACB45988A" will look like "8DA44E325915B6B6A2FACB45988A"
*
* Finally, we enqueue the ADS-B hex message.
*/
// 1A33000000000000008DA44E325915B6B6A2FACB45988A
String modeS = new BigInteger(rawBuffer).toString(BASE_16).toUpperCase();
// Remove Mode-S Beast info
final int modesBeastPrefixLength = 18;
String adsbMessage = modeS.substring(modesBeastPrefixLength, modeS.length());
LOGGER.info("Message read from receiver/antenna: [" + adsbMessage + "]");
rawAdsbMessages.offer(adsbMessage);
++totalEnqueued;
}
}
}
catch (
IOException ioe)
{
LOGGER.error("Problem encountered reading from Socket. " + ioe.getMessage());
}
finally
{
if (Objects.nonNull(in))
{
try
{
in.close();
}
catch (IOException ex)
{
LOGGER.error("Problem encountered closing the Socket reader. " + ex.getMessage());
}
}
}
}
I expect to not see the bytesRead value become -1 and it have to re-establish the connection since this is all in one test. I have very limited knowledge of socket programming, so maybe this is an unrealistic expectation. If so, please tell me why. Maybe putting a buffered reader/writer in .?? Any suggestions would be fantastic.
Related
I have connection to TCP server (ip,port) to which meter is connected. I'd like to read the specified data from this port because when I'm using standard read method it sends me the whole data stream which takes about 15 minutes to read. So my question: is there any method I can use to get one specified register's value using his OBIS code (1.1.1.8.0.255 - active energy taken) in java via TCP server?
import java.net.*;
import java.io.*;
public class scratch {
public static void main(String[] args) {
String hostname = "ip (hidden)";
int port = port (hidden);
try (Socket socket = new Socket(hostname, port)) {
OutputStream out = socket.getOutputStream();
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
int character;
StringBuilder data = new StringBuilder();
String test = "/?!\r\n";
byte[] req = test.getBytes();
out.write(req);
while ((character = reader.read()) != '\n') {
data.append((char) character);
}
System.out.println(data);
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
The message "test" send initiation request to meter and his respond is correct but I dont' know how to put flags (ACK STX ETX) in my request, I've tried something like this:
String test2 = (char)0x6 + "051\r\n";
byte[] req2 = test2.getBytes("ASCII");
out.write(req2);
But meter doesn't recognize it.
I am new to Java NIO and I am using NIO2 to write a simple Server-Client 2 way communication program. Server and Client are running locally. I could not get the result of what I expected, could anyone help to check the code please? Thanks a lot.
Server side:
public class Server
{
public static void main( String[] args )
{
try (AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open()) {
server.bind(new InetSocketAddress("127.0.0.1", 2001));
Future<AsynchronousSocketChannel> acceptCon = server.accept();
AsynchronousSocketChannel client = acceptCon.get(20, TimeUnit.SECONDS);
if ((client != null) && (client.isOpen())) {
Thread.sleep(50); // *** if I do not sleep 50 milsec here, I will get empty string
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> readval = client.read(buffer);
String msg = new String(buffer.array()).trim();
System.out.println("Received from client: " + msg);
readval.get();
buffer.flip();
String str = "I am fine! Thanks.";
Future<Integer> writeVal = client.write(ByteBuffer.wrap(str.getBytes()));
System.out.println("Writing back to client: " + str);
writeVal.get();
buffer.clear();
}
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Client
{
public static void main( String[] args )
{
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
try (AsynchronousSocketChannel client = AsynchronousSocketChannel.open()) {
Future<Void> result = client.connect(new InetSocketAddress("127.0.0.1", 2001));
result.get();
String str = "Hello! How are you?";
ByteBuffer buffer = ByteBuffer.wrap(str.getBytes());
Future<Integer> writeval = client.write(buffer);
System.out.println("Writing to server: " + str);
writeval.get();
buffer.flip();
Thread.sleep(100); // If I do not sleep 100 milsec here, most of the time, I will get empty string for svrMsg
Future<Integer> readval = client.read(readBuffer);
String svrMsg = new String(readBuffer.array()).trim();
System.out.println("Received from server: " + svrMsg);
readval.get();
readBuffer.clear();
buffer.clear();
} catch (ExecutionException | IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("Disconnected from the server.");
}
}
}
I was hoping to get something like:
Server:
Received from client: Hello! How are you?
Writing back to client: I am fine! Thanks.
Client:
Writing to server: Hello! How are you?
Received from server: I am fine! Thanks.
But instead, I got:
Received from client: Hello! How are you? | (If do not use sleep, it is empty string here)
Writing back to client: I am fine! Thanks.
Client:
Writing to server: Hello! How are you?
Received from server: I am fine! Thanks.(If do not use sleep, empty string here)
My questions are:
1. I am using Eclipse, when I debug the server and client proj via breakpoints, I get the expected result. But when I run the server and the client, on the client side, if I do not use Thread.sleep(100), it will show empty string for "Received from server:", why?
2. And for the server side, if I do not sleep for 50 milseconds, most of the time, the output of "Received from client: " will be empty string as well, any tips?
Thank you very much guys for your help.
client.read(buffer); is an asynchronous operation. The get call on the future ensures that the operation has completed successfully.
ByteBuffer buffer = ByteBuffer.allocate(1024);
Future<Integer> readval = client.read(buffer);
readval.get();
String msg = new String(buffer.array()).trim();
System.out.println("Received from client: " + msg);
I'm having the following problem in java: I am developing and app using java.net.Socket. It looks like that: There is a server with a thread which accepts and adds new client, and another thread which reads data from sockets and does "something" with it. Next to it there are clients. Client has data reader thread as well as a separate thread. I send the data as simple as:
socket.getOutputStream().write((content+"\n").getBytes());
on the client side and read it on the server like:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String received;
while(true) {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
received = reader.readLine();
if(received == null) {
break;
}
System.out.println("SERVER " + received);
increaseReceivedCounter(1);
} catch(SocketException e) {
break;
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("SERVER RECEIVED "+ getReceivedCounter() + " MESSAGES!");
}
Now I just set the client to send some amount of messages like this:
try {
int n = 1000;
System.out.println("sending "+ n +" messages to " + client);
for(int i=0 ; i<n ; ++i) {
socket.getOutputStream().write((content+"\n").getBytes());
}
System.out.println("done sending " + n + " messages");
} catch (IOException e) {
e.printStackTrace();
}
The problem is that not all of the messages are transferred to a server. I have been looking for some solution for this but didn't manage to achieve 100% reliability. Is it even possible? I also tried with read instead of readLine but the result is the same: sometimes even 90% data loss. I think while server is working on the received data it ignores incoming packets and they're just lost.
Edit
Sockets initializations:
serverSocket = new ServerSocket(Server.PORT);//PORT = 9876, whatever
for the data reader on server side:
socket = serverSocket.accept();
on the client:
socket = new Socket("127.0.0.1", Server.PORT)
This is not an 'efficiency issue'. It is a bug in your code.
The problem is that not all of the messages are transferred to a server.
No, the problem is that you are losing data at the server. This is because you keep recreating BufferedReaders. You should create it once for the life of the socket.
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Remove this line.
The way you have it, you will lose data every time the prior BufferedReader has, err, buffered.
You also need to close the socket.
I have this class which opens a HTTP-Server and listens on a port. The reply is a http-header plus a json object. The class takes the input stream from the server, converts it to a string, filters the http header and parses the json object.
The thing is that the conversion from input stream to string is taking about 3 seconds. Is there a way to read the inputstream faster?
public class GamestateListener {
private static int PORT = 3001; // Port specified in your cfg
public static ServerSocket listenServer;
private static JSONObject MYJSONOBJ;
public GamestateListener() {
try {
listenServer = new ServerSocket(PORT); // open new Server Socket
System.out.println("Started Socket..."); // printing out started
// listening
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public JSONObject listenAndParseJSON() throws IOException {
System.out
.println("Listening for connection on port " + PORT + " ...."); // printing
// out
// started
// listening
try (Socket socket = listenServer.accept()) { // wait for connection
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
String responseString = IOUtils.toString(mis, "UTF-8");
System.out.println("Stop to String "
+ System.currentTimeMillis());
MYJSONOBJ = new JSONObject(responseString.substring(responseString
.indexOf("{")));// split the response string
return MYJSONOBJ;// return the json obj
} catch (Exception e) {
MYJSONOBJ = new JSONObject("{ERROR:True}");// create error obj
return MYJSONOBJ;// return it
}
}
}
You're not measuring what you think you are. Here:
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
... you seem to think that you've read all the data when getInputStream() returns. You haven't. You've just got a stream you can read from. It means there's a connection, but that's all.
If you want to measure how long it takes just to read all the data (and not actually process it) you could do something like:
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
byte[] buffer = new byte[8192];
// Read all the data (but ignore it)
while ((mis.read(buffer)) != -1) ;
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
Of course, there then won't be any data to read for the rest of the code, but you'll see how long just the data reading takes. My guess is that that'll be about 3 seconds... which could be due to slow networking, or the client taking a long time to even send all the data. (It could connect, sleep for 2.9 seconds and then send a bunch of data.)
Is this even possible? I have a java server program on a mac that I need to use to communicate back to a windows program. I have the client working in Java, but I can't seem to figure out how to get it to work in VB.net...
Here is the Java code...
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class socketClient {
public static void main(String[] args) {
/**
* Define a host server
*/
String host = "10.1.1.194";
/**
* Define a port
*/
int port = 19999;
StringBuffer instr = new StringBuffer();
String TimeStamp;
System.out.println("SocketClient initialized");
try {
//Obtain an address object of the server
InetAddress address = InetAddress.getByName(host);
//Establish a socket connection
Socket connection = new Socket(address, port);
//Instantiate a BufferedOutputStream object
BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream());
/**
* Instantiate an OutputStreamWriter object with the optional
* character encoding.
*/
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
TimeStamp = new java.util.Date().toString();
String process = "Initiate file transfer on " + host + " port " + port
+ " at " + TimeStamp + (char) 13;
//Write across the socket connection and flush the buffer
osw.write(process);
osw.flush();
/**
* Instantiate a BufferedInputStream object for reading /**
* Instantiate a BufferedInputStream object for reading incoming
* socket streams.
*/
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
/**
* Instantiate an InputStreamReader with the optional character
* encoding.
*/
InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");
//Read the socket's InputStream and append to a StringBuffer
int c;
while ((c = isr.read()) != 13) {
instr.append((char) c);
}
//Close the socket connection.
connection.close();
System.out.println(instr);
}
catch (IOException f)
{
System.out.println("IOException: " + f);
}
catch (Exception g)
{
System.out.println("Exception: " + g);
}
}
}
And here is my VB.NET code that I have so far...
Private clientSocket As Socket
Private host As String = "10.1.1.194"
Private port As Integer = 19999
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Try
Dim add As New IPEndPoint(IPAddress.Parse(host), port)
clientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
clientSocket.Connect(add)
Dim netStream As New NetworkStream(clientSocket, True)
Dim outstream As Byte() = System.Text.Encoding.ASCII.GetBytes("Initiate file transfer from " _
& System.Environment.MachineName & " on " & host & " port " & port & " at " & TimeOfDay)
netStream.Write(outstream, 0, outstream.Length)
netStream.Flush()
Catch ex As Exception
Debug.Write(ex.Message)
End Try
End Sub
Now, if I run the vb code, it hangs... and nothing appears in my console on the mac (Like it does when I use the java client), however, when I close the VB code, I get the java.net.SocketException: Connection reset error, so I must be getting pretty close to figuring this out.
The thing is, I know almost nothing when it comes to socket programming, so if someone could push me in the right direction, it would be very appreciated!
Is this even possible?
Yes.
I don't see you writing Carriage Return (13) character anywhere in your VB.NET example, yet you expect it to appear on a Java side in order to print something to the console.