Multithreading Thread restart - java

i'am writing a small app to remote control a (Behringer x32) Mixing console. And i got a problem with the communication.
I'am sending data from the pc (app) to the console (port 10023 UDP Protocol), then the console answers to the port from the pc has send data, (random port).
So i have 2 Threads one for sending data, and one for listening for data from the console..... so every time i send data to the console, i need to change the listening port... so i have to kill the listening thread and start it new.
But after some time a have and the app has about x1000 threads open.
How can i restart the Thread or update the listening port without create a new thread?
here's the code for this section, the whole files are # gihub
the listening thread class:
public class Receiver implements Runnable {
private List<IReceiverListener> listeners;
private final static int PACKETSIZE = 48;
private int port;
public Receiver() {
listeners = new ArrayList();
}
public void addReceiverListener(IReceiverListener listener) {
listeners.add(listener);
}
private void update(String data, String adress) {
for (IReceiverListener listener : listeners) {
listener.receiveConsoleData(data, adress);
if (data.indexOf("active") > -1) {
listener.incrementWatchDog();
}
}
}
#Override
public void run() {
try {
// Convert the argument to ensure that is it valid
// Construct the socket
while (true) {
//System.out.println("Listen on Port:" + this.port);
DatagramSocket socket = new DatagramSocket(this.port);
// Create a packet
DatagramPacket packet = new DatagramPacket(new byte[PACKETSIZE], PACKETSIZE);
// Receive a packet (blocking)
socket.receive(packet);
// Print the packet
update(new String(packet.getData()), packet.getAddress().toString());
//logger.addLogData(new String(packet.getData())+" "+packet.getAddress().toString());
// Return the packet to the sender
socket.close();
}
} catch (IOException e) {
}
}
public void setPort(int port) {
this.port = port;
}
public int getPort() {
return port;
}
}
and here my port updateFunction
#Override
public void updatePort(int port) {
receiverThread.interrupt();
receiverThread = null;
receiver.setPort(port);
receiverThread = new Thread(receiver);
receiverThread.start();
}
and the sending thread does this, when it sends data:
listener.updatePort(dsocket.getLocalPort());

This is actually not a threading problem. The problem is, that the receiver thread is stuck in the receive method, so it cannot react to the changed port. However, calling the method DatagramSocket#close from another thread releases the blocking receiver thread with a SocketException.
Thus, you can solve this by closing the currently receiving socket when the receiving port was changed. The receiving thread can now catch the SocketException and create a new DatagramSocket that listens on the new port.
There is no need to kill and recreate threads.
First you put the socket into a field. This allows you to access it from another thread, so you can call the socket.close() method. Second, you put another try-catch block into the while(true) loop, which only catches SocketException.
Something like this might work fine:
public class Receiver implements Runnable {
private static final int PACKETSIZE = 48;
private final ConcurrentLinkedQueue<IReceiverListener> listeners = new ConcurrentLinkedQueue<>();
private volatile DatagramSocket socket;
private volatile int port;
public Receiver(int port) {
this.port = port;
}
public void addReceiverListener(IReceiverListener listener) {
listeners.add(listener);
}
public void updatePort(int port) {
this.port = port;
DatagramSocket socket = this.socket;
if (socket != null) {
socket.close();
}
}
#Override
public void run() {
try {
while (true) {
receiveLoop(new DatagramSocket(port));
}
} catch (IOException e) {
// handle error
}
}
private void receiveLoop(DatagramSocket newSocket) throws IOException {
try (DatagramSocket socket = newSocket) {
this.socket = newSocket;
while (true) {
DatagramPacket packet = new DatagramPacket(new byte[PACKETSIZE], PACKETSIZE);
socket.receive(packet);
process(packet);
}
} catch (SocketException e) {
// port was changed -> return and restart with a new socket
} finally {
this.socket = null;
}
}
private void process(DatagramPacket packet) {
update(new String(packet.getData()), packet.getAddress().toString());
}
private void update(String data, String adress) {
for (IReceiverListener listener : listeners) {
listener.receiveConsoleData(data, adress);
if (data.indexOf("active") > -1) {
listener.incrementWatchDog();
}
}
}
}
Please note, that this might still contains some bugs. It is only supposed to give you a rough idea of how to solve this.

As you are using DatagramSocket, you can change the used port by Binding the socket to a new port rather than the used one:
socket.bind(new InetSocketAddress(new_port));
But remember that bind() method won't work unless the socket is already opened and a port assigned to it, so at the first time you have to create the socket regularly, then when you try to change the port, just bind it.
And the following is a complete visualization of the process:
public void video_udp_server(int port) throws Exception
{
byte[] receiveData = new byte[Integer.MAX_VALUE/100];
for(int i = 0; i < receiveData.length; i++){
receiveData[i] = ' ';
}
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
DatagramSocket socket = null;
try{
socket = new DatagramSocket(port);
}catch(Exception ex){
socket.bind(new InetSocketAddress(port));
}
socket.setReuseAddress(true);
socket.receive(receivePacket);
System.out.println(new String(receivePacket.getData()));
}

Related

Why DatagramSocket doesnt send in some pcs

I'm developing a net game with udp socket (DatagramSocket) between two clients (the server notifies both the respective ip and the clients establish the connection). The problem is that the connection isn't working on all PCs. It works for some friends, but doesn't work for others. Denifitely the problem is sending.
Send hi is a function to send a sort message repeatedly to start the port (I discovered that to receive in UDP port it's necessary to send first), and send ack it just a confirmation to the "hi"
(There is a process calling receive, and obviously i send and receive in the same port)
This would be the most important:
public class connection {
protected DatagramSocket socketUDP;
protected InetAddress address;
protected int timeout = 50;
protected int portSend;
protected byte[] bufReceive = new byte[65535];
protected byte[] bufSend;
private boolean isUDP = true;
public connection(String ip, int port, int timeout, boolean isUDP) {
this.isUDP = isUDP;
this.timeout = timeout;
try {
if(isUDP) {
socketUDP = new DatagramSocket(port);
this.portReceive = port;
if (timeout > 0) {
socketUDP.setSoTimeout(timeout);
}
address = InetAddress.getByName(ip);
}
else{
///
}
}catch (Exception e){
e.printStackTrace();
}
this.rec = new receiver(this);
this.rec.start();
}
private void send(int id, Object msg, boolean string){
if(isUDP) {
bufSend = (Integer.toString(id) + ";NR;" + (String)msg).getBytes();
DatagramPacket packet = new DatagramPacket(bufSend, bufSend.length, address, portSend);
try {
socketUDP.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
}
else {
/////
}
}
public void receive(){
if(blockReception || socketUDP != null && !socketUDP.isConnected()){return;}
try {
if(isUDP) {
String received = "";
DatagramPacket packet
= new DatagramPacket(bufReceive, bufReceive.length);
socketUDP.receive(packet);
InetAddress address = packet.getAddress();
int port = packet.getPort();
received = new String(packet.getData(), 0, packet.getLength());
if(received.equals("HI")){
sendAck(msgID.toClient.hi);
return;
}
System.out.println(received)
}
else{
//////
}
}catch (Exception e){e.printStackTrace();}
}
public void setPortSend(int portSend) {
this.portSend = portSend;
if(isUDP) {
socketUDP.connect(address, portSend);
sendHi();
}
}
}
I hope someone can say me why it isn't working for all users.
Most personal firewalls or antiviruses are blocking UDP inbound traffic. Business and education organizations are often blocking UDP other than for some common services. Some ISP s may also be blocking UDP traffic on unusual ports.

Multi threaded server sending and receiving data between two clients at same time

What I need is a server that can receive data from any client and send it to any other clients that are connected. I've looked all over the internet for help but everything I try fails.
I need the server to run on a single port. I need it to be able to send strings in this format: ID:XPOS:ZPOS:ROTATION:ECT e.g. 256:56:88:90:Steve. Then I need the other clients to receive this and split it.
The server will need to be threaded so that it can support multiple clients.
I managed to do this with BlockingQueues. It's not the best solution though, java.nio scales much more better but i guess it works for something around 50 clients perfectly.
You can create a thread for each client, in that thread you have an infinite loop which waits for a queue to get items from. When the queue is empty all client threads are blocked so there is no busy waits. Whenever a message needs to be broadcasted add it to the message queue of clients.
class Server {
public static final int port = 11111;
private final ServerSocket mServerSocket;
private final Collection<Client> mClients;
private boolean acceptNewClients;
public Server() {
mServerSocket = new ServerSocket(port);
mClients = new ArrayList<Client>();
acceptNewClients = true;
ThreadManager.t.execute(new Runnable() {
#Override
public void run() {
Client c;
while (acceptNewClients) {
// On new client connected
c = new Client(mServerSocket.accept());
mClients.add(c);
}
}
});
}
private void broadcast(String message) {
for (Client c : mClients)
c.sendMessage(message);
}
}
class ThreadManager {
public static final ExecutorService t = Executors.newCachedThreadPool();
}
final class Client implements Runnable {
private Socket mSocket;
private OutputStreamWriter mWriter;
private InputStreamReader mReader;
private boolean mContinueNetworking;
private LinkedBlockingDeque<String> mCommandsToSend;
public Client(Socket s) {
mSocket = s;
mWriter = new OutputStreamWriter(socket.getOutputStream());
mReader = new InputStreamReader(socket.getInputStream());
mCommandsToSend = new LinkedBlockingDeque<String>();
mContinueNetworking = true;
ThreadManager.t.execute(this);
}
public void sendMessage(String message) {
mCommandsToSend.addLast(message);
}
#Override
public void run() {
String message;
while (mContinueNetworking) {
message = mCommandsToSend.take();
try {
mWriter.write(message);
mWriter.write('\n');
mWriter.flush();
} catch (SocketException e) {
e.printStackTrace();
mContinueNetworking = false;
} catch (IOException e) {
e.printStackTrace();
// optional: uncomment for retry in case of failure
// commandsToSend.put(toSend);
}
}
}
}

Is it possible to have multiple threads listening on the same DatagramSocket?

I'm writing a chat program in java and I have been stuck for hours with this problem. This is my class that waits for clients to connect to the server.
Every time a new client connects I create a new ChatClient(String name, DatagramSocket serverSocket,InetAddress IPAddress, int port) object.
My idea was that every ChatClient object listens on the socket and when a package is sent from the same IP as the ChatClient, it will handle it, otherwise do nothing.
As it is now, when I only have one client connected; the client gets every 2 packages, then run() in WaitForConnection() gets the rest.
So my question, is it possible to have multiple threads listening on the same DatagramSocket without loss (everyone gets everything send). If there is a solution, how?
private ArrayList<ChatClient> clients;
private DatagramSocket serverSocket;
private boolean running;
public WaitForConnection() {
running = true;
clients = new ArrayList<ChatClient>();
try {
serverSocket = new DatagramSocket(ChatServer.port);
} catch (SocketException e) {
System.out
.println("Couldn't open socket. Port might alreadybe in use");
e.printStackTrace();
}
try {
serverSocket.setReuseAddress(true);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run() {
while (running) {
for (ChatClient ch : clients) {
System.out.println(ch.toString());
}
byte[] handShake = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(handShake,
handShake.length);
try {
serverSocket.receive(receivePacket);
} catch (IOException e) {
System.out.println("Waiting for connections error");
e.printStackTrace();
}
String connect = new String(receivePacket.getData());
System.out.println(connect);
InetAddress IPAddress = receivePacket.getAddress();
// if connect == "OPEN_CONNECTION" -> new client want to connect.
if (connect.contains("openconnection")) {
int port = receivePacket.getPort();
try {
ChatClient chatClient = new ChatClient(
IPAddress.getHostName(), serverSocket, IPAddress,
port);
// Don't want double clients.
for (int i = 0; i < clients.size(); i++) {
if (clients.get(i).equals(chatClient)) {
clients.remove(i);
}
}
clients.add(chatClient);
} catch (IOException e) {
System.out.println("Couldn't connect to client");
e.printStackTrace();
}
}
}
}
}
Code for ChatClient if you need to look at it.
public class ChatClient extends Thread {
private InetAddress IPAddress;
private DatagramSocket serverSocket;
private int port;
private String name;
public ChatClient(String name, DatagramSocket serverSocket,
InetAddress IPAddress, int port) throws IOException {
super(name);
this.name = name;
this.IPAddress = IPAddress;
this.serverSocket = serverSocket;
this.port = port;
byte[] confirmConnection = new byte[1024];
String connected = "Connection to server established";
confirmConnection = connected.getBytes();
serverSocket.send(new DatagramPacket(confirmConnection,
confirmConnection.length, IPAddress, port));
start();
}
public void run() {
while (true) {
byte[] message = new byte[1024];
DatagramPacket receivedPacket = new DatagramPacket(message,
message.length);
try {
serverSocket.receive(receivedPacket);
} catch (IOException e) {
System.out
.println("Something went wrong receiving data in ChatClient");
}
if (receivedPacket.getAddress().equals(IPAddress)) {
String connect = new String(receivedPacket.getData());
connect = connect.toUpperCase();
System.out.println(connect + "client side");
message = connect.getBytes();
try {
serverSocket.send(new DatagramPacket(message,
message.length, IPAddress, port));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
It is possible for multiple threads to receive from the same DatagramSocket, but only one of them will get each datagram.
I don't see why you think you need this.
It is technically not possible, because the network hardware receives the packet only once. But then you can always duplicate it in memory once it is read. In your code basically just do Arrays.copyOf(receivePacket)
For a more sophisticated version, you could use the NIO package and work with a Selector. This would allow you to have all network connections run through a single thread, that reads and distributes the data to processing threads. That saves you the extra threading-overhead if you have multiple connections from many clients.

How to reuse DatagramSocket?

I have a problem using DatagramSocket. The problem is that I can't run two Android JUnit tests one after another using DatagramSockets because the second tests throws the following exception:
java.net.BindException: Address already in use
I guess this will be a problem in Activities too, because when the Activity moves from background to foreground, I would probably get the same exceptions.
I'm satisfied if I could either disconnect and reconnect the socket or if I'm able to reuse the old socket but I can't get one of them working. My reusing concept looked like this:
if (serverSocket == null || !serverSocket.isBound()) {
serverSocket = new DatagramSocket(9800);
}
But this doesn't work, same exception. It doesn't even work when I try to reinstantiate it (when I don't negate the 2nd term).
I tried to dis- and reconnect it...
serverSocket.disconnect();
serverSocket = new DatagramSocket(null);
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress("localhost", 9800));
Doesn't work either. Same exception when executing the second test. What can I do to solve this? Here is the whole class:
public class UdpListener extends Thread implements Subject {
private DatagramSocket serverSocket;
private DatagramPacket receivedPacket;
private volatile boolean running = false;
private String sentence = "";
private Observer observer;
private static final String TAG = "UdpListener";
public UdpListener(Observer o) throws SocketException {
observer = o;
if (serverSocket == null || !serverSocket.isBound()) {
serverSocket = new DatagramSocket(9800);
}
}
#Override
public void run() {
setName(TAG);
while (isRunning()) {
byte[] receivedData = new byte[1024];
receivedPacket = new DatagramPacket(receivedData, receivedData.length);
try {
serverSocket.receive(receivedPacket);
}
catch (IOException e) {
Log.w(TAG, e.getMessage());
}
try {
sentence = new String(receivedPacket.getData(), 0, receivedPacket.getLength(), "UTF-8");
if (UdpState.UPDATE.toString().equals(sentence)) {
notifyObserver();
}
}
catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage());
}
}
}
private boolean isRunning() {
return running;
}
public void setThreadRunning(boolean running) throws SocketException {
this.running = running;
if (running) {
// serverSocket = new DatagramSocket(9800);
this.start();
}
else {
// serverSocket.disconnect();
// serverSocket = new DatagramSocket(null);
// serverSocket.setReuseAddress(true);
// serverSocket.bind(new InetSocketAddress("localhost", 9800));
}
}
#Override
public void notifyObserver() {
observer.update();
}
}
ok I was just looking at your code for a while and I just realized you never call:
serverSocket.close();
call it after you call:
serverSocket.disconnect();
and your problem should be solved.
Your code:
if (serverSocket == null || !serverSocket.isBound()) {
serverSocket = new DatagramSocket(9800);
}
Will be short-circuited if the serverSocket instance is null, aka the second check to ensure it is not bound may not get called.
Keep in mind also that there may be a lag period between calling disconnect on your Datagram socket and when the OS actually releases said socket for reuse.

Sockets, Threads and Services in android, how to make them work together?

I am facing a probleme with threads and sockets I cant figure it out, if someone can help me please i would really appreciate.
There are the facts :
I have a service class NetworkService, inside this class I have a Socket attribute.
I would like it be at the state of connected for the whole lifecycle of the service.
To connect the socket I do it in a thread, so if the server has to timeout, it would not block my UI thread.
Problem is, into the thread where I connect my socket everything is fine, it is connected and I can talk to my server, once this thread is over and I try to reuse the socket, in another thread, I have the error message Socket is not connected.
Questions are :
- Is the socket automatically disconnected at the end of the thread?
- Is their anyway we can pass back a value from a called thread to the caller ?
Thanks a lot,
Here is my code
public class NetworkService extends Service {
private Socket mSocket = new Socket();
private void _connectSocket(String addr, int port) {
Runnable connect = new connectSocket(this.mSocket, addr, port);
new Thread(connect).start();
}
private void _authentification() {
Runnable auth = new authentification();
new Thread(auth).start();
}
private INetwork.Stub mBinder = new INetwork.Stub() {
#Override
public int doConnect(String addr, int port) throws RemoteException {
_connectSocket(addr, port);
_authentification();
return 0;
}
};
class connectSocket implements Runnable {
String addrSocket;
int portSocket;
int TIMEOUT=5000;
public connectSocket(String addr, int port) {
addrSocket = addr;
portSocket = port;
}
#Override
public void run() {
SocketAddress socketAddress = new InetSocketAddress(addrSocket, portSocket);
try {
mSocket.connect(socketAddress, TIMEOUT);
PrintWriter out = new PrintWriter(mSocket.getOutputStream(), true);
out.println("test42");
Log.i("connectSocket()", "Connection Succesful");
} catch (IOException e) {
Log.e("connectSocket()", e.getMessage());
e.printStackTrace();
}
}
}
class authentification implements Runnable {
private String constructFirstConnectQuery() {
String query = "toto";
return query;
}
#Override
public void run() {
BufferedReader in;
PrintWriter out;
String line = "";
try {
in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
out = new PrintWriter(mSocket.getOutputStream(), true);
out.println(constructFirstConnectQuery());
while (mSocket.isConnected()) {
line = in.readLine();
Log.e("LINE", "[Current]- " + line);
}
}
catch (IOException e) {e.printStackTrace();}
}
}
Define the output stream as a member variable, attach it in your thread, and only close that stream when you're done...
Currently you're opening (and implicitly closing) the output stream within the thread. As the thread dies, it will close that output stream, which in turn may be killing the socket/connection.
If you define the stream outside of the thread, you can attach it within the thread, and close it at a later time such as when the service is asked to terminate.

Categories