Im trying to write server and client for service which would tell the current time. My code:
SERVER
public class TimeServer {
public static void main(String[] args) {
try {
final DatagramSocket so = new DatagramSocket(8189);
new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
try {
InetAddress group = InetAddress.getByName("200.20.2.0");
byte[] buf = new byte[256];
Calendar cal = Calendar.getInstance();
buf = cal.toString().getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length,
group, 8189);
so.send(packet);
} catch (IOException ex) {
ex.printStackTrace();
}
Thread.sleep((int)(Math.random() * 5));
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}).start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
CLIENT
public class TimeClient {
public static void main(String[] args) {
try {
MulticastSocket so = new MulticastSocket(8190);
InetAddress group = InetAddress.getByName("200.20.2.0");
so.joinGroup(group);
//5 razy czekamy na otrzymanie od serwera wiadomosci
for (int a=0; a<5; a++) {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
so.receive(packet);
String recv = new String(packet.getData());
System.out.println("RECEIVED: " + recv);
}
so.leaveGroup(group);
so.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
When launching server and then client I get the following error:
java.net.BindException: Address already in use
at java.net.PlainDatagramSocketImpl.bind0(Native Method)
at java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:95)
at java.net.DatagramSocket.bind(DatagramSocket.java:376)
at java.net.MulticastSocket.<init>(MulticastSocket.java:172)
at java.net.MulticastSocket.<init>(MulticastSocket.java:137)
at timeclient.TimeClient.main(TimeClient.java:13)
Please help, thanks
EDIT:
I changed client port and now I get exception:
java.net.SocketException: Not a multicast address
at java.net.MulticastSocket.joinGroup(MulticastSocket.java:306)
at timeclient.TimeClient.main(TimeClient.java:15)
What's now?
Every Port can only be used by a single application. In your case, your server and your client (2 applications) are trying to use the same port which is causing the exception.
To fix it, change for example the port for the client from 8189 to 8190
You must change the client port (or the server port) because every port only can be used by a single process.
try DatagramSocket.setReuseAddress(true) and see what happens.
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.
Learning java MulticastSocket, the same LAN only the machine can receive the broadcast, the other equipment can not. why? Is the router setting problem or the broadcast address setting problem?
send.java
public class sentServer {
public static void main(String[] args) {
String host = "224.0.0.1";
int port = 9998;String message = "test-multicastSocket";
try {
InetAddress group = InetAddress.getByName(host);
MulticastSocket s = new MulticastSocket();
s.joinGroup(group);
DatagramPacket dp = new DatagramPacket(message.getBytes(),message.length(),group,port);
s.send(dp);
s.close();
} catch (UnknownHostException e)
{
e.printStackTrace();
} catch (IOException e)
{e.printStackTrace();
}
}
}
The listening address set here is 224.0.0.1
recevier.java
public class reClinet {
public static void main(String[] args) {
String host="224.0.0.1";
int port=9998;
int length=1024;
byte[] buf=new byte[length];
MulticastSocket ms=null;
DatagramPacket dp=null;
StringBuffer sbuf=new StringBuffer();
try {
ms=new MulticastSocket(port);
dp=new DatagramPacket(buf,length);
InetAddress group=InetAddress.getByName(host);
ms.joinGroup(group);
System.out.println("port is open");
ms.receive(dp);
ms.close();
int i;
for(i=0;i<1024;i++){
if(buf[i]==0){
break;
}
sbuf.append((char)buf[i]);
}
System.out.println("message"+sbuf.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
`
Thanks
In case you are asking: why can only systems attached to the same network segment see broadcasts?
That is the nature of broadcasts in Java: a client connects to a specific server; and joins the broadcast group; then that client will be notified.
If a client doesn't get those notifications; you have to look into your network settings, firewalls, ...
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.
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.
Is multi-threading possible in a simple java server using udp connectionless protocol? give an example!!
Multi-threading is actually simpler with UDP because you don't have to worry about connection state. Here is the listen loop from my server,
while(true){
try{
byte[] buf = new byte[2048];
DatagramPacket packet = new DatagramPacket( buf, buf.length, address );
socket.receive( packet );
threadPool.execute( new Request( this, socket, packet ));
.......
The threadPool is a ThreaPoolExecutor. Due to the short-lived nature of UDP sessions, thread pool is required to avoid the overhead of repeatedly thread creation.
Yes, it's possible through the use of the DatagramChannel class in java.nio. Here's a tutorial (It does not address the multithreading, but that is a separate issue anyway).
Here is one example try putting your own ip to get the hard-coded message back
package a.first;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Serv {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Listner listner = new Listner();
Thread thread = new Thread(listner);
thread.start();
String messageStr = "Hello msg1";
int server_port = 2425;
DatagramSocket s = new DatagramSocket();
InetAddress local = InetAddress.getByName("172.20.88.223");
int msg_length = messageStr.length();
byte[] message = messageStr.getBytes();
DatagramPacket p = new DatagramPacket(message, msg_length, local,
server_port);
System.out.println("about to send msg1");
s.send(p);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
messageStr = "Hello msg2";
msg_length = messageStr.length();
message = messageStr.getBytes();
p = new DatagramPacket(message, msg_length, local,
server_port);
System.out.println("about to send msg2");
s.send(p);
}
}
class Listner implements Runnable
{
#Override
public void run() {
String text = null;
while(true){
text = null;
int server_port = 2425;
byte[] message = new byte[1500];
DatagramPacket p = new DatagramPacket(message, message.length);
DatagramSocket s = null;
try{
s = new DatagramSocket(server_port);
}catch (SocketException e) {
e.printStackTrace();
System.out.println("Socket excep");
}
try {
s.receive(p);
}catch (IOException e) {
e.printStackTrace();
System.out.println("IO EXcept");
}
text = new String(message, 0, p.getLength());
System.out.println("message = "+text);
s.close();
}
}
}