i shall implement a UDP-based client/server application and im new in the world of Java. The Server implements a simple request-acknowledge protocol upon the UDP protocol. For a received string identifier (command) with optional parameters the server returns a specified result. For example "thread" returns a random integer number between 1 and 5 and length returns a random integer number between 5 and 25.
The questions is did i do the implementation right and how can i fix my problem (length nr is always between 1 and 5). I think my problem is that in the server class the if statements are not checked. Is there some other way to send a comand to a server i tried here to do it with sending strings then trying to check it with if statements?
and thats my code (Server):
public class server {
public static void main(String[] args) throws IOException, InterruptedException {
DatagramSocket skt;
try {
skt = new DatagramSocket(1252);
byte [] buffer = new byte[1000];
while(true){
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
skt.receive(request);
String arrayMsg = new String(request.getData());
System.out.println(arrayMsg);
//check if the client asks for threadnr
if(arrayMsg.equals("thread")){
int threadnumber = (int) (Math.random()*5)+1;
String threadnum = Integer.toString(threadnumber);
byte [] b = threadnum.getBytes();
DatagramPacket reply = new DatagramPacket(b, b.length, request.getAddress(), request.getPort());
skt.send(reply);;}
//check if the client asks for lengthnr
else if(arrayMsg.equals("length")){
int lengthnumber = (int) (Math.random()*25)+5;
String lengthnum = Integer.toString(lengthnumber);
byte [] b = lengthnum.getBytes();
DatagramPacket reply = new DatagramPacket(b, b.length,request.getAddress(), request.getPort());
skt.send(reply);}
}}
catch (SocketException e) {
System.out.println("UDP Port 9876 is occupied.");
System.exit(1);
}}}
thats my Client:
public class client {
public static void main(String[] args) throws UnknownHostException, IOException {
DatagramSocket skt = new DatagramSocket();
InetAddress host = InetAddress.getByName("localhost");
int serverSocket = 1252;
byte [] senddata = new byte [1000];
byte [] getdata = new byte[1000];
//thread send request
String th = "thread";
senddata = th.getBytes();
DatagramPacket requestth = new DatagramPacket(senddata, senddata.length, host, serverSocket);
skt.send(requestth);
//thread get reply
DatagramPacket replyth = new DatagramPacket ( getdata, getdata.length);
skt.receive(replyth);
String arrayth = new String(replyth.getData());
int threadnr=Integer.parseInt(arrayth.trim()); //convert thread string to int and trim it (whitespace)
System.out.println("Thread received " + threadnr);
//length send request
String lg = "length";
senddata = lg.getBytes();
DatagramPacket requestlg = new DatagramPacket(senddata, senddata.length, host, serverSocket);
skt.send(requestlg);
//length get reply
DatagramPacket replylg = new DatagramPacket ( getdata, getdata.length);
skt.receive(replylg);
String arraylg = new String(replyth.getData());
int lengthnr=Integer.parseInt(arraylg.trim()); //convert thread string to int and trim it (whitespace)
System.out.println("Length received " + lengthnr);
skt.close();
And all i get is something like this:
Thread received 3
Length received 1
(Length should be between 5 and 25 and in my case its never bigger then 5)
The code parses the response from the first message instead of from the last, so you get the random 1-5. I suggest using better names for the variables and you'll spot the problem quicker.
Related
I wanna do a simple application to transfer integers via DatagramSockets, but I didn't want to do workarounds like using Strings and casting them to int, I'd rather know if there is a adhoc way to pass integers via DatagramSocket.
//sender side
public void Send() throws Exception {
DatagramSocket socket = new DatagramSocket(3000);
int x = 5;
DatagramPacket sendPacket = ...
socket.send(sendPacket);
}
//reeceiver side
public void Receive() throws Exception {
DatagramSocket socket = new DatagramSocket(2000);
DatagramPacket receivePacket = ...
socket.receive(receivePacket);
int x = (int) receivePacket;
}
Part of this code is just to demonstrate what I want. I'd like to know how to write an int in the sender side and how to read this int in the receiver side.
Use a ByteBuffer.
SocketAddress address = ...
int value = ...
byte[] buf = ByteBuffer.allocate(Integer.BYTES).putInt(value).array();
socket.send(new DatagramPacket(buf, buf.length, address));
I'm making a simple client server program. When the client sends the string "start", I want the server to start executing some code. Right now, I have the client sending a datagram packet with the message "start", the server gets the byte buffer from the packet, turns it into a string, and then compares that string value with the string literal "start". Obviously I'm doing something wrong because my code never enters the for loop of if(sentence.equals(start){ System.out.println("ok");}
My code:
public static void main(String args[]) throws IOException{
byte[] receiveData;
byte[] sendData;
DatagramSocket serverSocket = new DatagramSocket(2014);
while(true){
receiveData = new byte[15];
DatagramPacket frame = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(frame);
InetAddress IPaddress = frame.getAddress();
System.out.println("INET " + IPaddress);
byte[] data;
int port = frame.getPort();
System.out.println("port " + port);
String sentence = new String(frame.getData());
String start = new String("start");
System.out.println("RECEIVED FROM CLIENT: " + sentence);
if(sentence.equals(start)){
System.out.println("ok");
}
}
}
Make the following change.
String sentence = new String(frame.getData(), 0, frame.getLength());
Here are simple UDP client-server classes:
UDPServer:
import java.net.*;
/**
* Source:https://systembash.com/a-simple-java-udp-server-and-udp-client/
*
*/
class UDPServer {
public static void main(String args[]) throws Exception {
DatagramSocket serverSocket = new DatagramSocket(9876);
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String(receivePacket.getData());
// Sentence here is not equal "PING" ?
if(sentence.equals("PING")) {
System.out.println("It is PING: " + sentence);
} else {
System.out.println(sentence.getClass());
System.out.println("It is not equal PING. It is <" + sentence + ">");
}
System.out.println("RECEIVED: " + sentence);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
String capitalizedSentence = "PONG";
sendData = capitalizedSentence.getBytes();
DatagramPacket sendPacket
= new DatagramPacket(sendData, sendData.length, IPAddress, port);
serverSocket.send(sendPacket);
}
}
}
UDPClient:
import java.net.*;
/**
* Source:
* https://systembash.com/a-simple-java-udp-server-and-udp-client/
*
* #author
*/
class UDPClient {
public static void main(String args[]) throws Exception {
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("localhost");
byte[] sendData = new byte[1024];
byte[] receiveData = new byte[1024];
String sentence = "PING";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 9876);
clientSocket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
String modifiedSentence = new String(receivePacket.getData());
System.out.println("FROM SERVER:" + modifiedSentence);
clientSocket.close();
}
}
In the UDPServer there's a check for the response (variable sentence). For some reason the equals doesn't detect the "PING" when it has to. Moreover it outputs the sentence string is "PING", class string.
Why is that ?
The output of the UDPServer is the else:
class java.lang.String
It is not equal PING. It is:<PING>
RECEIVED: PING
If it matters the java version is "1.7.0_91".
getData() gives you a buffer from which you can obtain your data.
Don't use trim() as this could remove characters you actually want to keep (apart from being expensive)
Instead you should use the length of the message
String sentence = new String(receivePacket.getData(), 0, receivePacket.getLength());
This way you will only extract to portion of the buffer with data you want.
The getData method of DatagramPacket returns the underlying buffer, which is the 1024 byte buffer you created earlier. You create a String from this buffer. All bytes not filled in will be 0 (default initialized), so your String will contain a lot of additional zero's. That's why the equals method returns false. You could solve this with the trim method if you're sure the messages sent will not have leading or trailing whitespaces (or at least, none that matter to the rest of the program).
You are not getting true when calling equals because the response is 1024 bytes long. You can trim your response on UDPServer to solve this:
String sentence = new String(receivePacket.getData()).trim();
This is more a follow up to a previous question asked earlier however I have modified my original code now, to be able to send a file Instead of text) via a UDP socket with a specific packet size. The program runs perfectly if I specify a 1, 2 or 4 byte packet, however if I try for anything larger, such as a 8, 16 etc, the program grinds to a halt. No exception is thrown in the console, however Netbeans shows a tiny warning symbol in the bottom right hand corner and shows the following.
java.lang.IllegalArgumentException: Contents must be presorted - added value 42318 is less than preceding value 42320
at org.netbeans.core.output2.IntList.add(IntList.java:76)
at org.netbeans.core.output2.AbstractLines.addTabAt(AbstractLines.java:1122)
at org.netbeans.core.output2.OutWriter.doWrite(OutWriter.java:452)
at org.netbeans.core.output2.OutWriter.write(OutWriter.java:506)
at java.io.PrintWriter.write(PrintWriter.java:456)
at java.io.PrintWriter.write(PrintWriter.java:473)
at org.apache.tools.ant.module.bridge.impl.ForkedJavaOverride$Copier.maybeFlush(ForkedJavaOverride.java:350)
at org.apache.tools.ant.module.bridge.impl.ForkedJavaOverride$Copier.access$000(ForkedJavaOverride.java:251)
at org.apache.tools.ant.module.bridge.impl.ForkedJavaOverride$Copier$1.run(ForkedJavaOverride.java:271)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1432)
[catch] at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2044)
Is this error thrown because of the UDP Packets being received out of order by any chance? Is there a way to ignore this? I can tell the program has ceased as the string of "The End" does not appear. Does anyone know why this may be? My code for my client socket is attached below (its a bit of a long one and lots of comments for my own sanity). Many thanks in advance for any guidance.
public class UDPClient extends variable {
// static Integer portNo = 4444;
static Integer byteSize = 16;
public static void main(String[] args) throws Exception { //taken out main from here
SocketForm form = new SocketForm();
File file=null;
long startTime; // Starting time of program, in milliseconds.
long endTime; // Time when computations are done, in milliseconds.
double time;
//get server address
String serverName = "localhost";
if (args.length >= 1)
serverName = args[0];
InetAddress serverIPAddress = InetAddress.getByName(serverName);
//get server port;
int serverPort = form.cliportNo;
if (args.length >= 2)
serverPort = Integer.parseInt(args[1]);
//create socket
DatagramSocket clientSocket = new DatagramSocket();
//get input from keybaord
byte[] sendData = new byte[byteSize];
//BufferedReader inFromUser = new BufferedReader(new InputStreamReader (System.in));
//while (true){
//String sentence = inFromUser.readLine();
startTime = System.currentTimeMillis();
//sendData = sentence.getBytes();
String fileName = "/Users/Andrew/Desktop/pic.jpg";
File f = new File(fileName);
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
System.out.println("Total file size to read in bytes is : " + fis.available());
} catch (IOException e) {}
Path path = Paths.get("/Users/Andrew/Desktop/pic.jpg");
//byte[] data = Fles.readAllBytes(path);
sendData = Files.readAllBytes(path);
try {
for( int index = 0; index < sendData.length ; index += byteSize ) {
DatagramPacket packet = new DatagramPacket( sendData, index, Math.min( byteSize, sendData.length-index ), serverIPAddress, serverPort);
clientSocket.send(packet);
//DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverIPAddress, serverPort);
//receive datagram
byte[] receiveData = new byte [byteSize];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
//print output
String sentenceFromServer = new String(receivePacket.getData());
System.out.println("From Server:" + sentenceFromServer);
}
System.out.println("The End");
}
catch (Exception e) {}
//close client socket
//clientSocket.close();
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("Time :" + time);
// }
} //end of main
} //end of UDPClient
Solved. Was running 7.3 of Netbeans. It is a known issue in 7.3 and has been addressed in the latest revision of 7.4. Solution : Update to Netbeans 7.4. Now purring like a cat. Thanks to all those who tried to help with this!
I'm using the following code to send Hello, world! to a multicast group with Java.
InetSocketAddress sa = new InetSocketAddress("239.0.0.1", 12345);
MulticastSocket s = new MulticastSocket(sa);
s.setTimeToLive(255);
s.joinGroup(sa.getAddress());
byte[] sbuf = "Hello, world!".getBytes();
DatagramPacket sp = new DatagramPacket(sbuf, sbuf.length, sa);
s.send(sp);
byte[] rbuf = new byte[1024];
DatagramPacket rp = new DatagramPacket(rbuf, rbuf.length);
s.receive(rp);
System.out.format("Received \"%s\".\n", new String(rbuf));
s.leaveGroup(sa.getAddress());
s.close();
For some reason, the code always throws an exception like this:
java.io.Exception: Invalid argument
at java.net.PlainDatagramSocketImpl.send(Native Method)
at java.net.DatagramSocket.send(...)
at ...
Why is this? How can I fix it?
To get data:
InetAddress group;
int port;
group = InetAddress.getByName("239.0.0.1");
port = Integer.parseInt("12345");
//create Multicast socket to to pretending group
MulticastSocket s = new MulticastSocket(port);
s.joinGroup(group);
while(running){
s.receive(pkt);
System.out.println();
String msg_rec;
msg_rec = new String(pkt.getData(), 0, pkt.getLength());
System.out.println("(FROM:" + pkt.getAddress()+ ") "+ msg_rec);
System.out.println();
}
To send data:
String msgToSend = "Hello, world!";
dgram = new DatagramPacket(msgToSend.getBytes(), msgToSend.length(), group ,port);
s.send(dgram);
You are calling send() on an unconnected DatagramSocket with a DatagramPacket that doesn't contain a destination address:port. So there is nowhere to send it to. If you mean to send to the multicast address, you need to say so, by doing either of he things mentioned in the first sentence. Joining the group doesn't do that: it only affects receiving.