3

I have two problems with an app that i have built for socket communication, first I'll try to explain what the app does and then I'll go into the details of those two problems. First I click on a button, which starts a thread, which sends a multicast massage "group address" through a UDP socket. Once any of the devices receive the massage, they will send a response through TCP socket and my device will act as a server to the one that sent the response. So after debugging I found out the first problem which is clientSocket = serverSocket.accept(); sometimes gets stuck and the app will block everything and keep executing it, which might happen because the udp massage might never arrive at the destination which means there is no client for the tcp server that I've created.

First question: Is there any way to make the serverSocket.accept(); non-blocking or set a time out? I've tried serverSocket.setTimeSoOut() method, but that didn't work. Maybe this problem comes from something other than the UDP message?

The second problem is that if I press the button that calls the thread twice it will throw a BindException address already in use: Which will happen because of the re execution of serverSocket.bind(new InetSocketAddress(4125));. Is there any way to fix/avoid that?

Here are the threads that I'm using: This one is called after I press the button:

 private class ChatClientThread extends Thread {

     DatagramSocket socket;
     String sentence;
     String modifiedSentence;
     BufferedReader inFromUser;

     DataOutputStream outToServer;
     BufferedReader inFromServer;
     Socket clientSocket;
     ServerSocket serverSocket;
      @Override
      public void run() {
       /*Socket socket = null;
       DataOutputStream dataOutputStream = null;
       DataInputStream dataInputStream=null;*/
          clientSocket=null;


       try {
           String data="NewTask_"+EmpPhoneNumber;

           serverSocket=new ServerSocket();
           serverSocket.setReuseAddress(true);
            serverSocket.bind(new InetSocketAddress(4125));
           socket = new DatagramSocket(52276);
           socket.setBroadcast(true);
           InetAddress group = InetAddress.getByName(
                   "224.0.1.2");
           DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
               group, 52276);

           socket.send(packet);

              while(true){
               clientSocket = serverSocket.accept();

              ConnectThread ct=new ConnectThread(clientSocket);
              ct.start();
              }

       } catch (UnknownHostException e) {
        e.printStackTrace();
        final String eString = e.toString();
        TicketDetails.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
         }

        });
       } catch (IOException e) {
        e.printStackTrace();
        final String eString = e.toString();
        TicketDetails.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
         }

        });
       }  finally {






        TicketDetails.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {

         }

        });
       }

      }


     }

this one is called from the above thread as you can see:

private class ConnectThread extends Thread {

      Socket socket;
      String sentence;
         String modifiedSentence;
         BufferedReader inFromUser;

         DataOutputStream outToServer;
         BufferedReader inFromServer;
      ConnectThread(Socket socket){

       this.socket= socket;

      }

      @Override
      public void run() {
       DataInputStream dataInputStream = null;
       DataOutputStream dataOutputStream = null;
       Socket socket2 = null;
       DataOutputStream dataOutputStream2= null;
       DataInputStream dataInputStream2=null;

       try {
           while(true){


               inFromUser = new BufferedReader( new InputStreamReader(System.in));
               outToServer = new DataOutputStream(socket.getOutputStream());
               inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
               sentence = inFromUser.readLine();


               modifiedSentence = inFromServer.readLine();
               socket2 = new Socket(socket.getInetAddress().getHostAddress(), 4125);
                dataOutputStream2 = new DataOutputStream(
                  socket2.getOutputStream());

                String[] parts = modifiedSentence.split("_");
                String partGive = parts[0].substring(4); // 004
                String partEmpId = parts[1];
               if(partGive.equals("GiveMeATask")&&Integer.parseInt(partEmpId)==empId){

                   dataOutputStream2.writeUTF("  "+"SolveProblemOrder_2");
                    dataOutputStream2.flush();
               }



               System.out.println("FROM SERVER: " + modifiedSentence);


               if(modifiedSentence!=null) break;}

           outToServer.close();
           inFromServer.close();


       } catch (IOException e) {
        e.printStackTrace();
       } finally {
        if (dataInputStream != null) {
         try {
          dataInputStream.close();
         } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
         }
        }

        if (dataOutputStream != null) {
         try {
          dataOutputStream.close();
         } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
         }
        }


       }

      }



     }
mhlz
  • 3,497
  • 2
  • 23
  • 35
Ahmad Sanie
  • 3,678
  • 2
  • 21
  • 56
  • You might want to take a look at ServerSocketEx: http://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/io/. I put this together as a framework to encapsulate all the standard plumbing that it seems you are currently stuggling with – ControlAltDel May 12 '15 at 13:51

2 Answers2

2

Those are two very commmon problems. I'll answer the two in reverse order.

  1. The button you are talking about is creating a ServerSocket and binding it to a specific port. In your case, the port is 4125. From looking at your code, you don't seem to be closing that serversocket anywhere. When you click the button a second time, a second instance of ServerSocket tries to bind to the same port - but that port is still in use by the first ServerSocket. In that case, you get a bind exception. One port cannot be used by more than one ServerSocket. The solution would be to close the existing ServerSocket before creating a new one using serverSocket.close();

  2. If you read the documentation, it clearly states what ServerSocket.accept() does: "[...] The method blocks until a connection is made." This is the "getting stuck" that you described. The thread that executes that code is put into a waiting position and continues only when a connection is made, then returns that new connection. The classic approach is to start a new thread that waits for incoming connections so that your main thread continues to execute and your whole application does not "freeze". Another approach would be a non-blocking framework that encapsulates all that overhead away from you, one of those is Apache MINA.

I would highly suggest to look into small example projects that deal with basic client/server behaviour as you will most likely deal with threads here.

Community
  • 1
  • 1
f1sh
  • 11,489
  • 3
  • 25
  • 51
  • I've tried to close the server socket before serverSocket=new ServerSocket(); but it give I/O Exception, null pointer exception any ideas where to put it in the above code – Ahmad Sanie May 12 '15 at 14:14
  • regarding the first problem serverSocket.accept() any idea how to start the thread that will handle it and when to execute other threads that will read the data and write it, could you please provide me with a code that may solve my problem or till me how to put it in order! thanks – Ahmad Sanie May 12 '15 at 14:16
  • Well you can't just close a ServerSocket that has never existed, you can check that using ``if(serverSocket != null){serverSocket.close();}``. But if handling a NullPointerException is one of the problems that you face I highly recommend to get more training in java before you start with sockets and threading. – f1sh May 12 '15 at 14:32
  • yeah i agree, i have to read more about sockets but still trying things out is the best way of learning don't you agree! any way you don't have i already solved most of the problems but i'm still struggling with serverSocket.accept(), so i'm thinking of making a count down timer that will try to accept for lets say 10 seconds then will ignore the serverSocket.accept() if it stays null, what do you think about that ? and is there a better way to ignore serverSocket.accept() after a specific period of time – Ahmad Sanie May 13 '15 at 05:21
0

First problem: It is very likely that your application is not receiving the UDP packages. If serverSocket.accept() doesn't get any clients it'll wait indefinitely for someone to connect. You could avoid this by using yet another thread that just accepts connections to avoid freezing your application. Another way would be to use Java's NIO classes that provide non-blocking IO for pretty much anything. That would require you to use ServerSocketChannel and related classes. (Quick googling also gave me this guide which seems fairly easy to follow).

Second problem: You need to close your ServerSocket once you're done using it. Otherwise the port will never be free again to be used by another ServerSocket. Alternatively you could just leave the Socket open and remember that you already openend it (e.g. with a boolean field in your class).

mhlz
  • 3,497
  • 2
  • 23
  • 35
  • could you please provide a sample code for the first problem – Ahmad Sanie May 12 '15 at 14:08
  • I can't really write out a full example right now but maybe the resources linked in [this answer](http://stackoverflow.com/questions/7097745/selecting-among-multiple-sockets-that-are-ready-to-be-read-from) will help you get there. – mhlz May 12 '15 at 14:14
  • you don't have to my friend i already solve most of the problems that im having but i'm still struggling with serverSocket.accept(), so i'm thinking of making a count down timer that will try to accept for lets say 10 seconds then will ignore the serverSocket.accept() if it stays null, what do you think about that ? and is there a better way to ignore serverSocket.accept() after a specific period of time? – Ahmad Sanie May 13 '15 at 05:19