I am trying to understand how multicast works, thus I am experimenting with it a bit.
Situation
I built a simple server which has a MulticastSocket, listening on port 1250. It simply echoes the message it receives.
Next I built a simple client, also with a MulticastSocket, listening on port 4711. It sends a String-Message to the server and waits for any message that comes back.
Expected behaviour
I want two or more clients send their own unique message to the server and receive all responses the server sends back to the multicast group listening on port 4711.
Observed behaviour / Problem
As soon as I start more than one instance of the client, all responses from the server are only received by the first client that joined the group. All other clients that joined the multicast group on port 4711 do not receive anything. Why is this and how can I solve the problem?
The result looks like this (you can see that only the process MulticastEchoClient2 receives the server's response):
Code
Server-Code
public class MulticastEchoServer
{
public static void main(String[] args)
{
if (args.length != 2)
{
System.out.println("Wrong usage of parameters! <MulticastAddress><id>");
return;
}
UDPMulticastSocket socket = null;
String id = args[1];
try
{
socket = new UDPMulticastSocket(1250);
System.out.println("Socket created...");
socket.join(args[0]);
while(true)
{
String msg = socket.receive(1024);
System.out.println("Message received: " + msg + " from " + socket.getSenderAddress() + ":" + socket.getSenderPort());
if (msg.toLowerCase().equals("quit"))
{
System.out.println("Shutting down...");
break;
}
socket.reply("Reply from " + id + " -> " + msg);
}
socket.leave(args[0]);
}
catch(Exception e)
{
e.printStackTrace();
}
if (socket != null)
{
socket.close();
System.out.println("Shutting down...");
}
}
}
Client Code
public class MulticastEchoClient
{
public final static int MESSAGES = 10000;
public static void main(String[] args)
{
if (args.length != 3)
{
System.out.println("Wrong usage of parameters: <Multicast-Address><Address of Server><id>");
return;
}
UDPMulticastSocket socket = null;
String id = args[2];
try
{
socket = new UDPMulticastSocket(4711);
socket.setTimeout(1000);
System.out.println("Socket created...");
socket.join(args[0]);
InetAddress srvrAddress = InetAddress.getByName(args[1]);
for (int i = 0; i < MESSAGES; i++)
{
socket.send(id + " sending: " + i, srvrAddress, 1250);
try
{
while(true)
{
String msg = socket.receive(1024);
System.out.println("Message received: " + msg + " from " + socket.getSenderAddress() + ":" + socket.getSenderPort());
}
}
catch (IOException e)
{
System.out.println("All messages received...");
}
}
socket.leave(args[0]);
}
catch(Exception e)
{
e.printStackTrace();
}
if (socket != null)
{
socket.close();
System.out.println("Shutting down...");
}
}
}
Utility Classes
public class UDPSocket
{
protected DatagramSocket socket;
private InetAddress senderAddress;
private int senderPort;
//constructors
protected UDPSocket(DatagramSocket socket)
{
this.socket = socket;
}
public UDPSocket() throws SocketException
{
this(new DatagramSocket());
}
public UDPSocket(int port) throws SocketException
{
this(new DatagramSocket(port));
}
//getters
public InetAddress getSenderAddress()
{
return senderAddress;
}
public int getSenderPort()
{
return senderPort;
}
//setters
public void setTimeout(int timeout) throws SocketException
{
socket.setSoTimeout(timeout);
}
//methods
public void send(String s, InetAddress rcvrAddress, int rcvrPort) throws IOException
{
byte[] data = s.getBytes();
DatagramPacket outPacket = new DatagramPacket(data, 0, data.length, rcvrAddress, rcvrPort);
socket.send(outPacket);
}
public String receive(int maxBytes) throws IOException
{
byte[] data = new byte[maxBytes];
DatagramPacket inPacket = new DatagramPacket(data, 0, data.length);
socket.receive(inPacket);
senderAddress = inPacket.getAddress();
senderPort = inPacket.getPort();
//return new String(data, 0, data.length);
return new String(data, 0, inPacket.getLength());
}
public void reply(String s) throws IOException
{
if (senderAddress != null)
{
send(s, senderAddress, senderPort);
}
else
{
throw new IOException("ERROR: No one to reply to!");
}
}
public void close()
{
socket.close();
}
}
public class UDPMulticastSocket extends UDPSocket
{
public UDPMulticastSocket(int port) throws IOException
{
super(new MulticastSocket(port));
}
public UDPMulticastSocket() throws IOException
{
super(new MulticastSocket());
}
public void join(String mcAddress) throws IOException
{
InetAddress ia = InetAddress.getByName(mcAddress);
((MulticastSocket) socket).joinGroup(ia);
}
public void leave(String mcAddress) throws IOException
{
InetAddress ia = InetAddress.getByName(mcAddress);
((MulticastSocket) socket).leaveGroup(ia);
}
}
You're replying to the sending address, so only the sending address is receiving the reply. If you want to reply to the multicast group, reply to the multicast group, not the sending address.
Related
I want to send/receive messages by the multicast socket.
This is my code
'''
public class MulticastSender {
public static final String GROUP_ADDRESS = "230.0.0.1";
public static final int PORT = 7766;
public static void main(String[] args) throws InterruptedException {
DatagramSocket socket = null;
try {
// Get the address that we are going to connect to.
InetAddress address = InetAddress.getByName(GROUP_ADDRESS);
System.out.println("GROUP_ADDRESS: " + address);
// Create a new Multicast socket
socket = new DatagramSocket();
DatagramPacket outPacket = null;
long counter = 0;
while (true) {
String msg = "Sent message No. " + counter;
counter++;
outPacket = new DatagramPacket(msg.getBytes(), msg.getBytes().length, address, PORT);
socket.send(outPacket);
System.out.println("Server sent packet with msg: " + msg);
Thread.sleep(1000); // Sleep 1 second before sending the next message
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
'''
'''
public class MulticastReceiver {
public static final byte[] BUFFER = new byte[4096];
public static void main(String[] args) {
MulticastSocket socket = null;
DatagramPacket inPacket = null;
try {
// Get the address that we are going to connect to.
SocketAddress address = new InetSocketAddress(MulticastSender.GROUP_ADDRESS, MulticastSender.PORT);
// Create a new Multicast socket
socket = new MulticastSocket(address);
socket.joinGroup(address, NetworkInterface.getByName("eth0"));
while (true) {
// Receive the information and print it.
inPacket = new DatagramPacket(BUFFER, BUFFER.length);
socket.receive(inPacket);
// System.out.println(socket.getInterface());
String msg = new String(BUFFER, 0, inPacket.getLength());
System.out.println("From " + inPacket.getAddress() + " Msg : " + msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
'''
It is working on my local host. however, I want to send messages from my AWS server instance (with public ipv4) and receive them in the local client. How to do it?
if yes, please give me an example!
Tks all
Basically I'm writing a 2 way communication client server program. The client sends requests to the server and server responds accordingly. The requests have to do with adding or removing tokens from a list of tokens stored on the server. The client side seems to work fine, the requests are being sent to the server. However it seems that the server is not receiving any request from the client and I have no idea why. I've attached the code:
client
package;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TokenClient {
private static final int PORT_NUMBER = 9999;
private Socket socket;
private InputStream inStream;
private OutputStream outStream;
private Scanner inStreamScanner;
private PrintWriter outStreamPrinter;
public static void main(String[] args) {
new TokenClient().go();
}
void go() {
try {
System.out.println(
"Enter commands of the form \"CONNECT IP-address\", \"SUBMIT token\", \"REMOVE token\" or \"QUIT\"\n");
Scanner consoleScanner = new Scanner(System.in);
// java.io.BufferedReader consoleInputReader = new
// BufferedReader(new InputStreamReader(System.in));
String command = "";
while (!command.equals("QUIT") && consoleScanner.hasNextLine()) {
command = consoleScanner.nextLine(); // consoleInputReader.readLine();
processCommand(command);
}
System.out.println("Goodbye!");
consoleScanner.close();
} catch (IOException e) {
System.out.println("An exception occurred: " + e);
e.printStackTrace();
}
}
void processCommand(String userCommand) throws IOException {
if (userCommand.startsWith("SUBMIT"))
sendMessageToServer(userCommand);
else if (userCommand.startsWith("REMOVE"))
sendMessageToServer(userCommand);
else if (userCommand.equals("QUIT"))
closeConnectionToServer();
else if (userCommand.startsWith("CONNECT")) {
closeConnectionToServer();
connectToServer(userCommand);
} else
System.out.println("Invalid user command: " + userCommand);
}
void closeConnectionToServer() {
if (socket != null && !socket.isClosed()) {
try {
System.out.println("Disconnecting from server...");
sendMessageToServer("QUIT");
socket.close();
System.out.println("Connection to server closed.");
} catch (IOException e) {
System.out.println("An exception occurred: " + e);
e.printStackTrace();
}
}
}
void connectToServer(String connectCommand) throws IOException {
String ipAddress = connectCommand.substring(8).trim();
System.out.println("Connecting to server at " + ipAddress + ", port " + PORT_NUMBER + "...");
socket = new Socket(ipAddress, PORT_NUMBER);
inStream = socket.getInputStream();
outStream = socket.getOutputStream();
inStreamScanner = new Scanner(inStream);
outStreamPrinter = new PrintWriter(outStream);
System.out.println("Connected to server.");
}
void sendMessageToServer(String command) {
System.out.println("Sending message to server: " + command + "...");
if (socket == null || socket.isClosed())
System.out.println("Not possible - not connected to a server");
else {
outStreamPrinter.println(command); // send the message to the server
// NB: client doesn't check if tokens are valid
outStreamPrinter.flush(); // do so immediately
// Receive response from server:
if (!command.equals("QUIT") && inStreamScanner.hasNextLine()) {
String response = inStreamScanner.nextLine();
System.out.println("Response from server: " + response);
}
}
}
}
server
package;
import java.net.*;
import java.util.ArrayList;
import java.util.Scanner;
import java.io.*;
public class server {
private static Socket s;
private static Scanner inStreamScanner;
private static int PORT_NUMBER = 9999;
private static InputStream inStream;
private static OutputStream outStream;
private static PrintWriter outStreamPrinter;
private static ArrayList<String> ts = new ArrayList<String>();
public static void main(String[] args) throws IOException{
ServerSocket ss = new ServerSocket(PORT_NUMBER);
server serverInstance = new server();
server.s = ss.accept();
System.out.println("Client connected");
inStream = s.getInputStream();
outStream = s.getOutputStream();
inStreamScanner = new Scanner(inStream);
outStreamPrinter = new PrintWriter(outStream);
serverInstance.run();
}
public void run() {
try {
try {
doService();
} finally {
s.close();
}
} catch (IOException e) {
System.err.println(e);
}
}
public void doService() throws IOException{
while(true) {
if(inStreamScanner.hasNext())
return;
else {
outStreamPrinter.println("NO REQUEST");
outStreamPrinter.flush();
String request = inStreamScanner.next();
outStreamPrinter.println("Request received: " +request);
outStreamPrinter.flush();
handleServerRequest(request);
}
}
}
public void handleServerRequest(String request) throws IOException{
if(request.startsWith("SUBMIT")) {
String token = extractNum(request);
addtoTS(token);
} else if(request.startsWith("REMOVE")) {
String token = extractNum(request);
removefromTS(token);
} else if(request.startsWith("QUIT")) {
s.close();
} else {
outStreamPrinter.println("UNKNOWN REQUEST");
outStreamPrinter.flush();
}
}
public String extractNum(String request) {
String str = request;
String numberOnly = str.replaceAll("[^0-9]", " ");
return numberOnly;
}
public void addtoTS(String token) {
if(ts.contains(token)) {
outStreamPrinter.println("OK");
outStreamPrinter.flush();
}else {
ts.add(token);
outStreamPrinter.println("OK");
outStreamPrinter.flush();
}
}
public void removefromTS(String token) {
if(ts.contains(token)) {
ts.remove(token);
outStreamPrinter.println("OK");
outStreamPrinter.flush();
}else {
outStreamPrinter.println("ERROR: TOKEN NOT FOUND");
outStreamPrinter.flush();
}
}
}
I haven't run the code, but there seems to be an issue in your doService() method on the server side. You have an infinite loop, but the entire method returns (and thus the program also quits) as soon as the input stream recieves a new line character (when the client sends a request). So, it seems your program would quit when it receives the first command from the client. I'd also recommend closing more gently (ie check in the loop for end rather than closing the socket directly).
So, I'd define a private class variable boolean listening; or something like that. Then in the main() method, set it to true after the socket has been initialized (when the client has connected).
Change your doService() to something similar to the following:
public void doService() throws IOException
{
while(listening)
{
if(inputStreamReader.hasNext())
{
String request = inStreamScanner.next();
outStreamPrinter.println("Request received: " +request);
outStreamPrinter.flush();
handleServerRequest(request);
}
}
}
And change how you handle the QUIT command:
from
else if(request.startsWith("QUIT"))
{
s.close();
}
to
else if(request.startsWith("QUIT"))
{
listening = false;
}
The socket will be closed by the finally in run().
I have a UDP process that required to define the receiving port and IP address.
Upon testing I figured out that having the same reception IP and port at the same time of requests might result to data loss/switching.
I came up with the idea that If there's an existing request with same data, the incoming/2nd request will wait for the first one to finish the transaction and then do the request.
Since this is a servlet and I'm worrying for multiple requests in different browser at the same time, I used Semaphore in a singleton pattern to return single instance. My DatagramSocket is in singleton pattern as well to avoid "already bind" error.
My code is doing well with no data switching in a happy path scenario where in it will just send a request and response with no error.
I set a socket timeout and execute a timeout exception scenario,here's what I got
First request =====> UDP server
Timeout exception <==== UDP server
Second Request=====> UDP server
First response <==== UDP server
I'm receiving the first response on my 2nd request and so on.
How will I reject/skip the response of the timeout request? Please note that I am not allowed to add an identifier on my response as per requirement.
Here's my code for your reference :
private void calludp(String ip, String targetIp, String port, String targetPort, String timeout, byte[] message)
throws IOException, SAXException, ParserConfigurationException, InterruptedException {
String key = targetIp + ":" + targetPort;
UDPReceptionData udpReceptionData = null;
udpReceptionData = getReceptionLock(key, receptionMap);
Semaphore semaphore = udpReceptionData.getSemaphore();
DatagramSocket datagramSocket = udpReceptionData.getDatagramSocket();
semaphore.acquire();
try {
send(ip, targetIp, port, targetPort, timeout, message, datagramSocket);
} finally {
semaphore.release();
}
}
private void populateUDPReceptionMap(String port, String target) {
if ((target != null && !target.isEmpty()) && (port != null && !port.isEmpty())) {
Semaphore semaphore = new Semaphore(1);
DatagramSocket datagramSocket = getSocketMap(port);
UDPReceptionData udpReceptionData = new UDPReceptionData(datagramSocket, semaphore);
this.receptionMap.put(target + ":" + port, udpReceptionData);
}
}
private DatagramSocket getSocketMap(String port) {
System.out.println(socketMap.toString());
DatagramSocket datagramSocket = null;
if (port != null && !port.isEmpty()) {
if (!socketMap.containsKey(port)) {
try {
datagramSocket = new DatagramSocket(Integer.parseInt(port));
this.socketMap.put(port, datagramSocket);
} catch (NumberFormatException | SocketException e) {
e.printStackTrace();
}
} else {
datagramSocket = socketMap.get(port);
}
}
return datagramSocket;
}
public UDPReceptionData getReceptionLock(String ipPort, Map<String, UDPReceptionData> receptionMap) {
System.out.println(receptionMap.toString());
return receptionMap.get(ipPort);
}
public byte[] send(String target, String receptionTarget, String port, String receptionPort, String timeout,
byte[] message, DatagramSocket clientSocket) throws IOException {
String messageResponse = ""; // Message response to be return to the
// caller
int intTimeout = Integer.parseInt(timeout);
DatagramPacket receivePacket = null;
try {
InetAddress ipAddress = InetAddress.getByName(target);
int intPort = Integer.parseInt(port);
byte[] receiveData = new byte[1024];
DatagramPacket sendPacket = new DatagramPacket(message, message.length, ipAddress, intPort);
clientSocket.send(sendPacket);
// receive the data
receivePacket = new DatagramPacket(receiveData, receiveData.length);
try {
clientSocket.setSoTimeout(intTimeout);
clientSocket.receive(receivePacket);
} catch (SocketTimeoutException e) {
throw new SocketTimeoutException("Socket Timeout Exception");
}
messageResponse = new String(receivePacket.getData());
String mes = new String(message, "UTF-8");
System.out.println("FROM SERVER:" + messageResponse + " :::: " + mes);
} finally {
// commented out the close since this is a single instance DatagramSocket
// clientSocket.close();
}
return receivePacket.getData();
}
UDPReceptionData.java
import java.net.DatagramSocket;
import java.util.concurrent.Semaphore;
public class UDPReceptionData {
private Semaphore semaphore;
private DatagramSocket datagramSocket;
public UDPReceptionData(DatagramSocket datagramSocket, Semaphore semaphore) {
this.datagramSocket = datagramSocket;
this.semaphore = semaphore;
}
public DatagramSocket getDatagramSocket() {
return this.datagramSocket;
}
public Semaphore getSemaphore() {
return this.semaphore;
}
}
UDPServer.java
private void udpSender(DatagramSocket serverSocket) throws IOException, InterruptedException {
while (true) {
byte[] responseMessage = new byte[1024];
byte[] requestMessage = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(responseMessage, responseMessage.length);
serverSocket.receive(receivePacket);
String receivedMessage = new String(receivePacket.getData());
System.out.println("RECEIVED: " + receivedMessage);
InetAddress IPAddress = receivePacket.getAddress();
int port = receivePacket.getPort();
requestMessage = receivedMessage.getBytes();
// Set the sending packet to designated IP Address and port
DatagramPacket sendPacket = new DatagramPacket(requestMessage, requestMessage.length, IPAddress, port);
//delay for 4 seconds for timeout testing
Thread.sleep(4000);
serverSocket.send(sendPacket);
}
}
main method
public static void main(String[] args) {
UDPProcess m = new UDPProcess();
m.populateUDPReceptionMap("9090", "localhost");
String request = "localhost:9090:message1";
String request2 = "localhost:9090:message2";
new Thread() {
public void run() {
try {
m.calludp("localhost", "localhost", "7979", "9090", "2000", request.getBytes());
} catch (IOException | SAXException | ParserConfigurationException | InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread() {
public void run() {
try {
m.calludp("localhost", "localhost", "7979", "9090", "60000", request2.getBytes());
} catch (IOException | SAXException | ParserConfigurationException | InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
Result :
java.net.SocketTimeoutException: Socket Timeout Exception
at com.comp.proj.connector.UDPProcess.send(UDPProcess.java:221)
at com.comp.proj.connector.UDPProcess.calludp(UDPProcess.java:135)
at com.comp.proj.connector.UDPProcess.access$0(UDPProcess.java:118)
at com.comp.proj.connector.UDPProcess$1.run(UDPProcess.java:51)
FROM SERVER:localhost:9090:message2 :::: localhost:9090:message1
You need sequence numbers in your requests and responses. You need to ignore responses from a prior sequence number. That can happen even without a timeout, as UDP datagrams can be duplicated (or more).
A client connects to the Server, the server sends to the client 1 message and the client must wait for another message. While client waiting in while(true) loop it loads the CPU to 50%. I try to do this as simple I can to learn how it works.
P.S. All catch() already hiden to minimize code here.
Client:
public class SocketClient
{
String host;
int port;
static Socket connection;
BufferedReader bfr;
public SocketClient(String host, int port)
{
this.port = port;
this.host = host;
}
public void connect() throws UnknownHostException, IOException, Exception
{
connection = new Socket(new String(host), port);
System.out.println("Client is ready.");
bfr = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
public void readInput() throws IOException
{
String input;
if(input = bfr.readLine()) != null)
{
System.out.println(input);
}
}
public static void main(String[] args) throws UnknownHostException, IOException, Exception
{
SocketClient socketClient = new SocketClient("localhost", 19999);
try {
socketClient.connect();
try
{
while(true)
{
socketClient.readInput();
}
}
}
}
}
Server:
public class MultipleSocketServer implements Runnable {
private Socket connection;
private String TimeStamp;
private int ID;
static PrintWriter writer;
private static File file;
public static void main(String[] args)
throws FileNotFoundException, UnsupportedEncodingException
{
int port = 19999;
int count = 0;
file = new File("E:/test.txt");
writer = new PrintWriter(file, "UTF-8");
try
{
ServerSocket socket = new ServerSocket(port);
System.out.println("MultipleSocketServer Initialized");
while (true)
{
Socket connection = socket.accept();
Runnable runnable = new MultipleSocketServer(connection, ++count);
Thread thread = new Thread(runnable);
thread.start();
}
}
}
MultipleSocketServer(Socket s, int i) {
this.connection = s;
this.ID = i;
}
public void run() {
try {
System.out.println("Connected: " + connection.getLocalSocketAddress() + " at port " + connection.getPort());
writer.println(ID + ": " + connection.getLocalSocketAddress() + " at port " + connection.getPort());
writer.flush();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
writer.write("MultipleSocketServer repsonded at " + new java.util.Date().toString());
writer.write("\n");
writer.flush();
}
finally {
try {
connection.close();
}
}
}
}
Analysis
It seems the server side closes connection after sending the data.
The client side has the following infinite loop:
while (true)
{
socketClient.readInput();
}
The loop can cause the CPU consumption: the method bfr.readLine() method call will return null immediately after the connection is closed.
Solution
Please consider changing the loop of the client side to read until "the end-of-connection":
String input;
while ((input = bfr.readLine()) != null) {
System.out.println(input);
}
I have been working on a message system where users type in a server IP/Port and that server then takes in messages and relays them to all other users on the server. The whole program was based of a echo server i rewrote from scratch, for every server.accept() socket it creates two Threads, one to receive messages and one to send them back. The two Threads are connected by a DatagramPacket system so if the server receives a message from one socket it sends it back to all other users because their Threads are listening for the same thing, this is where i am encountering problems; everything work fine except the fact that the user who receives the message alternates in order to time of log on.
Example of problem when two clients are connected:
Client #1 sends 10 messages:
0
1
2
3
4
5
6
7
8
9
The Server receives all of them.
Client #1 receives:
1
3
5
7
9
Client #2 receives:
0
2
4
6
8
Here is the code for the Client:
import java.io.*;
import java.util.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MessageClient {
public static void main(String[] args) {
System.out.println("Starting Message System...");
Scanner in = new Scanner(System.in);
MessageClient mc = new MessageClient();
String input;
System.out.println(":System Started, type help for help.");
System.out.print(":");
while (true) {
input = in.nextLine();
if (input.equalsIgnoreCase("HELP")) {
mc.printHelp();
System.out.print(":");
} else if (input.equalsIgnoreCase("QUIT")) {
System.exit(0);
} else if (input.equalsIgnoreCase("CONNECT")) {
mc.connect(in);
in.nextLine();
System.out.print(":");
} else {
System.out.print("No command found.\n:");
}
}
}
public static void printHelp() {
System.out.println("help\tShow this prompt\nconnect\tStarts a new connection\nquit\tQuit the program\nexit\tExit a connection");
}
public void connect(Scanner in) {
Socket soc = null;
InetAddress addr = null;
System.out.print("IP_ADDRESS/HOST:");
String ip = in.nextLine();
System.out.print("PORT:");
int port = in.nextInt();
try {
System.out.println("Attempting to connect to HOST:\'" + ip + "\' on PORT:\'" + port + "\'");
addr = InetAddress.getByName(ip);
soc = new Socket(addr, port);
} catch(Exception e) {
System.out.println("Error connecting to server: " + e.getLocalizedMessage());
return;
}
SwingUtilities.invokeLater(new MessageGUI(ip + ":" + port, soc));
}
}
class MessageGUI implements Runnable {
public MessageGUI(String windowName, Socket server) {
JFrame window = new JFrame(windowName);
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.setSize(500, 300);
window.setLayout(new BorderLayout());
window.setVisible(true);
MessageReceive mr = new MessageReceive(server);
mr.setEditable(false);
mr.setBackground(new Color(0, 0, 0));
mr.setForeground(new Color(0, 255, 0));
mr.setVisible(true);
new Thread(mr).start();
window.add(mr, BorderLayout.CENTER);
DataOutputStream dos = null;
try {
dos = new DataOutputStream(server.getOutputStream());
} catch(Exception e) {
System.out.println("Error creating output stream to server: " + e.getLocalizedMessage());
}
JTextField input = new JTextField();
input.addActionListener(new MessageSend(server, input, dos));
input.setBackground(new Color(0, 0, 0));
input.setForeground(new Color(0, 255, 0));
window.add(input, BorderLayout.PAGE_END);
System.out.println("Displaying connection.");
}
public void run() {}
}
class MessageReceive extends JTextArea implements Runnable {
protected Socket server;
public MessageReceive(Socket server) {
this.server = server;
}
public void run() {
DataInputStream dis = null;
int bytes;
try {
dis = new DataInputStream(server.getInputStream());
} catch(Exception e) {
System.out.println("Error connecting server: " + e.getLocalizedMessage());
}
this.append("Connected.\n");
while (true) {
try {
while ((bytes = dis.read()) != -1) this.append(String.valueOf((char) bytes));
} catch(Exception e) {
System.out.println("Error reading from server: " + e.getLocalizedMessage());
return;
}
}
}
}
class MessageSend implements ActionListener {
protected Socket server;
protected JTextField input;
protected DataOutputStream dos = null;
public MessageSend(Socket server, JTextField input, DataOutputStream dos) {
this.server = server;
this.input = input;
this.dos = dos;
}
public void actionPerformed(ActionEvent ae) {
try {
dos.writeBytes(input.getText() + "\n");
input.setText("");
} catch(Exception e) {
System.out.println("Error writing to server output stream: " + e.getLocalizedMessage());
}
}
}
Here is the code for the Server:
import java.io.*;
import java.net.*;
import java.util.*;
public class MessageServer {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
MessageServer ms = new MessageServer();
System.out.println("Starting server on port " + port + "...");
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
} catch(Exception e) {
System.out.println("Error creating server: " + e.getLocalizedMessage());
System.exit(0);
}
System.out.println("Created server port, now waiting for users...");
Socket client = null;
DatagramSocket ds = null;
try {
ds = new DatagramSocket(4);
} catch(Exception e) {
System.out.println("IN:Error creating Datagram Server: " + e.getLocalizedMessage());
e.printStackTrace();
System.exit(0);
}
while (true) {
try {
client = ss.accept();
System.out.println("Connecting user: " + client.getInetAddress().toString());
} catch(Exception e) {
System.out.println("Error on server: " + e.getLocalizedMessage());
}
new MessageConnectionIn(client, ds).start();
new MessageConnectionOut(client, ds).start();
}
}
}
class MessageConnectionOut extends Thread {
protected Socket client;
public DatagramSocket ds;
public MessageConnectionOut(Socket client, DatagramSocket ds) {
this.client = client;
this.ds = ds;
}
public void run() {
this.setName(client.getInetAddress().getHostAddress() + ":OUT");
try {
System.out.println("OUT:User connected.");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
while (true) {
byte[] outgoing = new byte[4096];
DatagramPacket dp = new DatagramPacket(outgoing, outgoing.length);
ds.receive(dp);
dos.writeChars(new String(outgoing) + "\n");
}
} catch(Exception e) {
System.out.println("OUT:Error connecting " + this.getName() + ": " + e.getLocalizedMessage());
return;
}
}
}
class MessageConnectionIn extends Thread {
protected Socket client;
public DatagramSocket ds;
public MessageConnectionIn(Socket client, DatagramSocket ds) {
this.client = client;
this.ds = ds;
}
public void run() {
this.setName(client.getInetAddress().getHostAddress() + ":IN");
try {
System.out.println("IN:User connected.");
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
while (true) {
String lineIn = br.readLine();
byte[] input = lineIn.getBytes();
System.out.println(lineIn);
byte[] output = new byte[4096];
for (int c = 0; c < output.length; c++) output[c] = 0x0;
for (int i = 0; i < input.length && i < output.length; i++) output[i] = input[i];
DatagramPacket dp = new DatagramPacket(output, output.length, InetAddress.getLocalHost(), 4);
ds.send(dp);
}
} catch(Exception e) {
System.out.println("IN:Error connecting to " + this.getName() + ": " + e.getLocalizedMessage());
return;
}
}
}
UPDATE:
I tried replacing all the DatagramSockets with MulticastSockets and adding it to a group when I declared it, MessageServer.main(). The same problem occurred.
Multicast code:
public class MessageServer {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
MessageServer msgsrv = new MessageServer();
System.out.println("Starting server on port " + port + "...");
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
} catch(Exception e) {
System.out.println("Error creating server: " + e.getLocalizedMessage());
System.exit(0);
}
System.out.println("Created server port, now waiting for users...");
Socket client = null;
MulticastSocket ms = null;
try {
ms = new MulticastSocket(4);
ms.joinGroup(InetAddress.getByName("225.65.65.65"));
} catch(Exception e) {
System.out.println("IN:Error creating Datagram Server: " + e.getLocalizedMessage());
e.printStackTrace();
System.exit(0);
}
while (true) {
try {
client = ss.accept();
System.out.println("Connecting user: " + client.getInetAddress().toString());
} catch(Exception e) {
System.out.println("Error on server: " + e.getLocalizedMessage());
}
new MessageConnectionIn(client, ms).start();
new MessageConnectionOut(client, ms).start();
}
}
}
class MessageConnectionOut extends Thread {
protected Socket client;
public MulticastSocket ms;
public MessageConnectionOut(Socket client, MulticastSocket ms) {
this.client = client;
this.ms = ms;
}
public void run() {
this.setName(client.getInetAddress().getHostAddress() + ":OUT");
try {
System.out.println("OUT:User connected.");
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
while (true) {
byte[] outgoing = new byte[4096];
DatagramPacket dp = new DatagramPacket(outgoing, outgoing.length);
ms.receive(dp);
dos.writeChars(new String(outgoing) + "\n");
System.out.println("SENT_TO:" + this.getName());
}
} catch(Exception e) {
System.out.println("OUT:Error connecting " + this.getName() + ": " + e.getLocalizedMessage());
return;
}
}
}
class MessageConnectionIn extends Thread {
protected Socket client;
public MulticastSocket ms;
public MessageConnectionIn(Socket client, MulticastSocket ms) {
this.client = client;
this.ms = ms;
}
public void run() {
this.setName(client.getInetAddress().getHostAddress() + ":IN");
try {
System.out.println("IN:User connected.");
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
while (true) {
String lineIn = br.readLine();
byte[] input = lineIn.getBytes();
System.out.println(lineIn);
byte[] output = new byte[4096];
for (int c = 0; c < output.length; c++) output[c] = 0x0;
for (int i = 0; i < input.length && i < output.length; i++) output[i] = input[i];
DatagramPacket dp = new DatagramPacket(output, output.length, InetAddress.getLocalHost(), 4);
ms.send(dp);
}
} catch(Exception e) {
System.out.println("IN:Error connecting to " + this.getName() + ": " + e.getLocalizedMessage());
return;
}
}
}
This sample may be help you out.
There is 2 threads for Server.
One for reading UDP messages. I used 2 different ports since I just want to avoid messages read by same process. I don't have 2 machines to test it. Tested on my local host.
Another thread will broadcast UDP messages received by reader thread.
There is a thread safe list which acts between threads as data sync. Received data added to the list. Broadcaster thread polling the list for the data, if there is any broadcast and else sleep for 500 microseconds. Threads are created using executor.
private final static String INET_ADDR = "224.0.0.3";
private final static int PORT1 = 8888;
private final static int PORT2 = 8889;
private static List<String> threadSafeList = null;
public static void main(String[] args) throws UnknownHostException, InterruptedException {
threadSafeList = new CopyOnWriteArrayList<String>();
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Sender(InetAddress.getByName(INET_ADDR), PORT1));
executorService.submit(new Receiver(InetAddress.getByName(INET_ADDR), PORT2));
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
private static class Receiver implements Runnable {
private InetAddress addr;
private int port;
public Receiver (InetAddress inetAddress, int port) throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
}
public void run() {
System.out.println(" # Receiver ");
System.out.println(" # Receiver " + this.port);
byte[] buf = new byte[256];
try {
MulticastSocket clientSocket = new MulticastSocket(this.port);
//Joint the Multicast group.
clientSocket.joinGroup(this.addr);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf, buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.println("Socket 1 received msg: " + msg);
threadSafeList.add(msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private static class Sender implements Runnable {
private InetAddress addr;
private int port;
public Sender (InetAddress inetAddress, int port) throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
}
public void run() {
System.out.println(" # Sender Address " + new String(this.addr.getAddress()));
System.out.println(" # Sender port " + this.port);
// Open a new DatagramSocket, which will be used to send the data.
while (true) {
try (DatagramSocket serverSocket = new DatagramSocket()) {
for (Iterator<String> it = threadSafeList.iterator(); !threadSafeList.isEmpty() && it.hasNext(); ) {
String i = it.next();
String msg = "Sent message no " + i;
// Create a packet that will contain the data
// (in the form of bytes) and send it.
DatagramPacket msgPacket = new DatagramPacket(msg.getBytes(), msg.getBytes().length, this.addr, this.port);
serverSocket.send(msgPacket);
threadSafeList.remove(i);
System.out.println("Server sent packet with msg: " + msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
try {
System.out.println("going for sleep");
Thread.currentThread().sleep(500);
System.out.println("going for sleeping");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Design can be modified by changing the creation of sender thread. Whenever receiver thread gets a message, create a sender thread and do the broadcast and shutdown that thread. You can use reusable thread pool instead of fixed Thread pool what used in this example. And you can pass message as argument while you create sender thread (so list may not be needed at all) and do the submit. I do have code.
public static void main(String[] args) throws UnknownHostException,
InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(new Receiver(InetAddress.getByName(INET_ADDR),
PORT2, executorService));
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
And inner classes,
private static class Receiver implements Runnable {
private InetAddress addr;
private int port;
private ExecutorService executorService;
public Receiver(InetAddress inetAddress, int port,
ExecutorService executorService) throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
this.executorService = executorService;
}
public void run() {
System.out.println(" # Receiver ");
System.out.println(" # Receiver " + this.port);
byte[] buf = new byte[256];
try {
MulticastSocket clientSocket = new MulticastSocket(this.port);
// Joint the Multicast group.
clientSocket.joinGroup(this.addr);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf,
buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.println("Socket 1 received msg: " + msg);
executorService.submit(new Sender(InetAddress
.getByName(INET_ADDR), PORT1, msg));
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And
private static class Sender implements Runnable {
private InetAddress addr;
private int port;
private String message;
public Sender(InetAddress inetAddress, int port, String message)
throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
this.message = message;
}
public void run() {
System.out.println(" # Sender Address "
+ new String(this.addr.getAddress()));
System.out.println(" # Sender port " + this.port);
try {
DatagramSocket serverSocket = new DatagramSocket();
String msg = "Sent message no " + message;
// Create a packet that will contain the data
// (in the form of bytes) and send it.
DatagramPacket msgPacket = new DatagramPacket(msg.getBytes(),
msg.getBytes().length, this.addr, this.port);
serverSocket.send(msgPacket);
System.out.println("Server sent packet with msg: " + msg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Client has got 2 threads,
One for reading broadcaster messages.
Another for sending 5 messages in loop. Once it is finished, thread will shut-down.
No data exchange here, so no thread safe list.
private static class Receiver implements Runnable {
private InetAddress addr;
private int port;
public Receiver(InetAddress inetAddress, int port)
throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
}
public void run() {
System.out.println(" # Receiver ");
System.out.println(" # Receiver port " + this.port);
byte[] buf = new byte[256];
try (MulticastSocket clientSocket = new MulticastSocket(this.port)) {
// Joint the Multicast group.
clientSocket.joinGroup(this.addr);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf,
buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.println("Socket 1 received msg: " + msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And
private static class Sender implements Runnable {
private InetAddress addr;
private int port;
public Sender(InetAddress inetAddress, int port)
throws UnknownHostException {
this.addr = InetAddress.getByName(INET_ADDR);
this.port = port;
}
public void run() {
System.out.println(" # Sender Address "
+ new String(this.addr.getAddress()));
System.out.println(" # Sender port " + this.port);
// Open a new DatagramSocket, which will be used to send the data.
try {
DatagramSocket serverSocket = new DatagramSocket();
for (int i = 0; i < 5; i++) {
System.out.println("inside loop");
String msg = "Sent message no 2" + i;
// Create a packet that will contain the data
// (in the form of bytes) and send it.
DatagramPacket msgPacket = new DatagramPacket(
msg.getBytes(), msg.getBytes().length, this.addr,
this.port);
System.out.println("Before sending to socket");
serverSocket.send(msgPacket);
System.out.println("Server sent packet with msg: " + msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
This article sample code is extended further.
Code to be fine tuned.