Search code examples
javasocketsnetwork-programmingnioserversocket

How to send file name and file content using socket channel


i want to send file name and file content together using socketchannel. i have tried to convert file name to bytes, wrap those bytes in a bytebuffer, then send those buffer contents to the client (this is on the server side).

on the client side, i have tried to loop through the contents in the buffer, convert the bytes to characters and check the presence of a special character to note the end of the file name. when that character is identified, i call the buffer method compact() so that i can now start reading the contents. but this isn't working! my client side first while loop while(bb.hasRemaining()) isn't breaking and no character is printed from this loop!!

Server side

FileChannel sbc;
    ServerSocketChannel ssc=null;
    SocketChannel clientchannel=null;

try { 

 ssc=ServerSocketChannel.open();
 ssc.bind(new InetSocketAddress(5002));

 clientchannel=ssc.accept();

String filename=f.getName()+"?";
  byte[] nameinbytes=filename.getBytes("UTF-8");
System.out.println("name of file to send: "+filename);
ByteBuffer namebuffer=ByteBuffer.wrap(nameinbytes);
clientchannel.write(namebuffer);

                sbc=FileChannel.open(f.toPath());
                 ByteBuffer buff=ByteBuffer.allocate(10000000);

                 int bytesread=sbc.read(buff);
                 double read=(double)bytesread;
                 while(bytesread != -1){
                read+=(double) bytesread;
                buff.flip();
               clientchannel.write(buff);
                buff.clear();
                System.out.println("current position: "+sbc.position());
                bytesread=sbc.read(buff);
                 }
  System.out.println("file data written");

client side

SocketAddress address=new InetSocketAddress(InetAddress.getLocalHost(),5002);
     clientChannel=SocketChannel.open(address);
     ByteBuffer bb=ByteBuffer.allocate(10000000);
     int bytesRead=clientChannel.read(bb);
     String filename="";
     while(bb.hasRemaining()){
         byte bm=bb.get();
         char c=(char)(bm & 0xFF);
         System.out.println(c);
         if(c != '?'){
             filename+=Character.toString(c);
         }else{
             bb.compact();
             break;
         }
     }

      File file=new File("C:\\Users\\C-I-C\\Desktop\\fromclient\\"+filename);

     bout =new FileOutputStream(file);
      sbc=bout.getChannel();

     while(bytesRead != -1){
       bb.flip();
       sbc.write(bb);
       bb.clear();
      bytesRead=clientChannel.read(bb);
     }
     System.out.println("received: "+filename);

Q

How can i send both filename and file contents using the same channel?


Solution

  • Server side

    1. Convert the file name to an array of bytes.
    2. wrap the byte array in a ByteBuffer object.
    3. send the ByteBuffer object content to the socket channel

    After sending the that buffer which contain the file name(of course in bytes):

    1. Now create another ByteBuffer object and give it a size
    2. Start reading file content from a FileChannel object to the buffer.
    3. in a while loop, start sending the contents to the socket channel until an end of file from the file channel is reached.

      ServerSocket server=ServerSocket.open();
      server.bind(new InetSocketAddress(1000));
      SocketChannel clientChannel= server.accept();
      File fileToSend=new File("stalkunderflow.txt").
      String filename=fileToSend.getName();
      byte[] nameBytes=filename.getBytes("UTF-8");
      ByteBuffer nameBuffer=ByteBuffer.wrap(nameBytes);
      clientChannel.write(nameBuffer);
      
      //now  prepare and send file contents
      
      FileChannel sbc=FileChannel.open(fileToSend.toPath());
                   ByteBuffer buff=ByteBuffer.allocate(10000000);
      
                   int bytesread=sbc.read(buff);
      
                   while(bytesread != -1){
                  buff.flip();
                 clientChannel.write(buff);
                  buff.compact();
                  bytesread=sbc.read(buff);
                   }
      

    Client Side

    1. create a ByteBuffer object(can call it nameBuffer) and give it a size(not a big one).

    2. write the contents from the socket channel to the buffer.

    3. flip the buffer and start writing down the buffer contents to a byte array.(do it in a while loop)

    4. convert the byte array to a string and there you have your file name.

    5. after that, create another ByteBuffer object(call it nameBuffer) to to store file contents where now you will be reading from this nameBuffer into a File Channel that write to the file with the name you obtained from the nameBuffer.

       //this is a test enviroment,therefore my server is running on the same machine as the client. 
      SocketAddress address=new InetSocketAddress(InetAddress.getLocalHost(),1000);
       SocketChannel clientChannel=SocketChannel.open(address);
      
       ByteBuffer namebuff=ByteBuffer.allocate(500);
       clientChannel.read(namebuff);
      
      byte[] namebyte=new byte[500];
      String filename="";
      
      int position=namebuff.position();
      
       while(namebuff.hasRemaining()){
          namebyte[position]=namebuff.get();
          position=namebuff.position();
       }
       filename=new String(namebyte,0,position);
      
       File file=new File(filename);
      
       ByteBuffer bb=ByteBuffer.allocate(10000000);
       int bytesRead=clientChannel.read(bb);
       FileOutputStream bout =new FileOutputStream(file);
        FileChannel sbc=bout.getChannel();
      
       while(bytesRead != -1){
         bb.flip();
         sbc.write(bb);
         bb.compact();
        bytesRead=clientChannel.read(bb);
       }