I'm a amateur programmer and writing Java TCP socket client program that receives Integer and String type messages from the server(plc). Currently it works fine and returns correct values if using basic try catch without any loops to keep the program running.
But... I've been trying to add while loop with counter of 5 receive times that ends the program after that but it returns on ONE read:
Int: 705 //correct value that it should receive every time
String: testi3 //correct value that it should receive every time
Int: 0 // prints also this duplicate value
String: // prints also this duplicate value
How I should use the while loop in this case so it returns the correct values 5 times and then ends the program correctly?
My program looks like this:
import java.io.*;
import java.net.Socket;
import java.util.Arrays;
public class GetData2 {
private static int counter =0;
private Socket clientSocket;
//private PrintWriter out;
private String host = "192.168.0.1";
private int port2 = 2000;
private DataInputStream inFromServer;
public void start() throws IOException{
System.out.println("Client started");
clientSocket = new Socket(host, port2);
}
public void run() throws IOException {
while (counter <= 5) {
inFromServer = new DataInputStream(clientSocket.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int length = 100; // read length of incoming message
byte[] messageFromServer = new byte[length];
for (int i = 0; i < messageFromServer.length; i++) {
messageFromServer[i] = (byte) inFromServer.read(); //read message from the server
}
System.out.println("\n");
//System.out.println(Arrays.toString(messageFromServer));
byte[] copyOfData = Arrays.copyOf(messageFromServer, messageFromServer.length); //copies byte array from messageFromServer[] to copyOfData[]
System.out.println("\n");
//Integer
short value = 0;
// reads bytes 0-1
value = (short) (copyOfData[0] * 256 + (short) copyOfData[1]); // moves received bytes
// shows the order of received byes
System.out.println("Int: " + value); // return bytes as an Integer
//String
System.out.print("String: ");
for (int i = 4; i < copyOfData.length && i < 10; i++) { // reads bytes 4-10 from array
System.out.printf("%c", copyOfData[i]); // returns String testi2 from pythondemo 2 plc application
}
counter++;
System.out.println(counter);
}
}
public void stop() throws IOException{
//out.close();
System.out.println("Application stopped");
clientSocket.close();
inFromServer.close();
}
public static void main(String[] args) throws IOException {
GetData2 getData2 =new GetData2();
getData2.start();
getData2.run();
if(counter == 5){
getData2.stop();
}
}
}
EDIT:
Seems like if i change the received byte array length from [100] to [10], the program executes and prints this;
Client started
Int: 705
String: testi3
counter: 1
Int: 0
String:
counter: 2
Int: 0
String:
counter: 3
Int: 0
String:
counter: 4
Int: 0
String:
counter: 5
Application stopped
EDIT #2
So, I made server program that runs in localhost and sends byte[100] and it works correctly. Seems like problem is most likely in my PLC program, not in Java.
Server Class:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class GetData2_Server {
public static void main(String[] args) throws IOException {
System.out.println("server started");
Scanner scan = new Scanner(System.in);
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
System.out.println("server accepted");
System.out.println("1 == out n flush, 0 == close program");
int value = scan.nextInt();
byte[] bytesOut = new byte[100];
bytesOut[0]=0;
bytesOut[1]=3;
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
while (value == 1)
{
out.write(bytesOut);
out.flush();
value = scan.nextInt();
if(value == 0){
out.close();
socket.close();
}
}
}
}
in your while loop, you loop from 0 to 5, which means 6 times.
you may want to change this:
while (counter <= 5)
to this, so that it loops only 5 times:
while (counter < 5)
You are not taking into account that the device sending the data (I'll refer to it as "server" for short) may close the stream on its end. When this happens, inFromServer.read() will return -1. You're not checking for this value, so you will end up filling the messageFromServer array with -1 values.
If you know that the messages are supposed to be 100 bytes, you can read a message with a single DataInputStream method call, without a for loop. Replace your
for (int i = 0; i < messageFromServer.length; i++) with:
byte[] messageFromServer = new byte[length];
inFromServer.readFully(messageFromServer);
If the server stream is closed before the full message is read, this method will throw an exception (EOFException).
Related
Hi I'm having a small problem with my program which is a simple client/server. The client sends the contents of a textfile to the server. The text file is just ints and then the server is suppose to send back the largest prime number less than each int in the text file(if its prime it should just send back the prime number and do nothing). So for instance lets say the text file is 5 15 28. The result after running the program should be 5 13 23.
Here's my code for the Client side:
public class TCPClient {
public static void main(String[] args) throws Exception{
try{
Socket mySock = new Socket("127.0.0.1", 12001);
BufferedReader in = new BufferedReader(
new InputStreamReader(mySock.getInputStream()));
PrintStream out = new PrintStream( mySock.getOutputStream());
Scanner scan = new Scanner(new File(args[0]));
String msg = scan.nextLine();
out.println(msg);
System.out.println(in.readLine());
mySock.close();
}catch (Exception e){
}
}
}
Here's my code for the server side:
public class TCPServer {
public static void main(String[] args) throws Exception {
try{
ServerSocket mySock = new ServerSocket(12001);
Socket client = mySock.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintStream out = new PrintStream( client.getOutputStream());
String[] arr = in.readLine().split(" ");
int[] intarr = new int[arr.length];
for(int i = 0; i <arr.length; i++){
intarr[i] = Integer.parseInt(arr[i]);
if (prim(intarr[i]) == true){
out.println(intarr[i]);
}else{
while (!prim(--intarr[i])){
}
out.println(intarr[i]);
}
}
client.close();
mySock.close();
}catch (Exception e){
}
}
public static boolean prim(int m){
int n=m;
for(int i=2;i<n;i++){
if(n%i == 0){
return false;
}
}
return true;
}
}
When I run this program my output is only the first number in the text file. So if my text file is 1 3 5. My output is just 1. However, my prime algorithm is at least working because if my text file is 8 for instance, my program will return 7. Does anyone know why this is happening?
By change your server code to a simple test and printing to System.out
String[] arr = "1 3 5 6".split(" ");
int[] intarr = new int[arr.length];
for(int i = 0; i <arr.length; i++){
intarr[i] = Integer.parseInt(arr[i]);
if (prim(intarr[i]) == true){
System.out.println(intarr[i]);
}else{
while (!prim(--intarr[i])){
}
System.out.println(intarr[i]);
}
}
you can see that it works OK, but in your code, your output in writing using println, so your client needs to loop System.out.println(in.readLine()); or change your server to write using one line and some delimiter
In TCPServer, when printing to outputstream use print instead of println
for(int i = 0; i <arr.length; i++){
intarr[i] = Integer.parseInt(arr[i]);
if (prim(intarr[i]) == true){
out.print(intarr[i]); // use print instead of println
}else{
while (!prim(--intarr[i])){
}
out.print(intarr[i]); // use print instead of println
}
}
How do I receive an array of integers from a server program written in C, to a client program written in Java?
So I send a number to a server and the server should return me an array of the divisors for that number. Here's my piece of code from the server, in C:
void deservire_client(int c) {
// serving the client
int nr, i=2, nrDiv=0, sirDiv[10]={0,0,0,0,0,0,0,0,0,0};
recv(c, &nr, sizeof(nr), MSG_WAITALL);
nr = ntohs(nr);
while ( i <= nr/2){
if ( nr%i == 0){
sirDiv[nrDiv]=i;
nrDiv+=1;
}
i+=1;
}
send(c, &sirDiv, sizeof(sirDiv), 0);
close(c);
So I tested it out and the array of divisors is being created in the server file. As in, it takes the number I send it, and executes the program correctly, ending up with an array of the number's divisors. I then send the reference to my array back to my client program, in Java. However, I'm pretty sure I'm doing something wrong, since once I input a number in the client, nothing happens.
Here's what I'm doing in my Java client program:
public static void main(String args[]) {
Socket socket = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(System.in));
socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
int nr = readUnsignedShort("nr = ", reader);
byte[] arr = {0,0,0,0,0,0,0,0,0,0};
writeIntegersToSocket(nr, socket);
readArrayFromSocket(socket);
}
private static void readArrayFromSocket(Socket c) throws IOException {
DataInputStream socketIn = new DataInputStream(c.getInputStream());
int i;
InputStream in = c.getInputStream();
DataInputStream dis = new DataInputStream(in);
byte[] data = new byte[10];
dis.readFully(data);
for(i=0; i < data.length; i++)
System.out.println(" " + data[i]);
}
This question already has answers here:
Removing the first 16 bytes from a byte array
(4 answers)
Closed 3 years ago.
I have a byte array named byteArr[].I need to remove first 4 bytes from it.My code is shown below. Here I use the byte array to store the input string.I got some unwanted byte with the output i.e the first four bytes is not needed from the fifth onwards is correct. My program is to take id from respected rfid tag using an rfid machine.
public class Serverc {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static void connection() throws IOException {
ServerSocket ss = new ServerSocket(9888);//exce
ss.setSoTimeout(300000000);//exce
System.out.println("Waiting for client on port " + ss.getLocalPort() + "...");
while (true) {
Socket server = ss.accept();//exce
System.out.println("Just connected to " + server.getRemoteSocketAddress());
int available = 0;
DataInputStream in = new DataInputStream(server.getInputStream());//exce
int input = 0;
//BufferedReader br = new BufferedReader(in);
byte byteArr[] = new byte[28];
try {
//read till the end of stream
//while((input = in.available()) != -1)
while ((input = in.read(byteArr)) != -1) {
System.out.println("Size read is " + input);
System.out.println("Data is " + bytesToHex(byteArr));
}
//System.out.println("inside finally");
server.close();//exce
//System.out.println("outside finally");
} catch (SocketTimeoutException ex) {
System.out.println("Socket timed out!");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws IOException {
Serverc obj = new Serverc();
obj.connection();
}
}
Here is my console
Waiting for client on port 9888...
Just connected to /106.208.71.50:61532
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Here I need to remove 55000016 from the output.
Advance thanks
You could use Arrays.copyOfRange method to filter the unwanted bytes and save the result to a new byte array.
byte[] filteredByteArray = Arrays.copyOfRange(byteArr, 4, byteArr.length);
If you want to skip the first four bytes change this,
for (int j = 0; j < bytes.length; j++) {
to something like
for (int j = 4; j < bytes.length; j++) {
Or you might use String.substring(int)
bytesToHex(byteArr).substring(8); // <-- skip the first 4 bytes
You have a larger problem than skipping the 4 bytes at the start of each of your packets. Your code does this:
byte byteArr[] = new byte[28];
try {
while ((input = in.read(byteArr)) != -1) {
System.out.println("Size read is " + input);
System.out.println("Data is " + bytesToHex(byteArr));
}
(commented-out lines removed)
Note that you cannot guarantee that all 28 bytes will be read on each call to in.read(), but that your bytesToHex() method is assuming that 28 valid bytes are present in the array. You need to collect data that you read into the array until you have all of your packet before processing it, probably using a DataInputStream with the method readFully(byte[]). Then you can skip the first 4 bytes as suggested in the other answers.
It is best for you to skip the 4 bytes. But if you want to remove them, you should use this solution (your array may become massive). This algorithm is best you can get in Java for your problem. O(1) space , O(n) time.
void removeFourBytes(byte[] a) {
for (int i = 4; i < a.length; i++) {
a[i-4]=a[i];
}
for (int i = a.length - 1; i > a.length - 5; i--) {
a[i] = 0;
}
}
Second best option would be System.arrayCopy() - O(n) space, O(n) time.
After browsing some other threads regarding my problem I think I've understood that I need to re-design my application. But just for clarification: I have a single TCP/IP connection between a client and a server. On the client side there are a number of threads running concurrently. Randomly one or more of these threads use the TCP/IP connection to communicate with the server. I've found out that, e. g. While a long running file transfer is active, using the connection with another thread concurrently might lead to errors. Though I've preceeded each message with a specific header including the data length it appears to me that the IP stack sometimes delivers a mix of more than one messages to my program, which means that though one message has net yet been delivered completely, part of another message is delivered to my read method. Is this a correct observation which matches the intended TCP/IP behaviour? Thanks in advance - Mario
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
For anybody who's interested: following is the source code of my test program. You may play with various values for the BUFFER_SIZE and the number of THREADS used to bombard the server socket with concurrent TCP/IP sends using the same socket. I've left out some error handling and removed a more sophisticated termination including the closing of the sockets. Test with a BUFFER_SIZE greater than 64KB always leads to errors on my machine.
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
public class TCPTest
{
private final static String INPUT_FILE = "c:/temp/tcptest.in";
private final static int BUFFER_SIZE = 64 * 1024 - 8; //65536;
private final static int MESSAGE_SIZE = 512 * 64 * 1024;
private final static int THREADS = 3;
private final static int SIZE_OF_INT = 4;
private final static int LENGTH_SIZE = SIZE_OF_INT;
private final static int ID_SIZE = SIZE_OF_INT;
private final static int HEADER_SIZE = LENGTH_SIZE + ID_SIZE;
private final static String NEW_LINE = System.getProperty("line.separator");
private ServerSocket m_serverSocket = null;
private Socket m_clientSocket = null;
private int m_iThreadCounter;
public static void main(String[] args)
{
new TCPTest();
} // main
public TCPTest()
{
final String id = "ReaderThread[*]";
// start a new thread creating a server socket waiting for connections
new Thread(new Runnable()
{
public void run()
{
try
{
// create server socket and accept client requests
m_serverSocket = new ServerSocket(12345);
m_clientSocket = m_serverSocket.accept();
// client request => prepare and read data
long startTime = System.currentTimeMillis();
byte[] buffer = new byte[BUFFER_SIZE];
ByteBuffer header = ByteBuffer.allocate(HEADER_SIZE);
int iTotalBytesRead = 0;
boolean fTerminate = false;
int iBytesRead;
// get hold of socket's input stream
InputStream clientInputStream = m_clientSocket.getInputStream();
// loop
while (false == fTerminate)
{
// loop to read next header
for (int i = 0; i < HEADER_SIZE; i++)
clientInputStream.read(header.array(), i, 1);
header.rewind();
// get information of interest
int iLength = header.getInt();
int iId = header.getInt();
int iLengthSoFar = 0;
int iBytesLeft = iLength;
int iBytesToRead;
// any length given?
if ((0 < iLength) && (BUFFER_SIZE >= iLength))
{
// that's the case => read complete message
while (iLengthSoFar < iLength)
{
// calculate number of bytes left
iBytesLeft = iLength - iLengthSoFar;
// calculate maximum number of bytes to read
if (iBytesLeft > BUFFER_SIZE)
iBytesToRead = BUFFER_SIZE;
else
iBytesToRead = iBytesLeft;
// read next portion of bytes
if ((iBytesRead = clientInputStream.read(buffer, 0, iBytesToRead)) != -1)
{
// maintain statistics
iTotalBytesRead += iBytesRead;
iLengthSoFar += iBytesRead;
} // if
else
{
// finish => print message
System.out.println("==> "+id+": ERROR length=<-1> received " +
"for id=<"+iId+">");
fTerminate = true;
break;
} // else
} // while
} // if
else
{
System.out.println("==> "+id+": ERROR data length <= 0 for id=<"+iId+">");
dump(header, 0, HEADER_SIZE / SIZE_OF_INT, "Error header");
} // else
} // while
System.out.println("==> "+id+": "+ iTotalBytesRead + " bytes read in "
+ (System.currentTimeMillis() - startTime) + " ms.");
} // try
catch (IOException e)
{
e.printStackTrace();
} // catch
} // run
}).start();
// create the socket writer threads
try
{
// ensure server is brought up and request a connection
Thread.sleep(1000);
System.out.println("==> "+id+": just awoke");
Socket socket = new Socket("localhost", 12345);
OutputStream socketOutputStream = socket.getOutputStream();
System.out.println("==> "+id+": socket obtained");
// create some writer threads
for (int i = 0; i < THREADS; i++)
// create a new socket writer and start the thread
(new SocketWriter(socket,
(i+1),
BUFFER_SIZE,
new String("WriterThread["+(i+1)+"]"),
socketOutputStream)).start();
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch
} // TCPTestEx
private final static void dump(ByteBuffer bb, int iOffset, int iInts, String header)
{
System.out.println(header);
bb.rewind();
for (int i = 0; i < iInts; i++)
System.out.print(" " + Integer.toHexString(bb.getInt()).toUpperCase());
System.out.print(NEW_LINE);
} // dump
private class SocketWriter extends Thread
{
Socket m_socket;
int m_iId;
int m_iBufferSize;
String m_id;
OutputStream m_os;
protected SocketWriter(Socket socket, int iId, int iBufferSize, String id, OutputStream os)
{
m_socket = socket;
m_iId = iId;
m_iBufferSize = iBufferSize;
m_id = id;
m_os = os;
// increment thread counter
synchronized (m_serverSocket)
{
m_iThreadCounter++;
} // synchronized
} // SocketWriter
public final void run()
{
try
{
long startTime = System.currentTimeMillis();
ByteBuffer buffer = ByteBuffer.allocate(m_iBufferSize + HEADER_SIZE);
int iTotalBytesRead = 0;
int iNextMessageSize = 512 * m_iBufferSize;
int iBytesRead;
// open input stream for file to read and send
FileInputStream fileInputStream = new FileInputStream(INPUT_FILE);
System.out.println("==> "+m_id+": file input stream obtained");
// loop to read complete file
while (-1 != (iBytesRead = fileInputStream.read(buffer.array(), HEADER_SIZE, m_iBufferSize)))
{
// add length and id to buffer and write over TCP
buffer.putInt(0, iBytesRead);
buffer.putInt(LENGTH_SIZE, m_iId);
m_os.write(buffer.array(), 0, HEADER_SIZE + iBytesRead);
// maintain statistics and print message if so desired
iTotalBytesRead += iBytesRead;
if (iNextMessageSize <= iTotalBytesRead)
{
System.out.println("==> "+m_id+": <"+iTotalBytesRead+"> bytes processed");
iNextMessageSize += MESSAGE_SIZE;
} // if
} // while
// close my file input stream
fileInputStream.close();
System.out.println("==> "+m_id+": file input stream closed");
System.out.println("==> "+m_id+": <"+ iTotalBytesRead + "> bytes written in "
+ (System.currentTimeMillis() - startTime) + " ms.");
// decrement thread counter
synchronized (m_serverSocket)
{
m_iThreadCounter--;
// last thread?
if (0 >= m_iThreadCounter)
// that's the case => terminate
System.exit(0);
} // synchronized
} // try
catch (Exception e)
{
e.printStackTrace();
} // catch
} // run
} // SocketWriter
} // TCPTest
Yer. TCP is a byte oriented stream protocol. That means that the application receives an (undelimited) stream of bytes. The concept of "message" should be provided by the application (or use a message oriented protocol instead).
In this program, my server takes a command followed by 1 or 2 operands from the client and returns the result of the operation.
I am having trouble in scanning the line of client input and in performing the actual operation in the switch statement, if anyone could point me in the right direction I would appreciate it.
Here is the code:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
// Takes in a mathematical operation and the operands from a client and returns the result
// Valid operations are add, sub, multiply, power, divide, remainder, square
public class MathServer
{
public static void main(String [] args) throws IOException
{
ServerSocket yourSock = new ServerSocket(50000); //put server online
while(true)
{
System.out.println("Waiting to accept connection");
Socket clientSock = yourSock.accept(); //open server to connections
System.out.println("Connection accepted");
process(clientSock); //process accepted connection
System.out.println("Connection closed");
}
}
//BufferedReader(Reader r)
static void process(Socket sock) throws IOException
{
InputStream in = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
OutputStream out = sock.getOutputStream();
PrintWriter pw = new PrintWriter(out, true);
String input = br.readLine(); //get user input from client
while(input != null && !input.equals("bye")) //check for input, if bye exit connection
{
int answer = operate(input); //perform desired operation on user input
pw.println(answer); //print out result
input = br.readLine(); //get next line of input
}
sock.close();
}
//Talk to the client
static int operate(String s)
{
System.out.println(s); //check if same as client input
Scanner myScanner = new Scanner(s);
String opType = myScanner.next(); //gets desired operation
System.out.println(opType); //checks for correct operation
switch (opType) {
case "add":
return (myScanner.nextInt() + myScanner.nextInt());
case "sub":
return (myScanner.nextInt() - myScanner.nextInt());
case "multiply":
return (myScanner.nextInt() * myScanner.nextInt());
case "power":
return (int) Math.pow(myScanner.nextInt(), myScanner.nextInt());
case "divide":
return myScanner.nextInt() / myScanner.nextInt();
case "remainder":
return myScanner.nextInt() % myScanner.nextInt();
case "square":
return (int) Math.pow(myScanner.nextInt(), 2);
default:
return (int) Math.pow(myScanner.nextInt(), 3);
}
}
}
As you're reading with BufferedReade.readLine() in your server, make sure you send a newline character from your client (common mistake). Also you may need to flush the OutputStream from your client. Because of the way that your Scanner reads in variables, you need to send in values on a single line from your client, e.g.
add 100 200
switch(opType) won't work for strings.
check with something like
if(opType.equals("add")){ //do Add }
else if(opType.equals("sub")){ //do subtraction }
etc.