I've got a strange problem while practising with UDP in Java. If I send multiple UDP handshake packets of different data lengths between servers, the UDP packets merge. I'm using a timer to send the handshakes between the servers.
public class UDPtest {
public static UDPtest test = new UDPtest();
public static byte[] buffer = new byte[1024];
public static InetAddress host = null;
Timer timer = new Timer();
TimerTask ttimer = new TimerTask() {
public void run() {
//System.out.println("time");
}
};
public static void main(String args[]) throws Exception {
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receiveSocket = new DatagramSocket(Integer.parseInt(args[1]));
String s = "SEND "+args[0];
host = InetAddress.getByName("localhost");
buffer = s.getBytes();
DatagramPacket handshake = new DatagramPacket(buffer, buffer.length, host, Integer.parseInt(args[2]));
test.RouteTimer(receiveSocket,handshake);
while (true) {
DatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);
receiveSocket.receive(receivePacket);
String receiveString = new String(receivePacket.getData());
if (receiveString.substring(0,1).matches("A")) {
System.out.println(receiveString);
continue;
}
else {
System.out.println(receiveString);
String temp = "A "+args[0];
buffer = temp.getBytes();
DatagramPacket sendPacket = new DatagramPacket(buffer, buffer.length, host, Integer.parseInt(args[2]));
sendSocket.send(sendPacket);
}
}
}
public void RouteTimer(final DatagramSocket socket, final DatagramPacket handshake) {
Timer timer = new Timer();
TimerTask ttimer = new TimerTask() {
#Override
public void run() {
try {
socket.send(handshake);
}
catch (Exception e) {
}
}
};
timer.scheduleAtFixedRate(ttimer, 1000, 5000);
}
}
For example: If I have server X and Y, the expected output for server X would be:
SEND X
A X
SEND X
A X
but the output becomes:
SEND Y
A Y
SEN
A Y
I'm trying to understand why this happens, and how to fix the problem.
Any help would be appreciated.
If I send multiple UDP handshake packets of different data lengths between servers, the UDP packets merge.
No they don't.
String receiveString = new String(receivePacket.getData());
Your problem is here. You are ignoring the length of the packet. It should be:
String receiveString = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
Related
What i'm trying to do is group 2 clients and make them communicate with eachother. So if 2 clients are connected they would only be able to communicate with eachother and if a third client got connected it would not be able to communicate with the 2 other clients but it would create another group of 2 clients and so on... Right now if a client sends a message it send it over to all clients but i don't know how to make it work like described above. Messages are send from client by typing something in console.
server:
public class Server extends Thread{
public final static int PORT = 7331;
private final static int BUFFER = 1024;
private DatagramSocket socket;
private ArrayList<InetAddress> clientAddresses;
private ArrayList<Integer> clientPorts;
private HashSet<String> existingClients;
public Server() throws IOException {
socket = new DatagramSocket(PORT);
System.out.println("[SERVER] UDP server successfully launched on port " + PORT);
clientAddresses = new ArrayList<InetAddress>();
clientPorts = new ArrayList<Integer>();
existingClients = new HashSet<String>();
}
public void run() {
byte[] buf = new byte[BUFFER];
while (true) {
try {
//resets buffer so only new messages get displayed
Arrays.fill(buf, (byte) 0);
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String content = new String(buf, buf.length);
InetAddress clientAddress = packet.getAddress();
int clientPort = packet.getPort();
String id = clientAddress.toString() + "," + clientPort;
if (!existingClients.contains(id)) {
existingClients.add(id);
clientPorts.add(clientPort);
clientAddresses.add(clientAddress);
}
System.out.println(id + " : " + content);
byte[] data = (id + " : " + content).getBytes();
for (int i = 0; i < clientAddresses.size(); i++) {
InetAddress cl = clientAddresses.get(i);
int cp = clientPorts.get(i);
packet = new DatagramPacket(data, data.length, cl, cp);
socket.send(packet);
}
} catch (Exception e) {
System.err.println(e);
}
}
}
public static void main(String args[]) throws Exception {
Server s = new Server();
s.start();
}
}
clients:
public class Client implements Runnable {
public static void main(String args[]) throws Exception {
String host = "127.0.0.1";
DatagramSocket socket = new DatagramSocket();
//handles the receiving part for every client (incoming packets to clients)
MessageReceiver r = new MessageReceiver(socket);
Client s = new Client(socket, host);
Thread rt = new Thread(r);
Thread st = new Thread(s);
rt.start();
st.start();
}
public final static int PORT = 7331;
private DatagramSocket sock;
private String hostname;
Client(DatagramSocket s, String h) {
sock = s;
hostname = h;
}
//sending clients socket to server
private void sendMessage(String s) throws Exception {
//getting bytes from message
byte buf[] = s.getBytes();
//getting hostname from server
InetAddress address = InetAddress.getByName(hostname);
//setting up packet
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, PORT);
//sending packet to server
sock.send(packet);
}
public void run() {
//connected boolean is used to send a greetings message once for every new client that has joined
boolean connected = false;
do {
try {
sendMessage("GREETINGS");
connected = true;
} catch (Exception e) {
}
} while (!connected);
//reads from the console
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
while (!in.ready()) {
Thread.sleep(100);
}
//sends message from console to server
sendMessage(in.readLine());
} catch (Exception e) {
System.err.println(e);
}
}
}
}
//this class handles receiving part of clients
class MessageReceiver implements Runnable {
DatagramSocket sock;
byte buf[];
MessageReceiver(DatagramSocket s) {
sock = s;
buf = new byte[1024];
}
public void run() {
while (true) {
try {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
sock.receive(packet);
String received = new String(packet.getData(), 0,
packet.getLength());
System.out.println(received);
} catch (Exception e) {
System.err.println(e);
}
}
}
}
What youre trying is a message broadcast or a message-repeater-client.
broadcasting is implemented on network layer (using brodcast the local network broadcast adress).
And if you implementing it that way, you'll flood your network, when you have more than 2 clients. Best regards to your network admin. ;-)
I am making a peer to peer chat application for which I have written the below code for chat with one person. This code works for localhost(127.0.0.1) but doesn't work for any specific ip address(192.168.43.118) and throws bindexception. Please help.
import java.sql.*;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class communicate {
public static void main(String args[]) throws Exception {
communicate ob = new communicate();
String ip = "192.168.43.118";
ob.text(ip);
}
public void text(String friend_ip) throws Exception{
System.out.println("Press 'Exit' to exit the chat");
int send_port = 40002;
int receive_port = 40002;
//InetAddress inetaddr = InetAddress.getByName(friend_ip);
byte[] ipAddr = new byte[] { (byte)192, (byte)168, (byte)43, (byte)118 };
System.out.println(ipAddr.length);
InetAddress inetaddr = InetAddress.getByAddress(ipAddr);
System.out.println("B");
DatagramSocket serverSocket = new DatagramSocket(receive_port, inetaddr);
System.out.println("YO");
Runnable send = new SendMsg(send_port, friend_ip, serverSocket);
Runnable receive = new GetMsg(friend_ip, receive_port, serverSocket);
Thread t1 = new Thread(send);
Thread t2 = new Thread(receive);
t1.start();
t2.start();
}
class SendMsg implements Runnable {
private DatagramSocket senderSocket;
private int send_port;
private String sendto_ip;
SendMsg(int port, String friend_ip, DatagramSocket ds)throws Exception {
senderSocket = new DatagramSocket(64432);
send_port = port;
sendto_ip = friend_ip;
}
public void run(){
try {
while(true) {
String sendString;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
sendString = br.readLine();
byte[] sendData = sendString.getBytes();
byte[] ipAddr = new byte[] { (byte)192, (byte)168, (byte)43, (byte)118 };
InetAddress inetAddress = InetAddress.getByAddress(ipAddr);
DatagramPacket sendPacket = new DatagramPacket (sendData, sendData.length, inetAddress, send_port);
senderSocket.send(sendPacket);
System.out.println("Message Sent");
}
}
catch(Exception e) {
System.out.println("Exc at Sender\n" + e);
}
finally {
if(senderSocket != null) senderSocket.close();
}
}
}
class GetMsg implements Runnable{
private DatagramSocket serverSocket;
private String friend_ip;
private int receive_port;
GetMsg(String ip, int port, DatagramSocket ds) throws Exception{
friend_ip = ip;
receive_port = port;
serverSocket = ds;
}
public void run(){
try {
while(true) {
byte[] receiveData = new byte[10000];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String message = new String (receivePacket.getData(), 0, receivePacket.getLength());
System.out.println(friend_ip + ": " + message);
}
}
catch(Exception e) {
System.out.println("Exc at Rec\n" + e);
}
finally {
if(serverSocket != null) serverSocket.close();
}
}
}
}
When I run it on terminal the following output is shown
Press 'Exit' to exit the chat
4
B
Exception in thread "main" java.net.BindException: Cannot assign requested address (Bind failed)
at java.base/java.net.PlainDatagramSocketImpl.bind0(Native Method)
at java.base/java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:131)
at java.base/java.net.DatagramSocket.bind(DatagramSocket.java:394)
at java.base/java.net.DatagramSocket.<init>(DatagramSocket.java:244)
at java.base/java.net.DatagramSocket.<init>(DatagramSocket.java:301)
at communicate.text(communicate.java:21)
at communicate.main(communicate.java:10)
As "YO" is not printed it seems that error is in the text method where I am trying to create DatagramSocket. Where am I going wrong?
If you want read, do not bind the remote address. Just create a local UDP socket (it will be a server socket) and just read from/write to its buffer. You can bind to your local network interface only and these must be initialized before. So you cannot bind to an unused Wifi, or unplugged ethernet adapter.
If you want test a sender, and a receiver in the same java program on different threads, you have to use two different socket.
A hint: use InetAddress.getByName(IPv4) for string IP input, you do not need the byte array.
I have an UDP send and receive which works in my device Samsung Galaxy Ace Plus (S7500) but the same code doesn't work in other devices, for example Samsung Galaxy S4. I don't have any error.
Send :
public class SendThread extends Thread {
byte[] receiveData = new byte[1024];
DatagramSocket serverSocket = null;
public SendThread() {
this.start();
}
public void run() {
DatagramSocket serverSocket = null;
byte[] receiveData = new byte[1024];
byte[] sendData = new byte[1024];
try {
serverSocket = new DatagramSocket("MY SOCKET PORT");
InetAddress IP = InetAddress.getByName("MY IP");
String send= "I am Android";
sendData = send.getBytes();
DatagramPacket send = new DatagramPacket(sendData, sendData.length, IP, "MY SEND PORT");
serverSocket.send(send);
serverSocket.close();
} catch (Exception e) {
}
}
}
Receive :
public class ReceiveThread extends Thread {
byte[] receiveData = new byte[1024];
DatagramSocket serverSocket = null;
boolean isActive = true;
public ReceiveThread() {
this.start();
}
public void run() {
DatagramSocket serverSocket = null;
byte[] receiveData = new byte[1024];
while (isActive) {
try {
serverSocket = new DatagramSocket("MY RECEIVE PORT");
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
String sentence = new String( receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
serverSocket.close();
} catch (Exception e){
}
}
}
}
This problem ocurred because some devices lock the Datagram receiver because the protocol security implemented by factory.
Your code is not wrong, but you need change the DatagramSocket for MulticastSocket.
For this your need execute some steps:
First, it's needed to add the uses-permission:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
On AmdroidManifest.xml
Second, it's necessary create a MulticastLock; Without this the MulticastSocket is not work properly;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
Thirdy, replace the DatagramSocket by MulticastSocket. Only on receive methods was needed put the code below or similar:
MulticastSocket ms = new MulticastScoket("Your socket port");
ms.joinGroup("Your IP");
It's not needed any modifies to send messages.
I use the multcast ip equals to 239.255.255.255. Attempt to range of multicast ip because the wrong ip will block the method flow correctly.
Finally, before use MulticastSocket it's needed to execute MulticastLock.acquire(), and after use execute MulticastLock.release();
It could be puted on service, and acquire or release MulticastLock on start or stop service.
Is it possible to use a single DatagramSocket to send and receive packets in a single Java application? I have been attempting to do this using threads but have had not luck. Every socket tutorial I find online uses separate client and server classes to send data. However, in my case, I want the client and server to reside in a single application. Below is my attempt:
public class Main implements Runnable {
// global variables
static DatagramSocket sock;
String globalAddress = "148.61.112.104";
int portNumber = 9876;
byte[] receiveData = new byte[1024];
public static void main(String[] args) throws IOException {
sock = new DatagramSocket();
(new Thread(new Main())).start();
// send data
while (true) {
InetAddress IPAddress = InetAddress.getByName("127.0.0.1");
int port = 9876;
int length = 1024;
byte [] sendData = new byte[1024];
String message = "hello";
sendData = message.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
IPAddress, port);
sock.send(sendPacket);
}
}
public void run() {
//get incoming data
while (true) {
byte[] sendData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
receivePacket.setPort(portNumber);
try {
sock.receive(receivePacket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String sentence = new String(receivePacket.getData());
System.out.println("RECEIVED: " + sentence);
}
}
}
As you can see I am sending data in a loop on the main thread and receiving data on the loop in the runnable thread. The main thread should continuously send "hello" to the receiver and output the message. However, no output is given?
Am I on the right track here? Is using threads the best way to do this? Is this even possible? And if so is there a better solution?
I made connection between server and client properly and i send message from client to the server,but how can i send messages from server to client.I mean how can i make server act like a client too.i tried to copy the client methods to the another class that server can invoke.but i couldnt then i tried to create a new package to use the client code in server class.any advices?
ps:Sorry about my english.
public class Entrance_Server extends JFrame{
JButton buton = new JButton("Create");
JButton buton2 = new JButton("Join");
JPanel butonpanel = new JPanel();
DatagramSocket sockServer = null;
DatagramSocket sockClient = null;
int port = 7777;
String s;
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
public Entrance_Server() {
setLayout(new GridLayout(2,1));
add(buton);
add(buton2);
buton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Choosing c = new Choosing();
c.start();
System.out.println("Server socket created. Waiting for incoming data...");
}
});
buton2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Choosing c = new Choosing();
c.start();
}
});
}
public static void main(String[] args){
Entrance_Server e = new Entrance_Server();
e.setSize(500,350);
e.setTitle("Welcome");
e.setLocationRelativeTo(null);
e.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
e.setVisible(true);
e.connect();
}
public void connect (){
try{
sockServer = new DatagramSocket(7777);
byte[] buffer = new byte[65536];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
while(true)
{
sockServer.receive(incoming);
byte[] data = incoming.getData();
String s = new String(data, 0, incoming.getLength());
//echo the details of incoming data - client ip : client port - client message
System.out.println(incoming.getAddress().getHostAddress() + " : " + incoming.getPort() + " - " + s);
s = "OK : " + s;
DatagramPacket dp = new DatagramPacket(s.getBytes() , s.getBytes().length , incoming.getAddress() , incoming.getPort());
sockServer.send(dp);
Entrance_Client_in_Server ec = new Entrance_Client_in_Server();
ec.connectc();
}
}catch(IOException i){
System.err.println("IOException " + i);
}
}
}
On your client u need to wait on the server response by using socket.Receive()
You can identify a client after he has send a packet to the server like you are doing. You can then indentify the client like this:
InetAddress address = packet.getAddress();
int port = packet.getPort();
And use it to send a packet back to the client, which will read the response using the socket.Receive();
For further information about Client/Server connection using UDP DatagramSockets check
Client-Server Datagram sockets