#Java Socket Programming - Multithreading

97 messages · Page 1 of 1 (latest)

silk forge
#

My server class is unable to extract the ACKACK message that was sent from the client, even though the client was able to receive and extract the message sent by the server (ACK).
when the client sends (ACKACK) the console prints the statement (client name) is connected, which is only suppose to be printed once before the ACK is taking place.


public class MultiThreadServer {
public static void main (String [] args) throws Exception {
    DatagramSocket serverSocket = new DatagramSocket(6666);
        while (true) {
            byte[] receiveData = new byte[1024];
            byte[] sendData = new byte[1024];

            System.out.println("FTP Server starting at host: " + InetAddress.getLocalHost().getHostName() +
                ", waiting to be contacted for transferring files...");
           
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(receivePacket);

            String message = new String(receivePacket.getData());
            InetAddress clientAddress = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();
           
            System.out.println(clientAddress.getHostName()+ " has started the connection");

            // Create a new thread to handle the client connection
            Thread t = new Thread(new ClientHandler(serverSocket, clientAddress, clientPort));
            t.start();
        } //!!DO NOT TOUCH WHILE(TRUE)
    }//MAIN METHOD
   
    }//SERVER

   import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class ClientHandler implements Runnable {
private DatagramSocket serverSocket;
private InetAddress clientAddress;
private int clientPort;


public ClientHandler(DatagramSocket serverSocket, InetAddress clientAddress, int clientPort) {
       this.serverSocket = serverSocket;
       this.clientAddress = clientAddress;
       this.clientPort = clientPort;
   }


public void run() {
       try {
        String ACK = "ACK";
           Frame sendFrame = new Frame(clientAddress, "ACK", "", 0, ACK.length(), ACK.getBytes());
           Frame.sendFrame(serverSocket, sendFrame, clientPort, clientAddress);

           while(true) {
           // receive acknowledgement from client
           Frame receiveFrame = Frame.receiveFrame(serverSocket, clientAddress, clientPort);
           String clientACK = new String(receiveFrame.getBody());
           System.out.println("Acknowledgement from client: " + clientACK.trim());
           }
           
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
} 
wheat harborBOT
#

This post has been reserved for your question.

Hey @silk forge! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

silk forge
#

for context here is the frame class:

import java.io.*;
import java.net.*;
import java.util.*;

public class Frame implements Serializable {
private InetAddress hostIP;
   private String msgType;
   private String fileName;
   private int sequenceNo = 0;
   private int length;
   private byte[] body;
   
   
   public Frame(InetAddress hostIP, String msgType, String fileName, int sequenceNo, int length, byte[] body) {
       this.hostIP = hostIP;
       this.msgType = msgType;
       this.fileName = fileName;
       this.sequenceNo = sequenceNo;
       this.length = length;
       this.body = body;
   }
   
   
   public InetAddress getHostIP() {
       return hostIP;
   }

   public String getMsgType() {
       return msgType;
   }

   public String getFileName() {
       return fileName;
   }

   public int getSequenceNo() {
     if (sequenceNo == 0) {
         Random rand = new Random();
         sequenceNo = rand.nextInt(100);
         return sequenceNo;
     }
     else
        return sequenceNo;
   }

   public int getLength() {
       return length;
   }

   public byte[] getBody() {
       return body;
   }
   
   public void setHostIP(InetAddress hostIP) {
       this.hostIP = hostIP;
   }

   public void setMsgType(String msgType) {
       this.msgType = msgType;
   }

   public void setFileName(String fileName) {
       this.fileName = fileName;
   }

   public void setSequenceNo(int sequenceNo) {
      this.sequenceNo = sequenceNo;
   }

   public void setLength(int length) {
       this.length = length;
   }

   public void setBody(byte[] body) {
       this.body = body;
   }

   //converts the frame object into bytes so we can send it
   public static byte[] serializeFrame(Frame object) throws IOException {
       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       ObjectOutputStream out = new ObjectOutputStream(bos);
       out.writeObject(object);
       return bos.toByteArray();
   }
   
   //converts it back into a frame
   public static Frame deserializeFrame(byte[] serializedFrame) throws IOException, ClassNotFoundException {
       // create an input stream to deserialize the object
       ByteArrayInputStream bis = new ByteArrayInputStream(serializedFrame);
       ObjectInputStream in = new ObjectInputStream(bis);
       // deserialize the object into a Frame instance
       Frame frame = (Frame) in.readObject();

       return frame;
   }
   

   public static void sendFrame(DatagramSocket socket, Frame frame, int destPort, InetAddress destAddr) throws IOException {
       byte[] serializedFrame = serializeFrame(frame); // Serialize the frame object into bytes
       DatagramPacket packet = new DatagramPacket(serializedFrame, serializedFrame.length, destAddr, destPort); // Create a datagram packet to hold the serialized frame data
       socket.send(packet); // Send the packet over the socket
   }


   public static  Frame receiveFrame(DatagramSocket socket, InetAddress hostIP, int port) throws IOException, ClassNotFoundException {
       byte[] buffer = new byte[1024];
       DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
       socket.receive(packet);

       if (packet.getAddress().equals(hostIP) && packet.getPort() == port) {
           Frame frame = deserializeFrame(packet.getData());
           return frame;
       } else {
           throw new IOException("Received packet from unexpected host or port");
       }
   }

}
urban delta
#

because you keep listening the port in the server class

#

I bet it starts to listen for a new packet before it creates and starts the new thead, so server class is first who receives the next packet

#

even if both run, the new packet will be received by random thread

#

who will be active, what will read it

#

@silk forge

silk forge
#

i’m able to connect two clients simultaneously and both client receive the ACK. nah that’s as far as the code goes. then it loops itself.
do you have any tips on how i can send another packet from a client who already is connected without having the server separate it into a new thread ?

urban delta
#

thus, server won't be interception packets and won't be creating new thread for same cliend on each packet sent (from client)

silk forge
#

yeah using UDP is a requirement.

urban delta
#

here is another option: you work only with one server class, no another threads. But each client mandatory to send an identifier.

silk forge
#

so, connect to clients on server port 6666
create client handler
move to thread

client handler class:
create a new socket 6669
now all incoming datagram packets from already connected clients will go to server port 6669 ?

silk forge
silk forge
urban delta
#

Frame class could only receive the port of client and that's it.

#

after it creation it sends a packet to client, client reads the new port and remember it

#

connection created

silk forge
#

ok, i’ll give that a go in the morning and update you on any progress. thanks for the tips 😊. ill keep this post open so i can take a look at our conversation to recall.

wheat harborBOT
urban delta
#

to sum up:

  1. client sends request to server on 6666 port
  2. server creates new ClientHandler instance in new Thread, and starts it
  3. ClientHandler object sends response to client
  4. client receives the packet and remembers the port he took this first packet from
  5. connection established
silk forge
#

creates a new frame class ? not a new client handler ?

urban delta
#

yeah, clienthandler

silk forge
#

noted.

urban delta
#

ok, good luck, have fun 😉

wheat harborBOT
#

💤 Post marked as dormant

This post has been inactive for over 300 minutes, thus, it has been archived.
If your question was not answered yet, feel free to re-open this post or create a new one.

silk forge
#

the server is still unable to read from the client

kind swallow
silk forge
#

sure

#
public class MultiThreadServer {
public static void main (String [] args) throws Exception {
    DatagramSocket serverSocket = new DatagramSocket(6666);
        while (true) {
            byte[] receiveData = new byte[1024];
            byte[] sendData = new byte[1024];

            System.out.println("FTP Server starting at host: " + InetAddress.getLocalHost().getHostName() +
                ", waiting to be contacted for transferring files...");
           
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(receivePacket);

            String message = new String(receivePacket.getData());
            InetAddress clientAddress = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();
           
            System.out.println(clientAddress.getHostName()+ " has started the connection");

            // Create a new thread to handle the client connection
            Thread t = new Thread(new ClientHandler(serverSocket, clientAddress, clientPort));
            t.start();
        } 
    }
   
    }
public class ClientHandler implements Runnable {
private DatagramSocket serverSocket;
private InetAddress clientAddress;
private int clientPort;

   public ClientHandler(DatagramSocket serverSocket, InetAddress clientAddress, int clientPort) throws Exception {
       this.clientAddress = clientAddress;
       this.clientPort = clientPort;
       this.serverSocket = serverSocket;

   }

public DatagramSocket getServerSocket() throws SocketException {
   serverSocket = new DatagramSocket(6669);
return serverSocket;
}
public void setServerSocket(DatagramSocket serverSocket) {
this.serverSocket = serverSocket;
}


public void run() {
       try {

           while(true) {
           //send initial ACK to confirm the connection
           String ACK = "ACK";
           Frame sendFrame = new Frame(clientAddress, "ACK", "", 0, ACK.length(), ACK.getBytes());
           Frame.sendFrame(serverSocket, sendFrame, clientPort, clientAddress);
           // receive acknowledgement from client
           Frame receiveFrame = Frame.receiveFrame(serverSocket);
  String clientACK = new String(receiveFrame.getBody());
           System.out.println("Acknowledgement from client: " + clientACK.trim());
           }
           
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}
urban delta
silk forge
#

i kinda fixed it for sending string messages, but as soon as i sent a frame it goes back to how it was

#

but i still want to implement what you said because it makes sense

#

but im just not sure how

#
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class ClientHandler implements Runnable {
private DatagramSocket serverSocket;
private InetAddress clientAddress;
private int clientPort;



   public ClientHandler(DatagramSocket serverSocket, InetAddress clientAddress, int clientPort) throws Exception {
       this.clientAddress = clientAddress;
       this.clientPort = clientPort;
       this.serverSocket = serverSocket;

   }

public DatagramSocket getServerSocket() throws SocketException {
   serverSocket = new DatagramSocket(6669);
return serverSocket;
}
public void setServerSocket(DatagramSocket serverSocket) {
this.serverSocket = serverSocket;
}


public void run() {
       try {
        byte [] rData = new byte [1024];
        byte [] sData = new byte [1024];
       

           while(true) {
           //send initial ACK to confirm the connection
           String ACK = "ACK";
           sData = ACK.getBytes();
           DatagramPacket sPacket = new DatagramPacket(sData,sData.length,clientAddress, clientPort);
           serverSocket.send(sPacket);
           DatagramPacket rPacket = new DatagramPacket(rData,rData.length);
           serverSocket.receive(rPacket);
           String clientAck = new String(rPacket.getData());
           // receive acknowledgement from client
           System.out.println("Acknowledgement from client: " + clientAck.trim());
           
           
           rData = new byte [1024];
           rPacket = new DatagramPacket(rData,rData.length);
           serverSocket.receive(rPacket);
           System.out.println("got the packet");
           byte [] fData = rPacket.getData();
           Frame rFrame = Frame.deserializeFrame(fData);
           System.out.println("extracted it");
           String transfer = rFrame.getMsgType();
           System.out.println(transfer);

           
           }
           
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

this is the progress ive made but it stops at the frame

#

that space between the two codes

urban delta
# silk forge but im just not sure how

you have java public ClientHandler(DatagramSocket serverSocket, InetAddress clientAddress, int clientPort) throws Exception { this.clientAddress = clientAddress; this.clientPort = clientPort; this.serverSocket = serverSocket; } But you shouldn't user serverSocket that you received from MultiThreadServer. You shouldn't receive it at all if you decided to generate it in ClientHandler. You might should do something like ```java
this.serverSocket = getServerSocket();

silk forge
#

oooooooooh

#

so now

#

in the run ()
all the messages are being sent through 6669?

urban delta
#

yeah

silk forge
#

ok ive got a question

#

the client makes the connection on 6666

#

the server responds on 6669

#

from the client's end

#

how do i know the server sent it through 6669?

#

without manually doing it myself

urban delta
urban delta
silk forge
#

so each client will be sending on a different port

urban delta
#

right, so they don't interfere with each other

silk forge
kind swallow
#

isn't your server only receiving from one port though?

silk forge
#

now only one client is able to connect

kind swallow
#

yeah

#

that would be the expected behavior since the Server is connected to 6666 or whatever

#

as long as your calling a thread for each Client that's accepted by the ServerSocket, you shouldn't need to change the port and there shouldn't be an interference since it's done concurrently.

silk forge
kind swallow
#

seems like you've only shown Server Side code

#

how is the Client responding

#

ClientHandler class should be a utility class used by the Server to handle Client Connections and specifically Client Requests

#

not act as the Client itself

silk forge
#

there is nothing wrong with the client

#

everything is coming at fault from the server's end

#

like sometimes it works flawlessly

#

and other times

#

it doesnt work like it should

silk forge
#
import java.io.*;
import java.net.*;
import java.util.*;

public class ClientHandler implements Runnable {
private DatagramSocket serverSocket;
private InetAddress clientAddress;
private int clientPort;

   public ClientHandler(DatagramSocket serverSocket, InetAddress clientAddress, int clientPort) throws Exception {
       this.clientAddress = clientAddress;
       this.clientPort = clientPort;
       this.serverSocket = getServerSocket();;

   }

public DatagramSocket getServerSocket() throws SocketException {
   serverSocket = new DatagramSocket();
return serverSocket;
}
public void setServerSocket(DatagramSocket serverSocket) {
this.serverSocket = serverSocket;
}


public void run() {
       try {
        byte [] rData = new byte [1024];
        byte [] sData = new byte [1024];
       
           while(true) {
           //send initial ACK to confirm the connection
           String ACK = "ACK";
           sData = ACK.getBytes();
           DatagramPacket sPacket = new DatagramPacket(sData,sData.length,clientAddress, clientPort);
           serverSocket.send(sPacket);
           DatagramPacket rPacket = new DatagramPacket(rData,rData.length);
           serverSocket.receive(rPacket);
           String clientAck = new String(rPacket.getData());
           // receive acknowledgement from client
           System.out.println("Acknowledgement from client: " + clientAck.trim());
           
           //getting the type of transfer
           rData = new byte [1024];
           rPacket = new DatagramPacket(rData,rData.length);
           serverSocket.receive(rPacket);
          // System.out.println("got the packet");
           byte [] fData = rPacket.getData();
           Frame rFrame = Frame.deserializeFrame(fData);
         //  System.out.println("extracted it");
           String transfer = rFrame.getMsgType();
           
           if(transfer.equals("get")) {
               while(true) {
                   String fileName = rFrame.getFileName();
                   System.out.println("The file name is " + fileName);
                   
                   if (fileName.equals("quit")) {
                            System.out.println("client has terminated their connection");
                            break;
                        } //if-quit
                  
                   File file = new File(fileName);  
                   if (!file.exists()){
                       System.out.println("Client requested a file that does not exist");
                       String msgType = "ERROR: the file does not exist in our server";
                       Frame sframe = new Frame(clientAddress,
                              msgType, //transfer type
                              null, //file name
                              0,   //sequence no.
                              0,  //length
                              null); //body
                              
                   //convert to bytes for sending
                 byte[] sFrame = Frame.serializeFrame(sframe);
                 sPacket = new DatagramPacket(sFrame, sFrame.length, clientAddress,clientPort);
                 serverSocket.send(sPacket); //GET frame sent
                 System.out.println("frame sent");
                 System.out.println("waiting...");
                 break;
                   } //if !exist    
                   
                 //check if it exists 
                   else if(file.exists()) {        
                       //do something
                       System.out.println(";)");
                   }//if exists
           }//while true    
  }//GET
           else if (transfer.equals("put")) {
               
           }//PUT
           else {
               System.out.println("ERROR: invalid transfer type");
           }//ERROR
           
           }//WHILE TRUE
           
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}
#

this is where im at

#

but its not executing anything

#

at all

#

it prints the same statement from the main server program

#

it use to work up until the frames

#

but as soon as i added the if statement to check the file name

#

its no longer functional

#

and now i just ran it after multiple attempts and it works

kind swallow
#

showing you're whole entire program is going to make it a lot harder to decrypt where the problem is coming from. work on create an MRE (https://en.wikipedia.org/wiki/Minimal_reproducible_example)

In computing, a minimal reproducible example (abbreviated MRE) is a collection of source code and other data files which allow a bug or problem to be demonstrated and reproduced. The important feature of a minimal reproducible example is that it is as small and as simple as possible, such that it is just sufficient to demonstrate the problem, bu...

urban delta
silk forge
#

it worked perfectly the first time but it keeps printing repetitive messages and im not sure why

urban delta
silk forge
#
public DatagramSocket getSocket() throws SocketException {
        int port = 0;
        do {
            port = 6666 + (int)(Math.random()*2222);
        } while(usedPorts.contains(port));
 
        return new DatagramSocket(port);
    }
 

whats the purpose of doing this?

urban delta
#

to create DatagramSocket with random free port in range from 6666 to 6666+2221

#

(it should be from 6667, because server works of 6666)

#

and you need it to make each clienthandler work with it's own port , so another threads won't interfere

#

well, you can run it

#

I run the server and 3 clients on same OS

#

worked fine