The following code is used to send over a simple string in the following formart "address,porttNum".
Here is the client side:
ByteArrayInputStream bin = new ByteArrayInputStream(packet.getData());
DataInputStream dis = new DataInputStream(bin);
try {
System.out.println("Data in packet: " + dis.readLine());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Here is the server side:
byte[] sbuf = data.getBytes();
// sbuf = output.getBytes();
packet = new DatagramPacket(sbuf,
sbuf.length, packet.getAddress(), packet.getPort());
try {
socket = new DatagramSocket();
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
Say the server sends "abcdefghi", the client only recieves "abcde". I have tried it with multiple test cases and the client always recieves 5 bytes. Can anyone point out where I messed up?
edit:
For debugging purposes I even added the following:
try {
System.out.println("Data in packet: " + dis.readLine());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
which outputs the right data the client still does not get it.
edit 2:
I changed the client side to the following:
String data = new String(packet.getData(), StandardCharsets.UTF_8);
System.out.println("Data in packet: " + data);
It makes no difference.
Here is some example code showing construction of a Datagram packet from the bytes of a String, sending it, and reconstruction of the String.
Notice that the buffer for receiving a packet is created much larger than the message that is eventually received. This is necessary as the the UDP socket will truncate the message to the size of the buffer if it receives a message larger than the buffer. For example, if the client sent the message "ZYXWV" to the server, and only created the buffer large enough for that message, and then reused the buffer for the incoming message, only the first 5 characters of the incoming message would be received.
public class DataGram {
public static void main(String[] args) throws SocketException {
new Thread(new Client()).start();
new Thread(new Server()).start();
}
static class Client implements Runnable {
DatagramSocket socket;
Client() throws SocketException {
socket = new DatagramSocket(1234);
}
#Override
public void run() {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
try {
socket.receive(packet);
String msg = new String(packet.getData());
System.out.println(msg);
} finally {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class Server implements Runnable {
#Override
public void run() {
SocketAddress address = new InetSocketAddress("localhost", 1234);
try (DatagramSocket socket = new DatagramSocket()) {
String msg = "abcdefghi";
byte[] buf = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
No DataInputStream or ByteArrayInputStream is used here, since you can directly convert a String to byte[] and back again.
Related
So in my code below i have a singlethreaded server and a multithreaded client. The reason for this is because i want the client to send packets and receive packets simultaneously. However when i start the server and run multiple clients the server can process multiple clients simultaneously even tough the server is not multithreaded? Can you explain this?
Server:
public class server {
public static void main(String[] args) throws IOException{
new server();
}
//declare the UDP server socket
DatagramSocket datagramSocket;
int port = 3741;
public server() throws IOException {
//create UDP server with a specific port number
datagramSocket = new DatagramSocket(port);
System.out.println("[UDP server] Datagram socket started on port " + port);
//prepare the packet structure for received packets
int dataLength = 100; //must be large enough so some part of packet doesn't get lost
byte[] receiveData = new byte[dataLength];
DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length);
while(true) {
datagramSocket.receive(packet);
System.out.println("client connected");
InetAddress inetAddress = packet.getAddress();
int clientPort = packet.getPort();
byte[] data = packet.getData();
//send response back to the client host
byte[] sendData = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(data, data.length, inetAddress, clientPort);
datagramSocket.send(datagramPacket); //sending data from server to client
}
}
}
Client:
public class client {
public static void main(String[] args) throws Exception {
new client();
}
public client() throws Exception{
DatagramSocket socket = new DatagramSocket();
InetAddress ip = InetAddress.getByName("127.0.0.1");
String message = "hello from client";
DatagramPacket packetSend = new DatagramPacket(message.getBytes(), message.getBytes().length, ip, 3741);
Thread th = new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 100; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
socket.send(packetSend);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
th.start();
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//this part can't be in a thread because the loop above us will finish first before this starts
//we can put this code before the loop and start a thread this would also work
while(true) {
try {
socket.receive(packet);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String data = new String(packet.getData()).trim();
System.out.println(data);
}
}
}
You think "the server can process multiple clients simultaneously even tough the server is not multithreaded" cause your brain cheat you. Acutually they are processing one by one in a reliatively fast speed. It's easy to see if you use wireshark or tcpdump to capture the server side packets. You will find the interesing truth.
So my application is a very simple. If you type something through the scanner it sends it over to the server, the server sends it back to client. However, i don't understand why we have to put our code where we handle our receiving packets from the server into a thread?
The code below works fine but if i don't use use multithreading then the application doesn't work. The part where i send packets also stop working. Could you explain why this happens?
public class Client {
private static DatagramSocket socket = null;
public static void main(String[] args) {
System.out.println("Send to server:");
Scanner scanner = new Scanner(System.in);
while (true) {
try {
// port shoudn't be the same as in TCP but the port in the datagram packet must
// be the same!
socket = new DatagramSocket();
} catch (SocketException e1) {
System.out.println("[CLIENT] Unable to initiate DatagramSocket");
}
InetAddress ip = null;
try {
ip = InetAddress.getByName("127.0.0.1");
} catch (UnknownHostException e) {
System.out.println("[CLIENT] Unable to determine server IP");
}
// must be in a while loop so we can continuously send messages to server
String message = null;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
receive();
}
});
thread.start();
while (scanner.hasNextLine()) {
message = scanner.nextLine();
byte[] buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, ip, 6066);
try {
socket.send(packet);
} catch (IOException e) {
System.out.println("[CLIENT] Unable to send packet to server");
}
}
}
}
private static void receive() {
// receiving from server
byte[] buffer2 = new byte[100];
DatagramPacket ps = new DatagramPacket(buffer2, buffer2.length);
while (true) {
try {
socket.receive(ps);
} catch (IOException e) {
System.out.println("[CLIENT] Unable to receive packets from server.");
}
System.out.println("[SERVER] " + new String(ps.getData()));
}
}
}
If you type something through the scanner it sends it over to the
server, the server sends it back to client.
So the main method runs on the main thread and does some job. The job that you just referenced.
Read some user input plus the following part
while (scanner.hasNextLine()) {
message = scanner.nextLine();
byte[] buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, ip, 6066);
try {
socket.send(packet);
} catch (IOException e) {
System.out.println("[CLIENT] Unable to send packet to server");
}
}
Title: receive packets from an UDP server
You want to receive packets but you don't want to block the user from typing something as input and sending it to the server.
Therefore you need to do 2 jobs simultaneously. AKA multithreading
I made a client and server that use UDP protocol. I know that UDP is not very reliable and data can get lost but I run everything on my local host and the size of data that i send is only about 10 bytes.
The problem is that when server sends 4 bytes client receives only the first byte but when server sends
50 or 1000 bytes client receives... only first byte of data?! Yeah, exactly 1 byte (sometimes 2 or 3 but no more)! I have no idea whats going on. Is there an error in my code or this is fault of UDP?
Here is code of client
public void connect(String ip, int port) {
try {
adress = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
error("UnknownHostException");
e.printStackTrace();
}
try {
noErrors = true;
socket = new DatagramSocket();
socket.setSoTimeout(5000);
socket.connect(adress, port);
confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);
preapreConfirmation();
logIn();
} catch (SocketException e) {
error("Cannot connect");
e.printStackTrace();
}
}
private void logIn(){
String s;
while (noErrors) {// Sending request for connecting
sendRequest("2");
s = new String(packet.getData());
if (s.contains("2")) { // Connection was accepted
break;
} else if (s.contains("1")) {// Connection was refused
disconnect();
error("Connection refused");
break;
}
}
while(noErrors){ //loding map data: name
sendRequest("4"); // ask about world name
s = new String(packet.getData());
try {
System.out.println(s+" BYTES:"+s.getBytes().length+" "+socket.getReceiveBufferSize());
} catch (SocketException e) {
e.printStackTrace();
}
if(s.startsWith("4")){//world name was given
if( s.split("_").length>1){
mapname = s.split("_")[1];
break;
}
}
}
while (noErrors) { // loding map data: hash
sendRequest("6"); // ask about world hash
s = new String(packet.getData());
if (s.startsWith("6")) {
if (s.contains("h")) { // world hash was given
maphash = parse(s, 1);
break;
}
}
}
if(!noErrors)return;
System.out.println(maphash+" ==> "+ Screen.game.getHash(mapname)+" ("+mapname+")");
if (Screen.game.checkIfWorldExists(maphash, mapname)) { //validating world
Screen.game.loadMap(mapname);
Screen.setState(GameStates.GAME);
} else {
sendCommand("0");
}
isLogged = true;
}
public void sendRequest(){
try {
socket.send(packet);//Sending data
try{
socket.receive(packet);//receiving answer
} catch(PortUnreachableException ee){
error("Cannot connect");
} catch(SocketTimeoutException e){
error("End of stream");
}
socket.send(confirmation);//Sending confirmation of receiving answer
} catch (IOException e) {
error("IOException");
e.printStackTrace();
}
}
private void error(String message){
noErrors = false;
Screen.setErrorState(message);
}
public void sendCommand(){
try {
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
and here is code of server:
public void run() {
System.out.println("Server is waiting for data from socket");
while (isRunning) {
try {
buf = new byte[256];
// receives request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println("packet received");
// creating response
setCommand(new String(packet.getData(), "UTF-8"));
String d = getNextQuote(getCommand());
// sends the response to the client. "address" and "port" are
// already saved in last received packet
InetAddress address = packet.getAddress();
int port = packet.getPort();
System.out.println(">"+getCommand()+"\n<"+d);
if(d.equals("7")){
for(String g:packages){
buf = g.getBytes();
packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
}
} else {
buf = d.getBytes();
packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
}
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
}
}
System.err.println("Server stopped");
socket.close();
}
In my code i use commands that make the size of sent data smaller so client and server can communicate using only one byte like for e.g. client sends:
1 - disconnect me
2 - connect me
3 - send map length (chunks quantity)
4 - send map name to me
but then server must respond: 4_mapname and 1 byte is not enough
You need to reset the length of the DatagramPacket before receiving.
And I'm not crazy about this:
confirmation = new DatagramPacket(buf, buf.length, adress, port);
packet = new DatagramPacket(buf, buf.length, adress, port);
Two DatagramPackets sharing the same data buffer. You'll need to be very careful how you use them. It would probably better to only have one, then you know you have to be careful. In fact when sending confirmations or replies of any kind it's better to re-use the packet containing the request you're replying to. That way the target address and port are already set, and all you have to do is set up the data, offset, and length.
I just tried to send a message by UDP from an Erlang server to a Java client. Now I am wondering how I should do to interpret this message to something useful.
Here is what I wrote in Erlang:
{ok, Socket} = gen_udp:open(8789, [binary, {active, true}]).
gen_udp:send(Socket, {127,0,0,1},11001, "yeah!").
And here is my Java code:
public class Server {
private DatagramSocket socket;
private byte[] buffer;
public Server() {
try {
socket = new DatagramSocket(11001);
} catch (SocketException e) {
e.printStackTrace();
}
buffer = new byte[65508];
}
public void receivePackage() {
try {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
byte[] buffer = packet.getData();
System.out.println(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
How do I handle the byte buffer and translate it to something that I can output in the Java console?
on the Erlang side try to send
binary instead of string :
gen_udp:send(Socket, {127,0,0,1},11001, <<"yeah!">>).
On java side:
byte[] b1 = new byte[] {#your byte array};
String s2 = new String(b1);
This will parse binary data to string.
I'm trying to create a simple multicast communication between my PC (Ubuntu, client) and my phone (Android, server).
Unicast/TCP connections work without any problem, the defined port (37659) opens both on PC and phone. When trying to use a MulticastSocket, no ports get opened. nmap tells me the specified port (36963) is a TCP port and that it is closed. (While the receive-method is being executed).
Am I doing something wrong? Or is the firewall blocking the multicast sockets? (I've tried about 20 different ports and none worked..., currently using port 36963)
EDIT: Also with the firewall completely down, nmap tells me the port is closed...
The server's code (phone):
private void multicastLoop() {
String res = Build.FINGERPRINT + "\n";
final InetAddress group;
final MulticastSocket socket;
final DatagramPacket response;
try {
group = InetAddress.getByName("224.0.0.115");
socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(10000);
socket.joinGroup(group);
response = new DatagramPacket(res.getBytes(), res.length(), group, mport);
} catch (IOException e) {
e.printStackTrace();
return;
}
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(isRunning) {
try {
byte[] data = new byte[1024];
DatagramPacket dm = new DatagramPacket(data, data.length);
socket.receive(dm);
Log.d("udp", "received");
if (Arrays.equals(dm.getData(), "someone there".getBytes())) {
socket.send(response);
}
} catch (SocketTimeoutException e) {
continue;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
socket.leaveGroup(group);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
The client's code (computer):
public String[] findServers() {
String hello = "someone there";
try {
InetAddress group = InetAddress.getByName(mhost);
MulticastSocket socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(60000);
socket.joinGroup(group);
DatagramPacket p = new DatagramPacket(hello.getBytes(), hello.length(), group, mport);
byte[] buffer = new byte[1024];
socket.send(p);
DatagramPacket r = new DatagramPacket(buffer, buffer.length);
socket.receive(r);
socket.leaveGroup(group);
socket.close();
String srinfo = "";
byte[] data = r.getData();
for (byte b: data)
srinfo += (char) b;
System.out.println("Server found at " + r.getAddress().getHostName() + ": " + srinfo);
} catch (SocketTimeoutException e) {
return new String[] {"timeout"};
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Make sure mhost is set to "224.0.0.115" not some machine name.
Make sure multicast is enabled on your router.
If the host is multi-homed, you need to join the multicast group via all local interfaces, not just the default one, which is what you're doing at present.
You could send the response back to the source address it came from, which is in the received datagram packet. That would also mean that the client doesn't need a MulticastSocket, only a DatagramSocket.