Problem with Sending and Receiving Files with SPP over Bluetooth - java

I am attempting to transfer files (MP3s about six megabytes in size) between two PCs using SPP over Bluetooth (in Java, with the BlueCove API). I can get the file transfer working fine in one direction (for instance, one file from the client to the server), but when I attempt to send any data in the opposite direction during the same session (i.e., send a file from the server to the client), the program freezes and will not advance.
For example, if I simply:
StreamConnection conn;
OutputStream outputStream;
outputStream = conn.openOutputStream();
....
outputStream.write(data); //Data here is an MP3 file converted to byte array
outputStream.flush();
The transfer works fine. But if I try:
StreamConnection conn;
OutputStream outputStream;
InputStream inputStream;
ByteArrayOutputStream out = new ByteArrayOutputStream();
outputStream = conn.openOutputStream();
inputStream = conn.openInputStream();
....
outputStream.write(data);
outputStream.flush();
int receiveData;
while ((receiveData = inputStream.read()) != -1) {
out.write(receiveData);
}
Both the client and the server freeze, and will not advance. I can see that the file transfer is actually happening at some point, because if I kill the client, the server will still write the file to the hard drive, with no issues. I can try to respond with another file, or with just an integer, and it still will not work.
Anyone have any ideas what the problem is? I know OBEX is commonly used for file transfers over Bluetooth, but it seemed overkill for what I needed to do. Am I going to have to use OBEX for this functionality?

It could be as simple as both programs stuck in blocking receive calls, waiting for the other end to say something... try adding a ton of log statements so you can see what "state" each program is in (ie, so it gives you a running commentary such as "trying to recieve", "got xxx data", "trying to reply", etc), or set up debugging, wait until it gets stuck and then stop one of them and single step it.

you can certainly use SPP to transfer file between your applications (assuming you are sending and receiving at both ends using your application). From the code snippet it is difficult to tell what is wrong with your program.
I am guessing that you will have to close the stream as an indication to the other side that you are done with sending the data .. Note even though you write the whole file in one chunk, SPP / Bluetooth protocol layers might fragment it and the other end could receive in fragments, so you need to have some protocol to indicate transfer completion.

It is hard to say without looking at the client side code, but my guess, if the two are running the same code (i.e. both writing first, and then reading), is that the outputStream needs to be closed before the reading occurs (otherwise, both will be waiting for the other to close their side in order to get out of the read loop, since read() only returns -1 when the other side closes).
If the stream should not be closed, then the condition to stop reading cannot be to wait for -1. (so, either change it to transmit the file size first, or some other mechanism).

Why did you decide to use ByteArrayOutputStream? Try following code:
try {
try {
byte[] buf = new byte[1024];
outputstream = conn.openOutputStream();
inputStream = conn.openInputStream();
while ((n = inputstream.read(buf, 0, 1024)) > -1)
outputstream.write(buf, 0, n);
} finally {
outputstream.close();
inputstream.close();
log.debug("Closed input streams!");
}
} catch (Exception e) {
log.error(e);
e.printStackTrace();
}
And to convert the outputStream you could do something like this:
byte currentMP3Bytes[] = outputStream.toString().getBytes();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(currentMP3Bytes);

Related

About uploading mp3 files from clients to the server using UDP

I am quite new to StackOverflow, if my question is inappropriately asked or confusing, please let me know, thank you!
I am working on an audio streaming project, in which the clients are allowed to upload their mp3 files to the server. The server will store them into a playlist and stream the songs back to all the clients.
Here is my code for the client to upload the mp3:
public static void sendPackets(){
System.out.println("Sending test file...");
try{
while (active){
//The song needs to be uploaded;
File file = new File("Sorrow.mp3")
FileInputStream fis = new FileInputStream(file);
byte[] byteStream = new byte[(int) file.length()];
//Trying to convert mp3 to byteStream
fis.close();
InetAddress destination = InetAddress.getByName("localhost");
DatagramPacket sendingAirMail = new DatagramPacket(byteStream, byteStream.length, destination, 50010); // 50010 is the listening port
serverSocket.send(sendingAirMail); // sending the entire bytestream via UDP
// ServerSocket is a DatagramSocket
break;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
The Problem lies here:
serverSocket.send(sendingAirMail);
As it will give me this error:
java.net.SocketException: The message is larger than the maximum supported by the underlying transport: Datagram send failed
at java.base/java.net.DualStackPlainDatagramSocketImpl.socketSend(Native Method)
at java.base/java.net.DualStackPlainDatagramSocketImpl.send(DualStackPlainDatagramSocketImpl.java:136)
at java.base/java.net.DatagramSocket.send(DatagramSocket.java:695)
at client.sendPackets(client.java:116)
at client$2.run(client.java:67)
After looking up google, I learned that it is because the UDP has a limit of size in each package delivered, so I wish to know how to separate the UDP package properly in this case? I know the TCP will be better in this case, but I think I need to learn how to separate packages anyway because I need to stream back the byte arrays from the server using UDP. Any help will be appreciated!
I can post my server and other client information if needed.
The thing is that you need to cut your file into several pieces and deliver them. For UDP, you need some things to make sure the file is complete and correct. Here are some suggestions:
First, you need to cut your file, so you need to give a seq flag in the head. What's more you may need some extra infomations like the whole size of file, the timestamp and so on.
struct msg {
int seq;
int total_seq;
int size;
void *data;
};
Then, it's better to build a send buffer and recive buffer, check every time if the buffer is empty, if not, send/receive it.
After receiving some pieces, you need to rebuild them using the seq flag. When some seq gets lost, you need retransmission. So you need a retransmission design here.
In a word, you need the following things at least:
A user defined head before information
cut/rebuild file
retransmission(GBN or FEC or both)
Hope that can help you.

Java pattern for subsequent Input & OutputStream

Hello stack overflow world, I've been struggling with the most straight forward and common problem within Java IO, for some time, and now need your help to tackle it.
Check out this piece of code I have in a try block, within a thread.run():
// connect to client socket, and setup own server socket
clientSocket = new Socket(serverHostname, CLIENT_PORT);
//send a test command to download a file
String downloadFileName = "sample.txt";
DataOutputStream dataOutputStream = new DataOutputStream(clientSocket.getOutputStream());
System.out.println("Sending a request to download file : " + downloadFileName + " from user: Arsa node"); //todo: replace with node user later
dataOutputStream.writeUTF("D/sample.txt");
//close socket if host isn't detected anymore, and if socket doesn't become null suddenly
dataOutputStream.flush();
dataOutputStream.close();
System.out.println("****File has been sent****");
in = new DataInputStream(clientSocket.getInputStream());
byte[] retrievedFileData = new byte[8036];
if (in.readInt() > 0) {
System.out.println("Starting file download!");
in.read(retrievedFileData);
System.out.println("File data has been read, converting to file now");
//closing input stream will close socket also
in.close();
}
clientSocket.close();
2 Main questions that have been confusing me to death:
Why does dataOutputStream.close() need to be run for writeUTF to actually send my string to the server socket, I find that when I don't have dos.close(), data isn't retrieved on the other side, further because I close it, I no longer can read from the socket - as it seems the socket connection becomes closed when the Output Stream is previously closed...
What's a better way, following some sort of pattern to do this? For context, all I'm trying to do is write the filename I'm looking to download to my client, then read the response right away, which I expect to be bytes with the file, any error handling I will consider as a part of my development.
Overall, it shouldn't be complicated to write something to a socket, then read and ingest it's response...which doesn't seem to be the case here,
any help would be greatly appreciated! If the ServerSocket code snippet is needed I'm happy to share.
The observed behavior is just a side-effect of close(), as it calls flush() before closing to make sure any buffered data is sent. To solve your problem, you need to call the flush() method instead of closing.
This behavior is not unique to DataOutputStream: a lot of other OutputStream (or Writer) implementations apply buffering, and you will need to flush when you want to ensure the data is sent to the client, written to disk or otherwise processed.
BTW: The DataOutputStream and DataInputStream is for a very specific type of data serialization protocol that is particular to Java. You may want to consider carefully if this is the right protocol to use.

Stream Video from a self-written Server to Android App

I want to write a "simple" Java Server-type application to stream videos to different clients. My first step would be an again "simple" Android App containing a VideoView and a MediaPlayer set to Video Streaming (More Information on Android SDK - MediaPlayer) though later i might add desktop java application too.
What i'm not sure is how i would actually do the streaming on the server. I already wrote a little Http Server processing HTTP GET requests from a client over TCP.
There i write/"stream" the files back using this coding:
FileInputStream fs = new FileInputStream(f);
final byte[] buffer = new byte[1024];
int count = 0;
//add the header information to the respone
while ((count = fs.read(buffer)) >= 0) {
os.write(buffer, 0, count);
}
os.flush();
fs.close();
os.close();
os being the OutputStream of the Response i get through the tcp socket and f being the requested file.
This seems to send the file almost completly at once though and not like i want to, stream it "in chunks".
So my questions are:
What do i, or do i have to change my coding to actually stream the video, or is it already correct this way?
When i want to make it using UDP instead of TCP would i then only put the buffer byte arrays read from the fileinputstream directly into the DatagramPacket and the MediaPlayer would know what to do with it?
PS: I know there are several questions on here about streaming in Java but none of them actually cover the server side but mainly the (in this case Android-) client side.

J2ME - can't shutdown output stream on client side, server hangs on waiting for data [nokia J2ME implementation]

My question is: is there a way to perform a socket OutputStream shutdown or it is not right/fully implemented as it should be by nokia? (J2ME nokia implementation, tested at nokia c6-00 and not closing stream, tested on emulator and works fine)
The main problem is that J2SE server application does not get the end of stream info, the condition read(buffer) == -1 is never true, tries to read from an empty stream and hangs until client is force-killed. This works with a very, very, very ugly workaround on the server side application
Thread.sleep(10);//wait some time for data else you would get stuck........
while ((count = dataInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, count);
if (count != BUFFER_SIZE_1024 || dataInputStream.available() == 0) { //the worlds worst condition ever written... but works
break;
}
Thread.sleep(10);//wait for data input to get some data for dataInputStream.available() to return != 0 if client still sends data else you would not read all data......
}
but this solution is absolutely not acceptable (i dont know something about nokia java coding, i'm missing something, or is it maybe similar to a some sort of nokia-J2ME coding standard and i should get used to it or change platform)
I can't close the client socket after sending data because server sends a response to the client after receiving and processing data.
It looks like this: J2ME client -> J2SE server (hangs on read because client does not perform a outputstream shutdown) -> J2ME
I've tried to:
close the dataOutputStream on the J2ME client - no effect
setSocketOptions (KEEPALIVE, SNDBUF and others) - no effect or errors
nothing seems to work on the target device
sorry but i'm a bit furious right now after this nonsense fight with little java.
I'have searched for the solution but non seems to work
Client code:
SocketConnection socketConnection = (SocketConnection) Connector.open("socket://" + ip + ":" + port);
int count;
byte[] buffer = new byte[BUFFER_SIZE_1024];
// client -> server
DataOutputStream dataOutputStream = new DataOutputStream(socketConnection.openDataOutputStream());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
while ((count = byteArrayInputStream.read(buffer)) != -1) {
dataOutputStream.write(buffer, 0, count);
dataOutputStream.flush();
}
dataOutputStream.close();
byteArrayInputStream.close();
With J2SE, my advice would be to initialize Socket from the java.nio.channels.SocketChannel and just interrupt the blocked thread after reasonable timeout has expired.
I'm not sure which side you are trying to fix, but looks like with J2ME your only option would be to set socket timeout.
EDIT
Actually, now that you've posted client code, I see the problem. If the exception is thrown from the while loop for whatever reason, the output stream is not closed.
Here is my proposed fix for that:
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try
{
DataOutputStream dataOutputStream = new DataOutputStream(
socketConnection.openDataOutputStream()
);
try
{
while ((count = byteArrayInputStream.read(buffer)) != -1) {
dataOutputStream.write(buffer, 0, count);
dataOutputStream.flush();
}
}
finally
{
dataOutputStream.close();
}
}
finally
{
byteArrayInputStream.close();
}
Note, that it is not strictly necessary to close ByteArrayInputStream, but the code has a habit to mutate, and some day that input stream may become something that needs explicit close.
I've tried the code with the same effect - on the emulator works like a charm, on the device hangs but i solved my problem as follows:
On the J2ME client before sending the 1024 byte packet I'm sending its length and its state (IsNext or IsLast) after this on the J2SE server side in a while(true) loop. I'm reading first the length with a readShort, then state with a readByte (I know it's better to combine it on a one short but I didn't knew if it will work and if the effort was worth it and now when it works I'm not touching this, besides it is easy to add a new state if necessarily and it works quite fast).
After this server goes in to a second nested loop [ while (dataInputStream.available() < length) {} - I'll have to put here a timeout but I'll worry about that later. Also note that on J2ME dataInputStream.available() always returns a 0 (!) so in the J2ME client read in this place is a for (int i = 0; i < length... loop reading a single byte]
When the while(dataInputStream.available() ... loop breaks I'm reading a block of data which length I have, and if the state is IsLast I break the while(true) loop. Works perfectly and stable.
Thanks for the advice and hope this info will help someone

File transfer through Socket in java

I'm making a Network File Transfer System for transfering any kind of file over a network in java. The size also could be of any kind. Therefore I've used UTF-8 protocol for the task.
I'm providing the codes which I've made but the problem is some times the file gets transfered as it is, with no problem at all. But sometimes few kb's of data is just skipped at the receiving end, which actually restricts the mp3/video/image file to be opened correctly. I think the problem is with BUFFER. I'm not creating any buffer which, right now, I think may be of some use to me.
I would really appreciate if anyone could provide any help regarding the problem, so that the file gets transferred fully.
Client side : --->> File Sender
Socket clientsocket = new Socket(host,6789); // host contains the ip address of the remote server
DataOutputStream outtoserver = new DataOutputStream(clientsocket.getOutputStream());
try
{
int r=0;
FileInputStream fromFile1 = new FileInputStream(path); // "path" is the of the file being sent.
while(r!=-1)
{
r = fromFile1.read();
outtoserver.writeUTF(r+"");
}
}
catch(Exception e)
{
System.out.println(e.toString());
}
clientsocket.close();
Server side: --->> File Receiver
ServerSocket welcome = new ServerSocket(6789);
Socket conn = welcome.accept();
try
{
String r1 = new String();
int r=0;
FileOutputStream toFile1 = new FileOutputStream(path); // "path" is the of the file being received.
BufferedOutputStream toFile= new BufferedOutputStream(toFile1);
DataInputStream recv = new DataInputStream(conn.getInputStream());
while(r!=-1)
{
r1 = recv.readUTF();
r = Integer.parseInt(r1);
toFile.write(r);
}
}
catch(Exception e)
{
System.out.println(e.toString());
}
I don't understand why you are encoding binary data as text.
Plain sockets can send and receive streams of bytes without any problems. So, just read the file as bytes using a FileInputStream and write the bytes to the socket as-is.
(For the record, what you are doing is probably sending 3 to 5 bytes for each byte of the input file. And you are reading the input file one byte at a type without any buffering. These mistakes and others you have made are likely to have a significant impact on file transfer speed. The way to get performance is to simply read and write arrays of bytes using a buffer size of at least 1K bytes.)
I'm not sure of this, but I suspect that the reason that you are losing some data is that you are not flushing or closing outtoserver before you close the socket on the sending end.
FOLLOW UP
I also noticed that you are not flushing / closing toFile on the receiver end, and that could result in you losing data at the end of the file.
The first problem I see is that you're using DataInputStream and DataOutputStream. These are for reading/writing primitive Java types (int, long etc), you don't need them for just binary data.
Another problem is that you're not flushing your file output stream - this could be causing the lost bytes.
An explicit flush might help the situation.

Categories