Transfer a file between Android devices? - java

I'm making a code and I want to send a mp4 file to another Android device. I have reached to connect both Androids via Wifi and write from one a simple for cycle from 1-20 and the other Android device reads and displays the number that is sent.
Here it is the interesting part of the "sender":
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
Log.d("ClientActivity", "C: Connecting...");
Socket socket = new Socket(serverAddr, port);
connected = true;
while (connected) {
try {
Log.d("ClientActivity", "C: Sending command.");
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket
.getOutputStream())), true);
for (int i = 1; i < 20; i++) {
out.println(i);
i=i++;
and the "receiver":
serverSocket = new ServerSocket(SERVERPORT);
// listen for incoming clients
Socket client = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()),8*1024);
This works great! But I want to send a file from one device to another instead of an int. How can I make this?????

You need to package the data to the stream through a some kind of data format. One way to do this is to use the common MIME data format which is commonly used to send attachment in email.
I have answered other question related to sending binary via socket using this format in the following SO Question - android add filename to bytestream. You could check the accepted answer for that question.
For your reference, I just copied the code for sending and receiving through socket from that question below.
File f = new File(path);
BufferedOutputStream out = new BufferedOutputStream( socket.getOutputStream() );
String filename=path.substring(path.lastIndexOf("/")+1);
// create a multipart message
MultipartEntity multipartContent = new MultipartEntity();
// send the file inputstream as data
InputStreamBody isb = new InputStreamBody(new FileInputStream(f), "image/jpeg", filename);
// add key value pair. The key "imageFile" is arbitrary
multipartContent.addPart("imageFile", isb);
multipartContent.writeTo(out);
out.flush();
out.close();
And the code to read it back below using MimeBodyPart that is part of JavaMail.
MimeMultipart multiPartMessage = new MimeMultipart(new DataSource() {
#Override
public String getContentType() {
// this could be anything need be, this is just my test case and illustration
return "image/jpeg";
}
#Override
public InputStream getInputStream() throws IOException {
// socket is the socket that you get from Socket.accept()
BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
return inputStream;
}
#Override
public String getName() {
return "socketDataSource";
}
#Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
});
// get the first body of the multipart message
BodyPart bodyPart = multiPartMessage.getBodyPart(0);
// get the filename back from the message
String filename = bodyPart.getFileName();
// get the inputstream back
InputStream bodyInputStream = bodyPart.getInputStream();
// do what you need to do here....

There's an open source project released by Google you can take a look at it and have a general idea about connecting devices and sharing files between them.
Here is the link: android-fileshare

Related

TCP Video file transfer

I'm trying to make a video file transfer but am having problems getting the server to start sending bytes.
The first step is for the client to connect, the socket gets accepted. Then the client sends the video file name but the server never reads this.
This is the code for the server up until it blocks:
try(ServerSocket serverSocket = new ServerSocket(4005))
{
Socket socket = serverSocket.accept();
System.out.println("accepted");
OutputStream os = socket.getOutputStream();
BufferedReader receiveReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("This gets printed");
String request = receiveReader.readLine();//never passes this line
System.out.println("This doesn't get printed");
and this is the client up until it blocks waiting for the server to send the video bytes:
try(Socket socket = new Socket(IPAddress, 4005))
{
byte[] messageBytes = new byte[10000];
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.writeBytes("REQUEST;"+videoPath);//This is the line that should send the bytes for the server to read, so it won't block.
String home = System.getProperty("user.home");
String path = home+"\\Downloads" + videoName;
path = path.trim();
FileOutputStream fos = new FileOutputStream(path);
BufferedOutputStream bos = new BufferedOutputStream(fos);
InputStream is = socket.getInputStream();
int bytesRead = 0;
System.out.println("Downloading file...");
while((bytesRead = is.read(messageBytes))!=-1)//This blocks here
Why on earth isn't the server reading the "Request" + videoPath bytes that the server is sending? I tried outputStream.flush() as well, no luck.
Usual problem. You're reading a line but you aren't writing a line. Add a line terminator to the sent message.
When you fix this you will then discover that you can't mix buffered streams and readers on the same socket. I suggest you do all the I/O via the DataInput/OutputStream classes, using read/writeUTF() for the name.
If you're sending multiple files see my answer there.

Protobuf how to receive string and object multiple times

I am using a server and a client. The client only should deserialize the received protobuf message if the string "yes" is received.
EDIT:
The first message of protobuf is received well. But, if I want to send multiple messages at a time, it gives me:
System.OverflowException: Number overflow.
at ProtoBuf.ProtoReader.TryReadUInt32Variant (System.IO.Stream source, System.UInt32& value)
I read through this link, but I can't figured out what I should do in my case...
I am using TCP sockets. Here is an example code:
Client C#:
TcpClient tcpClient = new TcpClient(host, port);
NetworkStream netStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(netStream);
while(true)
{
// Read multiple messages one after another.
string message = reader.ReadLine();
if(message.Equals("yes"))
{
Command command = Serializer.DeserializeWithLengthPrefix<Command> (netStream, PrexiStyle.Base128);
BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create));
bw.Write(command.File);
bw.Flush();
bw.Close();
}
}
Server Java:
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream, true);
try{
// send "yes" and the protobuf messages ten times one after another
for(int i=0; i<10; i++)
{
writer.println("yes");
command.writeDelimitedTo(outputStream);
}
}catch(Exception e)
e.printStackTrace();
}
finally{
outputStream.close();
clientSocket.close();
}
My .proto file and proto contract has the same types. It works if I don't want to send a string, but only the protobuf message.
How can I solve this with using a string before deserializing the protobuf message? Is it possible?
Try separating protobuf data and other data in different sockets. Added a while loop to be able to read multiple messages from server.
using System.Threading;
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
// Protobuf data is read on this socket
TcpClient tcpClient = new TcpClient(host, port);
NetworkStream netStream = tcpClient.GetStream();
StreamReader reader = new StreamReader(netStream);
BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create));
bool running = true;
while(running)
{
bw.Write(Serializer.DeserializeWithLengthPrefix<Command>(netStream, PrexiStyle.Base128).File);
}
bw.Flush();
bw.Close();
}).Start();
// Other data is read no this socket
TcpClient tcpClientForOtherStuff = new TcpClient(host, port);
NetworkStream netStream = tcpClientForOtherStuff.GetStream();
StreamReader readerForOtherStuff = new StreamReader(netStream);
string message;
bool running = true;
BinaryWriter bwForOtherStuff = new BinaryWriter(File.Open(path2, FileMode.Create));
bool running = true;
while(running) bwForOtherStuff.Write(readerForOtherStuff.ReadLine());
bwForOtherStuff.Flush();
bwForOtherStuff.Close();
I have not tested or compiled the code.

Java Message sent from client to server

I'm using a socket to connect my client with the server, I need a way so that when somebody tries to login on the client with an account, it sends the username and password to the server, and checks if the account exists. I just need to know how to make it send the message to the server when they press login.
i tried this to make it send a message to the server
public static void sendmsg(String a, String b)
{
try
{
String host = "127.0.0.1";
int port = 43655;
InetAddress address = InetAddress.getByName(host);
socket = new Socket(address, port);
//Send the message to the server
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String sendMessage = a;
bw.write(sendMessage);
bw.flush();
System.out.println("Message sent to the server : "+sendMessage);
//Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
System.out.println("Message received from the server : " +message);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
//Closing the socket
try
{
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
nice you are working with Sockets, well I have an approach you can try, and maybe if it is useful you can consider for your implementation.
First of all I will create an entity to handle those values and fill it with the incoming data.
class UserAuth {
private String username;
private String password;
//Consider here your getters and setters, I am not including them
}
I will use the entity as the parameter for the method while sending and maybe you can fill it as something like:
UserAuth attemptingUser = new UserAuth(...)
ObjectInputStream works fine for these kind of scenarios. If you still want to work with Strings, you can use BufferedReader and try to merge your username and password as one single String and use the .readLine() method to obtain (separated with commas), then use String methods such Split but I find that could take some more time, should be better if you handle it with an object. But it depends on the complexity you want to add to your application :).
class AuthClient {
public void sendMsg(UserAuth attemptingUser) {
String host = "localhost";
int port = 2055;
//1. Create the socket
Socket sender = new Socket(host, port);
//2. Create an object output stream to write the object into the stream
ObjectOutputStream outputWriter = new ObjectOutputStream(sender.getOutputStream());
//3. Write (send the object)
outputWriter.writeObject(attemptingUser);
//4. Close
outputWriter.close();
sender.close();
}
}
class AuthServer {
ServerSocket ss = new ServerSocket(2055);
public void receiveMsg() {
//1. Accept the connection
Socket conn = ss.accept();
//2. Receive the flow
ObjectInputStream readStream = new ObjectInputStream(conn.getInputStream());
//3. Read the object
UserAuth userReceived = readStream.readObject();
//4. Verify against file, db or whatever
if (userReceived.getUsername().equals("admin") && userReceived.getPassword().equals("admin")) {
//Authentication
}
}
}
(This is added as the part I edit for what you asked me in the comments)
public void sendMsg(String username, String password) {
String host = "localhost";
int port = 2055;
//1. Create the socket
Socket sender = new Socket(host, port);
//2. Create the UserAuth object based on the parameters you received
UserAuth myuser = new UserAuth();
myuser.setUsername(username);
myuser.setPassword(password);
//3. Follow same instructions for the creation of ObjectOutputStream...
ObjectOutputStream objectWriter = new ObjectOutputStream(sender.getOutputStream());
objectWriter.writeObject(myuser);
//That is what I would use if I keep your structure
}
If you want to keep your structure using Strings, I would simplify and reduce impact of I/O by using the String methods. Since you know you are always expecting user/password, I would merge your two params in one single String or use special char and on server side handle with StringTokenizer class. Or maybe handle with the "split" method. You have many options here.
So far, this will be my approach for the problem you are facing. Hope it helps somehow. Best regards and happy coding :).
What you have done looks OK to me but it all depends on what the server is expecting to receive. What is the terminating character as you have not sent one unless it's already contained within your String a variable.
If the server is expecting an end of line character (which you don't currently send) you can use a PrintWriter instead of a BufferedWriter like this
pw = new PrintWriter(socket.getOutputStream(), true);
pw.println(a);
Your server would then be doing something like this
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String value = br.readLine();

Broken pipe using DataInputStream and DataOutputStream and sockets

I set up a client and server sockets. When I use classes ObjectOutputStream and ObjectInputStream and the method readObject/writeObject everything works fine.
It simulates communication with a robot that I know for sure interprets correctly only method
DataOutputStream.writeBytes.
So I set up the new architecture for simulation since the robot is not available for testing on a daily basis.
In the following code where ObjectOutputStream/ObjectInputStream readObject/writeObject were replaced with DataInputStream/DataOutputStream writeBytes and IOutils.toByteArray.
The server socket correctly receives the message but when it tries to write back a response I get a broken pipe as if the connection was closed somewhere.
Notice that I never close sockets or streams because the robot can answer even after 30 seconds.
Any help to make DataOutputStream.writeBytes work would be appreciated.
Here's the non-working code:
Client:
Socket serverSocket = new Socket("server", 9899);
DataOutputStream outputStream = new DataOutputStream(serverSocket.getOutputStream());
//ObjectOutputStream outputStream = new ObjectOutputStream(serverSocket.getOutputStream());
//outputStream.writeObject("\n" + "message" + "\r");
outputStream.writeBytes("\n" + "message" + "\r");
outputStream.flush();
DataInputStream inputStream = new DataInputStream(serverSocket.getInputStream());
//ObjectInputStream inputStream = new ObjectInputStream(serverSocket.getInputStream());
byte [] bytes = IOUtils.toByteArray(inputStream);
String serverResponse = new String(bytes,"UTF-8");
// String serverResponse = (String)inputStream.readObject();
Server:
ServerSocket serverSocket = new ServerSocket(9899);
while (true) {
Socket socket = serverSocket.accept();
//ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
byte [] bytes = IOUtils.toByteArray(inputStream);
String message = new String(bytes,"UTF-8");
//String message = (String) inputStream.readObject();
Thread.sleep(15000);
//ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
//outputStream.writeObject("server response");
outputStream.writeBytes("server response"); //EXCEPTION THROWN HERE FOR BROKEN PIPE
outputStream.flush();
}
Thanks for your time
IOUtils.toString(InputStream) must read the stream until its end, which would imply that the peer has disconnected. So you can't write to it.
If you're exchanging Strings with data streams you should use writeUTF() and readUTF().
Or read and write lines, with a BufferedReader/Writer.

client/server to send a file get stuck somewhere

I have implemented a client/server to send files . When there is no more messages exchanged after sending the file , the code works perfectly , but if the client sends some string to the server directly after the code of receiving the file both client and server stop doing anything and the file is not sent it's something like if they both get stuck in deadlock but I'm not really sure :
Here is the code to send the file without sending anything after it , which works:
Client
String filename;
BufferedReader UIn = new BufferedReader(new InputStreamReader(System.in));
Socket peer = new Socket("localhost",9999);
System.out.print("Enter the file name to download :");
filename= UIn.readLine();
///////////////////////////////
DataOutputStream OutToServer;
OutToServer = new DataOutputStream(peer.getOutputStream());
OutToServer.writeBytes(filename+"\n");
FileOutputStream fos = new FileOutputStream(new File("D:/new.txt"));
BufferedOutputStream out = new BufferedOutputStream(fos);
InputStream in = peer.getInputStream();
buffer = new byte[1024];
while((count=in.read(buffer))>0)
{
fos.write(buffer, 0, count);
System.out.println(buffer);
}
fos.close();
System.out.println("done");
Server:
ServerSocket server =null;
try {
server = new ServerSocket(9999);
while(true)
{
client= server.accept();
//System.out.println("Connection accepted");
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
DataOutputStream outToclient =new DataOutputStream(client.getOutputStream());
String request=inFromClient.readLine();
file = new File(request);
if (file.exists())
{
OutputStream out = client.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
while((count =in.read(buffer)) >0)
{
out.write(buffer,0,count);
out.flush();
}
}
// System.out.println(request);
// outToclient.writeBytes("alaa\n");
}
} catch (IOException ex) {
Logger.getLogger(ServerWork.class.getName()).log(Level.SEVERE, null, ex);
}
But if I try to send anything after the loop between client and server it stops working . Is it because I'm using readLine() and writeBytes()?
You are using both DataOutputStream and OutputStream. I think that they
should work together but what I guess you should do is to flush the buffer (or close it).
After you're done writing everything you want to send, some data may still be in the buffer. Now you will have to flush the buffer, to force it to send all the data.(as it is said here).
outToclient.writeBytes("alaa\n");
outToclient.flush();

Categories