0

My app can transfer files and messages between server and client. Server is multithreaded and clients simply connects to it. While file is being transferred, if sender sends a message, it will be consumed as bytes of file.

I don't want to open more ports,

Can I establish a new connection to the server for file transfer? Or I should open a separate port for files.

I don't want to block communication while a file is being transferred.

The question was marked as a duplicate but its not, i am trying to send messages and files simultaneously not one by one. I can already receive files one by one. Read again.

Also, as server is multithreaded, I cannot call server socket.accept() again to receive files in new connection because main thread listening for incoming will try to handle it instead. Is there a way around?

mrid
  • 5,782
  • 5
  • 28
  • 71
  • 1
    Chunk the sending of your file. In between chunks, check if user message needs to be sent. Mark each chunk to know either data or message is sent. – M. le Rutte Oct 08 '17 at 13:08
  • Not a good approach. – user7486817 Oct 08 '17 at 13:18
  • I totally agree, but given the question you ask, it is. – M. le Rutte Oct 08 '17 at 13:21
  • can you add your connection code? if you have a TCP connection, then you should not loss the packets, and if you have one socket, then you have one buffer for sending and one for receiving, so you cannot send any data on the same socket while it's sending the file, but the data should be queued until it finish streaming the file. – Amjad Omari Oct 08 '17 at 13:31

3 Answers3

1

you could use some system of all the lines of a file start with a string like this (file:linenum) and then on the other side it puts that in a file then to send text you could do the same thing but with a tag like (text) Server:

Scanner in = new Scanner(s.getInputStream());
while(true) {
    String message = in.nextLine();
    if(message.length > 14 && message.substring(0,6).equalsIgnoreCase("(file:") {
        int line = Integer.valueOf(message.substring(6).replaceall(")", ""));
        saveToFile(message.substring(6).replaceAll(")","").replaceAll("<1-9>",""));
    } else {
        System.out.println(message);
    }
}

I think that code works but I haven't checked it so it might need some slight modifications

eandr127
  • 35
  • 5
  • Thats how i do it but my approach is far better (no offense). Files are written as name:size:type and then bytes. I receive exact number of bytes on other side. Reading files as bytes is far better than converting them into string. – user7486817 Oct 08 '17 at 14:29
1

Seems to me like trying to multiplex files and messages onto the same socket stream is an XYProblem.

I am not an expert on this, but it sounds like you should do some reading on "ports vs sockets". My understanding is that ip:port is the address of the listening service. Once a client connects, the server will open a socket to actually do the communication.

The trick is that every time a client connects, spawn a new thread (on a new socket) to handle the request. This instantly frees up the main thread to go back to listening for new connections. Your file transfer and your messages can come into the same port, but each new request will get its own socket and its own server thread --> no collision!

See this question for a java implementation: Multithreading Socket communication Client/Server

Mike Ounsworth
  • 2,444
  • 21
  • 28
  • Thats how multithreaded server works, new thread for each socket connection (blocking mode). Question is about not blocking the communication while receiving a file. – user7486817 Oct 08 '17 at 14:32
  • Have I not answered the question? Don't block. Free main thread to accept a new connection... – Mike Ounsworth Oct 08 '17 at 14:34
  • Problem is with already established connection. Server can handle multiple connections fine. Take it as receiving two files at same time. – user7486817 Oct 08 '17 at 14:42
  • So let's go back to the beginning then: why are you trying to send a file over _the same connection_ as your messages? Why not open a new connection for the file? (multiple threads on the client) – Mike Ounsworth Oct 08 '17 at 14:45
  • Fundamentally, if you're trying to send two different kinds of data over the same connection at the same time, this is called multiplexing. It's complicated. It's possible, and in some cases you don't have a choice (like how you have more browser tabs open than there are pins on your ethernet cable), but if you do have a choice, way easier to have one connection per data stream. – Mike Ounsworth Oct 08 '17 at 14:49
  • Who on earth would create a new socket connection for each message. I can send and receive whatever i can on same connection. The only problem here is that when a connection is busy sending a file, it takes time, meanwhile i will not be able to go further. And if u read my question again, thats what i am asking, how can i create a seperate connection so that i can separate file transfer and messages. – user7486817 Oct 08 '17 at 14:54
  • Yes, this is exactly my point: if the file transfer is the problem, then run it in a background thread on the client on a new connection. – Mike Ounsworth Oct 08 '17 at 14:57
  • Your question reads _"as server is multithreaded, i cannot call serversocket.accept() again to receive files in new connection because main thread listening for incoming will try to handle it instead. Is there a way around?"_ I believe the link I provide to the other question answers that ... wtv, I'm done arguing. Good luck. – Mike Ounsworth Oct 08 '17 at 14:58
0

You could introduce a handshake protocol where clients can state who they are (probably happening already) and what they want from the given connection. The first connection they make could be about control, and perhaps the messages, and remain in use all the time. File transfer could happen via secondary connections, which may come and go during a session. Having several parallel connections between a client and a server is completely normal, that is what @MikeOunsworth was explaining too.

A shortcut you can take is issuing short-living, one-time tokens which clients can present when opening the secondary connection and then the server will immediately know which file it should start sending. Note that this approach easily can raise various security (if token encodes actual request data) and/or scalability issues (if token is something completely random and has to be looked up in some table).

tevemadar
  • 12,389
  • 3
  • 21
  • 49
  • It simply ignores any new connection attempts from same client. Maybe i need a separate serversocket with different port. – user7486817 Oct 08 '17 at 17:48
  • U can try 2 connection attempts to a serversocket. It will ignore the second one don't know why. A different client can make connection though – user7486817 Oct 08 '17 at 17:49
  • @user7486817 is the server running on an Android device too? Sounds a bit improbable, but maybe it is worth asking. – tevemadar Oct 08 '17 at 18:07
  • Both server and client are android apps – user7486817 Oct 08 '17 at 18:10
  • @user7486817 If you have time, one thing you could try is creating a dedicated test, some ```ServerSocket``` code simply accepting two connections (preferably nothing multithreaded, just accepting two separate ```Socket```s in a blocking way, one after the other), and a client code which connects this server via two separate ```Sockets```, yet again in simple serial code. – tevemadar Oct 08 '17 at 18:22
  • I just did, to my surprise, it accepted both connections. – user7486817 Oct 08 '17 at 18:55
  • @user7486817 Cool that the test works, but unfortunately it means some bughunting from now. It is not necessarily a bug, it can be a restriction in design too. For example if you strongly assumed that one client will have one connection only, and used some kind of name or even their IP address for indexing some hash table, that will not be able to distinguish between multiple parallel connections and needs some extension. – tevemadar Oct 08 '17 at 21:20