I created a UDP server. Here's a skeleton
public class UDPserver {
public static void main(String[] args) throws Exception{
while(true){
.... some code ...
packet = new DatagramPacket ( data , data.length, packet.getAddress(), packet.getPort() );
.... some code ...
socket.receive( ... );
}
}
}
Now, i want to make it handle multiple requests, so i checked out that i have to implement Runnable.
public class UDPserver implements Runnable { }
I read that I also need to have a run(). But i don't understand run(). should i put the whole while(true) statement inside run()? what about main()? Can anyone show how to change my code above to handle multiple requests?
thanks
move all the code inside the run method of UDPServer (including the while(true))
In your main method :
UDPServer udpServer = new UDPServer();
udpServer.start();
To make sure that no excpetion won't break your main loop, remember to catch and handle all exceptions that might be rasied inside the while(true) loop
You can also use new thread for each new connection for performing. For example:
class PacketPerforming extends Thread {
DatagramPacket pak;
PacketPerforming(DatagramPacket pak) {
super();
this.pak = pak;
}
public void run() {
// do somethoing with pak
}
}
// in your server thread
while (true) { // i prefered wirte for (;;)
DatagramPacket pak; // take pak object form remote socket
PacketPerforming perform = new PacketPerforming(pak);
perform.start();
}
Related
I have a list of the socket in the main function, add a new socket when a new client connects to the server.
public static void main(String[] args) throws Exception {
// TODO code application logic here
server = new ServerSocket(port);
List<MySocket> sockets = new ArrayList<>();
//this is thread responsible to synchronizing
new SyncThread().start();
while(true){
Socket socket = server.accept();
MySocket mySocket = new MySocket(socket);
sockets.add(mySocket);
SocketThread.setSockets(sockets);
new SocketThread(mySocket).start();
}
}
Besides that, I also want to create a new thread that will synchronize the list of this socket to the client (by sending the list to clients periodically).
public class SyncThread extends Thread{
private static List<MySocket> sockets;
#Override
public void run(){
//send list sockets to client
}
}
How to I synchronize the list of the socket between the main function and SyncThread?
Make your list a synchronized list:
List<MySocket> sockets = Collections.synchronizedList(new ArrayList<>());
And then pass this as a constructor parameter to SyncThread:
new SyncThread(sockets).start(); // Need to add constructor parameter to class.
public class SyncThread extends Thread{
private final List<MySocket> sockets; // NOT static.
public SyncThread(List<MySocket> sockets) {
this.sockets = sockets;
}
...
}
Bear in mind that this doesn't make sockets synchronized for compound operations, e.g. iteration. For that, you'd need to explicitly synchronize on sockets; or choose a different type of list such as CopyOnWriteArrayList, which is inherently thread-safe (the choice depends on the read/write characteristics of how you use the list).
Additionally, it's rarely appropriate to extend Thread directly. Instead, pass it a Runnable:
new Thread(() -> { /* send list sockets to client */ }).start();
I want to access the instance created in t1 from outside the thread, is this possible? So I can close the socket after the thread is executed.
Network class:
public class Network {
Socket socket;
public void changeConnection(String command)
throws Exception { // Whatever exceptions might be thrown
if (command.equals("connect")) {
socket = new Socket(server, port);
}
else if (command.equals("disconnect")) {
socket.close();
}
}
}
Main class:
public class Project1 {
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
try {
Network network = new Network();
network.connect("connect");
}
catch (Exception ex) {
}
}
});
t1.start();
Thread.sleep(20000);
network.connect("disconnect");
}
}
Yes, that's possible.
In your code, the t1 variable is local to main(String[] args):
public static void main(String[] args) {
Thread t1 = ...
}
You cannot access local variables from outside the method where they are declared. In order to do so, you just need to turn the local variable into a class member (also known as field or class property). Then you can set the access modifier to define which classes can access it.
public class Project1 {
protected static Thread t1;
public static void main(String[] args) {
t1 = new Thread...
}
}
The t1 inside main() refers to the class member t1. Of course, because your main() method is static, you also need the class member you want to access from within main() to be static. You can set the access modifier of t1.
Another way to do it
But if you want to close the connection after the thread is executed, then why don't you just close it as the last statement of the thread?
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
try {
Network network = new Network();
network.changeConnection("connect");
// Do loads of work...
// All work has been done and we're done with the
// connection. Why don't we close it just now?
network.changeConnection("disconnect");
}
catch (Exception exc) {
// Catch the exception properly
}
}
});
t1.start();
}
Or using a lambda expression:
Thread t1 = new Thread(() -> {
// body of run()
});
t1.start();
PS: You should always start class names (like Project1) with an uppercase character.
Why you want to open the socket connection in new thread as a non-static object? Because if you are opening the connection then certainly you want to close the connection.
Now if you are opening it in a new thread and as non-static socket connection object then you have keep your main thread alive who is holding the object/handler of the your socket connection so that in the end you can close it, otherwise socket connection will never be closed and the resources and RAM area it had occupied will never be freed.
Disclaimer: Without understanding your complete requirement it is hard to give you a fitting solution but my speculative solutions for you are as below, choose which fits your case/requirement:
One approach:
Generally, database connections are opened as a static object so that it can be accessed by many threads and later be closed be some/last thread. So, you can create a your SocketConnection class and create a static java.net.Socket object, which will be used by all your threads, and once everything is done over that socket connection then your last thread will close the socket connection.
Another approach (use java.lang.ThreadLocal):
If you want to pass some information/object to other pieces of code without passing it in method parameters then ThreadLocal is your friend. It will help you pass the object to any portion of code which is being executed by same thread. ThreadLocal has thread scope, so now you can understand that anything you will put in ThreadLocal will be valid until that thread is alive.
Read this nice tutorial on how to use ThreadLocal.
Another approach (solely based on the code example you used):
I guess you are using Thread.sleep(20000); so that by this sleep is over your thread t1 would have finished opening socket connection, and then you can do something, and at-last close socket connection.
If that is the case, then using sleep() method like this is not recommended. So, after thread has started, you can check if it has finished execution, and if yes then you can do whatever you wish. Below is code example:
final Network network = new Network();
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("Thread started...");
try {
network.changeConnection("connect");
}
catch (Exception ex) {
}
}
});
t1.start();
System.out.println("Thread start command executed...");
//Thread.sleep(20000);
while(t1.isAlive()){
//Do nothing...
}
network.changeConnection("disconnect");
As I think your problem, the solution should be like this.
Main class:
public class project1 {
static Thread t1 = null;
public static void main(String[] args) throws Exception {
t1 = new Thread(new Runnable() {
public void run() {
try {
network network = new network();
network.connect("connect");
}
catch (Exception ex) {
}
}
});
t1.start();
Thread.sleep(20000);
network.connect("disconnect");
}
}
Now you can access it anywhere in Project1 class.
am currently working on a project where I have to build a multi thread server. I only started to work with threads so please understand me.
So far I have a class that implements the Runnable object, bellow you can see the code I have for the run method provided by the Runnable object.
public void run() {
while(true) {
try {
clientSocket = serversocket.accept();
for (int i = 0; i < 100; i++) {
DataOutputStream respond = new DataOutputStream(clientSocket.getOutputStream());
respond.writeUTF("Hello World! " + i);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
//
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
Bellow is the main method that creates a new object of the server class and creates a threat. initializing the Thread.
public static void main(String args[]) {
new Thread(new Server(1234, "", false)).start();
}
I know this creates a new thread but it does not serve multiple clients at once. The first client need to close the connection for the second to be served. How can I make a multi threated server that will serve different client sockets at once? Do I create the thread on the clientSocket = serverSocket.accept();
yes.
from the docs:
Supporting Multiple Clients
To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads—one thread per each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
The thread reads from and writes to the client connection as necessary.
https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
I'm trying to make a multithreaded server/client app with java ! this code is for listen() method in a class of a package that named Bsocket (iserver.core.socket) :
try {
serverSocket = new ServerSocket(port);
}catch(IOException e ){
ui.log(e.toString());//*
}
while (true){
try{
clienSocket = serverSocket.accept();
ui.log("Incomming Connection.");//*
new connectionHandler(clienSocket, ui);
}catch(IOException e ){
ui.log(e.toString());
}
}
ui.log("Incomming Connection."); is a method in below of main class of Bgui (iserver.core.ui).Bgui is a jframe that contain a textarea and something else ! the problem is when the accept methods executed , the ui.log did not works ! whats wrong here ?
You will need to launch your server on a seperate thread since .accept is a blocking call. You might want to do something like so:
(new Runnable() {
#Override
public void run()
{
try {
serverSocket = new ServerSocket(port);
}catch(IOException e ){
ui.log(e.toString());//*
}
while (true){
try{
clienSocket = serverSocket.accept();
ui.log("Incomming Connection.");//*
new connectionHandler(clienSocket, ui);
}catch(IOException e ){
ui.log(e.toString());
}
}
}
}).start();
NOTE: This code is not tested, but it should give you an idea of what you need to do.
Socket.accept() blocks until there's an incoming connection to receive (see the documentation). You shouldn't be making any blocking calls from your UI thread - otherwise it will... you know... block!
You need to separate UI threads from your own network service threads. accept() is blocking (obviously) and it freezes your application until you get a new client, and freezes again waiting for more clients.
Is it correct to create a thread and call its start() method inside a class' constructor as done here?
public class Server implements Runnable {
private ServerSocket server;
public Server(int port) {
try {
//Opens a new server
server = new ServerSocket(port);
} catch (IOException ioe) {
ioe.printStackTrace();
}
new Thread(this, "Server").start();
}
#Override
public void run() {
}
}
IMHO, do not do this. You're allowing the this reference to escape during construction.
Granted, your code isnt doing it but what if your code looked like this:
public Server(int port)
{
new Thread(this, "Server").start();
try
{
//Opens a new server
server = new ServerSocket(port);
}
catch (IOException ioe){ ioe.printStackTrace(); }
}
#Override
public void run(){
if(server == null)throw new NullPointerException();// this may happen
}
}
The server reference may be null even though no exception occurs. This is because the Thread will use the created runnable and invoke the run method even if the constructor of your class hasn't finished.
Server s = new Server();
Thread t = new Thread(s, "Server").start();
is more testable. It allows you to create an instance of Server and unit test its methods without spawning a thread.
A couple more good reasons to split the Thread.start() from the constructor:
If you ever want to use some other framework/system to run the threads, such as a java.util.concurrent.Executor, you may do so.
If you ever want to interrupt the thread, you need a reference to it. Creating the Thread in a separate line of code makes this somewhat more routine / idiomatic. e.g.
Thread rememberMe = new Thread(server).start();
In your original code, Server could have a field to remember myThread, but it didn't.
public class Server implements Runnable
{
private ServerSocket server;
/**
* Because the constructor is private, the only way to instantiate a Server is through
* the static factory method.
* If there are any instantiation problems, the static factory method will fail in
* first line, before it is put into a thread.
* It will be put into a thread before being released.
**/
public static Server startServer ( int port )
{
Server server = new Server ( port ) ;
new Thread ( server , "Server" ) . start ( ) ;
return server ;
}
private Server(int port)
{
try
{
//Opens a new server
server = new ServerSocket(port);
}
catch (IOException ioe){ ioe.printStackTrace(); }
// don't release me into the wild yet!
// new Thread(this, "Server").start();
}
#Override
public void run(){
}
}