I used FTP and FTPClient in package 'org.apache.commons.net.ftp' to download files from FTP server.
Here is my total example code
public class FtpInput {
private static final Logger LOG = Logger.getLogger(FtpInput.class);
private static final int TIMEOUT = 120000;
private static final String SIZE_COMMAND_REPLY_CODE = "213 ";
/**
* FTPClient
*/
private FTPClient ftpClient;
/**
* FTP size
*/
private long completeFileSize = 0;
protected String ip = "";
protected int port = 21;
protected String user = "";
protected String passwd = "";
protected String path = "";
protected String fileName = "";
/**
* count input bytes
*/
private CountingInputStream is;
/**
* the bytes already processed
*/
private long processedBytesNum;
private byte[] inputBuffer = new byte[1024];
/**
* connect to ftp server and fetch inputStream
*/
public void connect() {
this.ftpClient = new FTPClient();
ftpClient.setRemoteVerificationEnabled(false);
try {
ftpClient.connect(ip, port);
if (!ftpClient.login(user, passwd)) {
throw new IOException("ftp login failed!");
}
if (StringUtils.isNotBlank(path)) {
if (!ftpClient.changeWorkingDirectory(path)) {
ftpClient.mkd(path);
if (!ftpClient.changeWorkingDirectory(path)) {
throw new IOException("ftp change working dir failed! path:" + path);
}
}
}
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setSoTimeout(TIMEOUT);
ftpClient.setConnectTimeout(TIMEOUT);
ftpClient.setDataTimeout(TIMEOUT);
ftpClient.enterLocalPassiveMode();
// keep control channel keep-alive when download large file
ftpClient.setControlKeepAliveTimeout(120);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException("ftp login failed!", e);
}
// get complete ftp size
completeFileSize = getFtpFileSize();
LOG.info(String.format("ftp file size: %d", completeFileSize));
try {
InputStream ftpis = this.ftpClient.retrieveFileStream(this.fileName);
if (ftpis == null) {
LOG.error("cannot fetch source file.");
}
this.is = new CountingInputStream(ftpis);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
/**
* readBytes
*
* #return
*/
public byte[] readBytes() {
byte[] bytes = readBytesFromStream(is, inputBuffer);
// the bytes processed
processedBytesNum = is.getCount();
return bytes;
}
/**
* readBytesFromStream
*
* #param stream
* #param inputBuffer
* #return
*/
protected byte[] readBytesFromStream(InputStream stream, byte[] inputBuffer) {
Preconditions.checkNotNull(stream != null, "InputStream has not been inited yet.");
Preconditions.checkArgument(inputBuffer != null && inputBuffer.length > 0);
int readBytes;
try {
readBytes = stream.read(inputBuffer);
} catch (IOException e) {
throw new RuntimeException(e);
}
if (readBytes == inputBuffer.length) {
// inputBuffer is filled full.
return inputBuffer;
} else if (readBytes > 0 && readBytes < inputBuffer.length) {
// inputBuffer is not filled full.
byte[] tmpBytes = new byte[readBytes];
System.arraycopy(inputBuffer, 0, tmpBytes, 0, readBytes);
return tmpBytes;
} else if (readBytes == -1) {
// Read end.
return null;
} else {
// may other situation happens?
throw new RuntimeException(String.format("readBytesFromStream: readBytes=%s inputBuffer.length=%s",
readBytes, inputBuffer.length));
}
}
/**
* fetch the byte size of remote file size
*/
private long getFtpFileSize() {
try {
ftpClient.sendCommand("SIZE", this.fileName);
String reply = ftpClient.getReplyString().trim();
LOG.info(String.format("ftp file %s size reply : %s", fileName, reply));
Preconditions.checkArgument(reply.startsWith(SIZE_COMMAND_REPLY_CODE),
"ftp file size reply: %s is not success", reply);
String sizeSubStr = reply.substring(SIZE_COMMAND_REPLY_CODE.length());
long actualFtpSize = Long.parseLong(sizeSubStr);
return actualFtpSize;
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
public void close() {
try {
if (is != null) {
LOG.info(String.format("already read %d bytes from ftp file %s", is.getCount(), fileName));
is.close();
}
if (ftpClient != null) {
// Must call completePendingCommand() to finish command.
boolean isSuccessTransfer = ftpClient.completePendingCommand();
if (!isSuccessTransfer) {
LOG.error("error happened when complete transfer of ftp");
}
ftpClient.logout();
ftpClient.disconnect();
}
} catch (Throwable e) {
e.printStackTrace();
LOG.error(String.format("Close ftp input failed:%s,%s", e.getMessage(), e.getCause()));
} finally {
is = null;
ftpClient = null;
}
}
public void validInputComplete() {
Preconditions.checkArgument(processedBytesNum == completeFileSize, "ftp file transfer is not complete");
}
/**
* main
*
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String ip = "***.***.***.****";
int port = 21;
String user = "***";
String passwd = "***";
String path = "/home/work";
String fileName = "b.txt";
FtpInput input = new FtpInput();
try {
input.fileName = fileName;
input.path = path;
input.ip = ip;
input.port = port;
input.user = user;
input.passwd = passwd;
// connect to FTP server
input.connect();
while (true) {
// read bytes
byte[] bytes = input.readBytes();
if (bytes == null) {
break;
}
LOG.info("read " + bytes.length + " bytes at :" + new Date(System.currentTimeMillis()));
// Attention: this is used for simulating the process of writing data into hive table
// it maybe consume more than 1 minute;
Thread.sleep(3000);
}
input.validInputComplete();
} catch (Exception e) {
e.printStackTrace();
} finally {
input.close();
}
}
}
here is the exception message:
java.net.SocketTimeoutException: Read timed out
or
java.net.SocketException: Connection reset
at stream.readBytes in method readBytesFromStream
At first, i think it probably caused by writing into hive table slowly, and then the FTP Server closed the connection.
But actually, the speed of writing into hive table is fast enough.
Now, i need your help, how can i fix this problem.
From your comments, it looks like it can take hours before you finish downloading the file.
You cannot reasonably expect an FTP server to wait for you for hours to finish the transfer. Particularly if you are not transferring anything most of the time. You waste server resources and most servers will protect themselves against such abuse.
Your design is flawed.
You should redesign your application to first fully download the file; and import the file only after the download finishes.
Related
My Mediarecorder gives me a PCM File as an output when I record the phone's microphone. Now when trying to listen to this File that it created all I hear is static and I think, if I have understood correctly, I get a PCM file from Mediarecorder not AAC and I need to add ADTS header to the PCM to be able to listen to it.
I have seen threads with custom Encoders but I can not seem to figure out where and what I need to do with them.
I make an output File from microphone recoridng like this:
private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;
private static final int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int SAMPLE_RATE = 44100; //44.1kHz
private static final int BUFFER_SIZE = 2048;
public Status status = Status.IDLE;
private AudioRecordingHandler arh;
private File outputFile;
private Context context;
/**
* Starts script for running. Needs output file to work!
*/
public void start() {
if (outputFile == null) { return; }
System.out.println("Start reading stream...");
aacEncoder = new AACEncoder(SAMPLE_RATE, micOutputPCM);
new Thread(new Runnable() {
#Override
public void run() {
record.startRecording();
byte[] data = new byte[BUFFER_SIZE];
float[] audioFloatBuffer = new float[BUFFER_SIZE/2];
Yin y = new Yin(SAMPLE_RATE, BUFFER_SIZE/2);
while(status == Status.RECORDING) {
record.read(data, 0, BUFFER_SIZE);
audioFloatBuffer = ConverterUtil.toFloatArray(data, 0, audioFloatBuffer,
0, audioFloatBuffer.length);
PitchDetectionResult pdr = y.getPitch(audioFloatBuffer);
aacEncoder.writeIntoOutputfile(data);
arh.handlePitch(pdr.getPitch());
}
aacEncoder.stopEncoding();
}
}).start();
}
/**
* Stops script
*/
public void stop() {
status = Status.IDLE;
record.stop();
arh.finishedRecording(micOutputPCM);
}
Here is how I get the byte[] from the File and where I try to encode the ADTS header to them.
public static File addHeaderToAac(File micOutputPCM, File output) throws IOException {
byte[] pcmFile = fullyReadFileToBytes(micOutputPCM);
int bufferSize = 2048;
//addADTSHeader to byte[] and return a File object
return fileWithADTSHeader;
}
public static byte[] fullyReadFileToBytes(File f) throws IOException {
int size = (int) f.length();
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
FileInputStream fis= new FileInputStream(f);;
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (IOException e){
throw e;
} finally {
fis.close();
}
return bytes;
}
My question is, does anyone have an Encoder that can accept a File or byte[] or ByteStream as an input and return a File.
Because ultimately I want to make a mp4parser AACTrackImpl, which can be found here : https://github.com/sannies/mp4parser
AACTrackImpl aacTrack2 = new MP3TrackImpl(new FileDataSourceImpl(micOutputPCM));
Also If I am missing some important details about how to convert and what I should do to be able to play it then that information will also be useful.
If I need provide more information in order to answer this question, then I will gladly do so.
Edit:
I've been trying to make an encoder that would do what I need, but so far I have had no success.
public static File addHeaderToAac(File pcmFile1, File output, Context context) throws IOException {
byte[] pcmFile = fullyReadFileToBytes(pcmFile1);
int bufferSize = 2048;
AACEncoder encoder = new AACEncoder(44100, output);
encoder.encodeAudioFrameToAAC(pcmFile);
return output;
}
I am trying to encode the PCM to AAC with this encoder, but this encoder writes the output file to memory, but I need an object. And when I give it my byte[] it also gives me an error :
W/System.err: at java.nio.ByteBuffer.put(ByteBuffer.java:642)
And the error is coming from this line :
inputBuf.put(frameData);
Finally, my encoder:
public class AACEncoder {
final String TAG = "UEncoder Processor";
final int sampleRate;
File outputFile;
FileOutputStream fos;
final int TIMEOUT_USEC = 10000 ;
MediaCodec encoder;
boolean isEncoderRunning = false;
boolean outputDone = false;
MediaCodec.BufferInfo info;
public AACEncoder(final int sampleRate, File outputFile) {
this.sampleRate = sampleRate;
this.info = new MediaCodec.BufferInfo();
this.outputFile = outputFile;
openFileStream();
initEncoder();
}
/**
* Initializes CrappyEncoder for AAC-LC (Low complexity)
* #throws Exception
*/
public void initEncoder() {
try {
encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (IOException ex) {
Log.e(TAG, "Failed to create CrappyEncoder");
ex.printStackTrace();
}
}
int generateIndex = 0;
public void encodeAudioFrameToAAC(byte[] frameData) {
if (encoder == null) return;
if (!isEncoderRunning) {
encoder.start();
isEncoderRunning = true;
}
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
if (fos != null) {
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
long ptsUsec = (System.currentTimeMillis() * 1000) / 10000;
if (outputDone) {
encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];
inputBuf.clear();
inputBuf.put(frameData);
encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);
}
generateIndex++;
}
tryEncodeOutputBuffer();
}
checkIfOutputDone();
}
/**
* Gets data from output buffer and encodes it to
* AAC-LC encoding with ADTS header attached before every frame
*/
private void tryEncodeOutputBuffer() {
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
//If >= 0 then valid response
int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
if (encoderStatus >= 0) {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
encodedData.position(info.offset);
encodedData.limit(info.offset + info.size + 7);
byte[] data = new byte[info.size + 7];
addADTStoPacket(data, info.size + 7);
encodedData.get(data, 7, info.size);
encodedData.position(info.offset);
writeIntoOutputfile(data);
encoder.releaseOutputBuffer(encoderStatus, false);
}
}
private void checkIfOutputDone() {
if (outputDone) {
if (fos != null) {
try {
fos.close();
} catch (IOException ioe) {
Log.w(TAG, "failed closing debug file");
throw new RuntimeException(ioe);
}
fos = null;
}
}
}
/**
* Add ADTS header at the beginning of each and every AAC packet.
* This is needed as MediaCodec CrappyEncoder generates a packet of raw
* AAC data.
*
* Note the packetLen must count in the ADTS header itself.
**/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
// fill in ADTS data
packet[0] = (byte)0xFF;
packet[1] = (byte)0xF9;
packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
packet[4] = (byte)((packetLen&0x7FF) >> 3);
packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
packet[6] = (byte)0xFC;
}
private void openFileStream() {
fos = null;
try {
fos = new FileOutputStream(outputFile, false);
} catch (FileNotFoundException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
/**
* Writes data into file
* #param data
*/
public void writeIntoOutputfile(byte[] data) {
try {
fos.write(data);
} catch (IOException ioe) {
Log.w(TAG, "failed writing debug data to file");
throw new RuntimeException(ioe);
}
}
public void stopEncoding() {
isEncoderRunning = false;
encoder.stop();
closeStream();
}
private void closeStream() {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
}
Hello I have created a multi-threaded HTTP Server in Java and cannot get content when using a web browser.
When I use a telnet client to read from the webserver it works fine, however with a browser such as chrome nothing shows up.
I have posted 3 pictures below showing that connection via telnet works fine and an additional picture that shows wireshark capture when calling webserver via chrome browswer using:
http://localhost:4568
Here is the code I have written posted below.
I changed the code to single threaded for easier debugging, the section in MainWebServer which is called "Debugging Section" is what the threading class contains.
MainWebServer:
package my.simple.webserver;
import java.io.*;
import java.net.*;
import java.util.*;
#SuppressWarnings("unused")
public class mainWebServer {
private static ServerSocket ser = null;
private static Socket cli = null;
private static String host = null;
private static int port;
/**
* #param args
*/
public static void main(String[] args) {
// Get parameters
if(args.length < 2)
{
setHost("localhost");
port = 4568;
}
else
{
setHost(args[0]);
port = Integer.parseInt(args[1]);
}
// initialize server
try {
// change to take in host
ser = new ServerSocket(port);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true)
{
try {
setCli(ser.accept());
//(new Thread(new HttpThread(cli))).start();
// Debugging section
DataInputStream sockIn = new DataInputStream(cli.getInputStream());
HttpRequest req = new HttpRequest(cli);
int cnt = 0;
byte[] buffer = new byte[1024];
while((cnt = sockIn.read(buffer)) >= 0)
{
System.out.println("We are here");
req.checkMethod(new String(buffer));
resetBuffer(buffer, 256);
}
// end debugging section
// run thread for client socket
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static String getHost() {
return host;
}
public static void setHost(String host) {
mainWebServer.host = host;
}
public static Socket getCli() {
return cli;
}
public static void setCli(Socket cli) {
mainWebServer.cli = cli;
}
// remove after debugging
public static void resetBuffer(byte[] buffer2, int i) {
// TODO Auto-generated method stub
for(int x=0; x < i; x++)
{
buffer2[x] = 0;
}
}
}
HttpRequest class:
package my.simple.webserver;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
public class HttpRequest {
private String method = null;
private String path = null;
private FileInputStream fis = null;
private OutputStream os = null;
private Socket mycli;
private static final String HTTP_OK_RESPONSE = "HTTP/1.1 200 OK\r\n";
private static final String HTTP_FNF_RESPONSE = "HTTP/1.1 404 NOT FOUND\r\n";
private static final String HTTP_DATE_RESPONSE = "Date: Mon, 04-Jan-99 13:14:15 GMT\r\n";
private static final String HTTP_SERVER_RESPONSE = "Server: Challenger\r\n";
private static final String HTTP_CONTENT_TYPE = "Content-Type: text/html\r\n";
private String HTTP_Content_Length = "Content-length: ";
public HttpRequest(Socket myCli) {
// TODO Auto-generated constructor stub
mycli = myCli;
}
void checkMethod(String buffer)
{
// get data and parse for method, location and protocol
// use switch statement based on method given
System.out.println("buffer = " + buffer);
StringTokenizer tok = new StringTokenizer(buffer);
try
{
method = tok.nextToken();
path = tok.nextToken();
}
catch(NoSuchElementException nse)
{
System.out.println(nse.getMessage());
method = "";
}
//System.out.println("method=" + method + " path=" + path);
switch(method)
{
case "GET":
//System.out.println("Get method called");
getMethod();
break;
case "HEAD":
System.out.println("Head method called");
break;
case "POST":
System.out.println("Post method called");
break;
case "PUT":
System.out.println("Put method called");
break;
case "DELETE":
System.out.println("Delete method called");
break;
case "TRACE":
System.out.println("Trace method called");
break;
case "OPTIONS":
System.out.println("Options method called");
break;
case "CONNECT":
System.out.println("Connect method called");
break;
default:
break;
}
}
private void getMethod()
{
String file;
File f = null;
// check if file exists
if(path.equalsIgnoreCase("/"))
{
//file = checkForIndex();
file = "index.html";
}
else
file = path;
System.out.println("file = " + file);
// open file
try {
file = "badfile.html";
f = new File(file);
os = mycli.getOutputStream();
//check if file exists
if(f.exists())
{
byte[] buffer = null;
buffer = HTTP_OK_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_DATE_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_SERVER_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_CONTENT_TYPE.getBytes();
os.write(buffer);
long fileLen = f.length();
HTTP_Content_Length = HTTP_Content_Length.concat(String.valueOf(fileLen));
HTTP_Content_Length = HTTP_Content_Length.concat("\r\n");
buffer = HTTP_Content_Length.getBytes();
os.write(buffer);
fis = new FileInputStream(file);
int nread, result;
// read file
while((nread = fis.available()) > 0)
{
buffer = new byte[nread];
result = fis.read(buffer);
if(result == -1) break;
os.write(buffer);
}
System.out.println("Left the loop!");
mycli.close();
}
else
{
// deal with 404
byte[] buffer = null;
buffer = HTTP_FNF_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_DATE_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_SERVER_RESPONSE.getBytes();
os.write(buffer);
buffer = HTTP_CONTENT_TYPE.getBytes();
os.write(buffer);
f = new File("fnf.html");
long fileLen = f.length();
HTTP_Content_Length = HTTP_Content_Length.concat(String.valueOf(fileLen));
HTTP_Content_Length = HTTP_Content_Length.concat("\r\n");
buffer = HTTP_Content_Length.getBytes();
os.write(buffer);
fis = new FileInputStream(f);
int nread, result;
// read file
while((nread = fis.available()) > 0)
{
buffer = new byte[nread];
result = fis.read(buffer);
if(result == -1) break;
os.write(buffer);
}
System.out.println("Left the loop!");
mycli.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// end thread
}
}
I am on a time crunch, I appreciate any help.
Thank you!
Because in HTTP protocol after sending the header, you need to send an empty line(\r\n) that indicates the end of header section in both request and response, for example
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 21
\r\n(EMPTY LINE) <- you forgot this one
<b>Hello World :D</b>
Add "\r\n" after you complete header.
Like:
HTTP_Content_Length = HTTP_Content_Length.concat("\r\n\r\n");
I'm trying to send and object over udp by first serializing it and then deserializing it on the other end. I thought this would be trivial since I have sent other data over udp before and serialized stuff to the files etc.
I have debugged thing some time now and I keep getting EOFException on the receiving end. Packets arrive properly but somehow deserialization fails. I'm not sure if the mistake is in sender or receiver. I suppose the problem might be about the receiver not knowing the size of the packet.
Here is my sender class:
package com.machinedata.sensordata;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.content.Context;
import android.util.Log;
import com.machinedata.io.DataSerializer;
import com.machinedata.io.ManagerUdpPacket;
/**
* This class sends udp-packets. It is used to send driver's information to the manager tablet.
* #author tuomas
*
*/
public class UdpSender
{
private final int MANAGER_PORT = 1234;
private String ip = "192.168.11.50"; //tablet's IP
private DatagramSocket sock = null;
private InetAddress host;
private String mType;
private DataSerializer dataser;
public UdpSender(Context context)
{
try
{
sock = new DatagramSocket();
host = InetAddress.getByName(ip); //tabletin ip
}
catch(Exception e)
{
System.err.println("Exception alustettaessa senderia" + e);
}
dataser = new DataSerializer(context);
}
/**
* With this function we can send packets about our machine to the manager to
* see in the fleet-view.
*/
public void sendToManager(ManagerUdpPacket managerUdp)
{
//serialize
Log.v("sendudp", "Send a packet: " + managerUdp.getDriver());
//serialize
byte[] data = dataser.serializeManagerPacket(managerUdp);
//send
try
{
DatagramPacket dp = new DatagramPacket(data , data.length , host , MANAGER_PORT);
sock.send(dp);
}
catch(IOException e)
{
System.err.println("IOException senderissa " + e);
}
}
public void close()
{
sock.close();
}
}
Here is the serialization function:
/**
* Serializes packet to be sent over udp to the manager tablet.
*/
public byte[] serializeManagerPacket(ManagerUdpPacket mp)
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(mp);
oos.close();
// get the byte array of the object
byte[] obj= baos.toByteArray();
baos.close();
return obj;
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
Packet receiver class
public class UdpReceiver {
private DatagramSocket clientSocket;
private byte[] receiveData;
private final int timeout = 1;
/**
* Create a receiver.
* #param port Port to receive from.
* #param signCount Number of signals in a packet
*/
public UdpReceiver(int port)
{
//receiveData = serializeManagerPacket(new ManagerUdpPacket("asd", new MachineData(1, 2, "asd", "modelName"), 1,2,3,4,5.0,null));
try{
clientSocket=new DatagramSocket(port);
clientSocket.setReceiveBufferSize(2048);
clientSocket.setSoTimeout(timeout);
}catch(SocketException e){
Log.e("ERR", "SocketException in UdpReceiver()");
}
}
public void close()
{
clientSocket.close();
}
/**
* Receive a data packet and split it into array.
* #param data Array to put data in, must be correct size
* #return True on successful read, false otherwise
*/
public ManagerUdpPacket receive()
{
//receive a packet
DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);
try{
clientSocket.receive(recvPacket);
}catch(IOException e){
Log.e("ERR", "IOException in UdpReceiver.receive");
return null;
}
ManagerUdpPacket obj = deserializeManagerPacket(receiveData);
if (obj != null)
Log.v("udpPacket", "UDP saatu: " + obj.getDriver());
return obj;
}
/**
* Deserialize the udp-packet back to readable data.
* #param data
* #return
*/
public ManagerUdpPacket deserializeManagerPacket(byte[] data)
{
try
{
ObjectInputStream iStream = new ObjectInputStream(new ByteArrayInputStream(data));
ManagerUdpPacket obj = (ManagerUdpPacket) iStream.readObject();
iStream.close();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
Thread which listens packets in receiving end:
dataStreamTask = new TimerTask()
{
public void run()
{
if (currentlyStreaming)
{
ManagerUdpPacket mp = udpReceiver.receive();
if(mp != null)
{
Log.v("log", "Paketti saatu! " + mp.getDriver());
}
//stop thread until next query
try {
synchronized(this){
this.wait(queryInterval);
}
} catch (InterruptedException e) {
Log.e("ERR", "InterruptedException in TimerTask.run");
}
}
}
And finally the class I'm sending over the UDP:
public class ManagerUdpPacket implements Serializable
{
private static final long serialVersionUID = 9169314425496496555L;
private Location gpsLocation;
private double totalFuelConsumption;
private long operationTime;
//workload distribution
private long idleTime = 0;
private long normalTime = 0;
private long fullTime = 0;
private int currentTaskId;
private String driverName;
String machineModelName = "";
String machineName = "";
int machineIconId = -1;
int machinePort = -1;
public ManagerUdpPacket(String driver, MachineData machine, int currentTaskId, long idleTime, long fullTime, long operationTime, double fuelConsumption, Location location)
{
driverName = driver;
this.currentTaskId = currentTaskId;
this.idleTime = idleTime;
this.fullTime = fullTime;
this.operationTime = operationTime;
this.totalFuelConsumption = fuelConsumption;
this.gpsLocation = location;
machineModelName = machine.getModelName();
machineName = machine.getName();
machineIconId = machine.getIconId();
machinePort = machine.getPort();
}
public String getDriver()
{
return driverName;
}
public int getCurrentTaskId()
{
return currentTaskId;
}
public long getIdleTime()
{
return idleTime;
}
public long getFullTime()
{
return fullTime;
}
public long getOperationTime()
{
return operationTime;
}
public double getTotalFuelConsumption()
{
return totalFuelConsumption;
}
public double getLocation()
{
return gpsLocation.getLatitude();
}
public String getMachineModelName()
{
return machineModelName;
}
public String getMachineName()
{
return machineName;
}
public int getMachineIconId()
{
return machineIconId;
}
public int getMachinePort()
{
return machinePort;
}
}
I tried to get the packet size from the size of the serialized packet or inserting arbitrary 2048 based on some examples on internet. Couldn't get it work though.
As far as i know the receive function returns the length of the bytes it received. But your buffer will be full:
Example:
int buffersize = 1024;
You send 8bytes over udp.
So your byte[] will be full with your 8 bytes but the rest of the 1024 will be 0.
save the size you get by the .receive() call and just save all values of your buffer to another byte[] and you should get your object.
For your example:
public ManagerUdpPacket receive()
{
int receivedBytes = 0;
//receive a packet
DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);
try{
receivedBytes = clientSocket.receive(recvPacket);
}catch(IOException e){
Log.e("ERR", "IOException in UdpReceiver.receive");
return null;
}
byte[] myObject = new byte[receivedBytes];
for(int i = 0; i < receivedBytes; i++)
{
myObject[i] = receiveData[i];
}
ManagerUdpPacket obj = deserializeManagerPacket(myObject);
if (obj != null)
Log.v("udpPacket", "UDP saatu: " + obj.getDriver());
return obj;
}
When receiving data on UDP, always use java.net.DatagramSocket.getReceiveBufferSize();. This is the actual size of the platform or SP_RCVBUF for the socket. Since UDP is a datagram based protocol unlike TCP, which is streaming protocol, receiving buffers become critical for data sanity. Usually, receiving and sending buffers are equal in size, but you are not bothered while sending when using DatagramSocket.send(DatagramPacket), alternately, you can also use DatagramSocket.setSendBufferSize(DatagramSocket.getSendBufferSize()) for using the SO_SNDBUF option for this socket. Keep in mind, in UDP, if you use a SO_SNDBUF size greater than platform's, the packet can be discarded.
public class SOAPClient implements Runnable {
/*
* endpoint url, the address where soap xml will be sent. It is hard coded
* now, later on to be made configurable
*/
private String endpointUrl = "";
/*
* This is for debugging purposes Message and response are written to the
* fileName
*/
static String fileName = "";
/*
* serverResponse This is a string representation of the response received
* from server
*/
private String serverResponse = null;
public String tempTestStringForDirectory = "";
/*
* A single file or a folder maybe provided
*/
private File fileOrFolder;
public SOAPClient(String endpointURL, File fileOrFolder) {
this.endpointUrl = endpointURL;
this.fileOrFolder = fileOrFolder;
serverResponse = null;
}
/*
* Creats a SOAPMessage out of a file that is passed
*
* #param fileAddress - Contents of this file are read and a SOAPMessage is
* created that will get sent to the server. This is a helper method. Is
* this step (method, conversion) necessary? set tempSoapText = XML String,
* currently getting from file, but it can be a simple string
*/
private SOAPMessage xmlStringToSOAPMessage(String fileAddress) {
System.out.println("xmlStringToSoap()");
// Picking up this string from file right now
// This can come from anywhere
String tempSoapText = readFileToString(fileAddress);
SOAPMessage soapMessage = null;
try {
// Create SoapMessage
MessageFactory msgFactory = MessageFactory.newInstance();
SOAPMessage message = msgFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
// Load the SOAP text into a stream source
byte[] buffer = tempSoapText.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
StreamSource source = new StreamSource(stream);
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Set contents of message
soapPart.setContent(source);
message.writeTo(out);
soapMessage = message;
} catch (SOAPException e) {
System.out.println("soapException xmlStringToSoap()");
System.out.println("SOAPException : " + e);
} catch (IOException e) {
System.out.println("IOException xmlStringToSoap()");
System.out.println("IOException : " + e);
}
return soapMessage;
}
/*
* Reads the file passed and creates a string. fileAddress - Contents of
* this file are read into a String
*/
private String readFileToString(String fileAddress) {
FileInputStream stream = null;
MappedByteBuffer bb = null;
String stringFromFile = "";
try {
stream = new FileInputStream(new File(fileAddress));
FileChannel fc = stream.getChannel();
bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
stringFromFile = Charset.defaultCharset().decode(bb).toString();
} catch (IOException e) {
System.out.println("readFileToString IOException");
e.printStackTrace();
} finally {
try {
stream.close();
} catch (IOException e) {
System.out.println("readFileToString IOException");
e.printStackTrace();
}
}
return stringFromFile;
}
/*
* soapXMLtoEndpoint sends the soapXMLFileLocation to the endpointURL
*/
public void soapXMLtoEndpoint(String endpointURL, String soapXMLFileLocation) throws SOAPException {
SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
SOAPMessage response = connection.call(xmlStringToSOAPMessage(soapXMLFileLocation), endpointURL);
connection.close();
SOAPBody responseBody = response.getSOAPBody();
SOAPBodyElement responseElement = (SOAPBodyElement) responseBody.getChildElements().next();
SOAPElement returnElement = (SOAPElement) responseElement.getChildElements().next();
if (responseBody.getFault() != null) {
System.out.println("fault != null");
System.out.println(returnElement.getValue() + " " + responseBody.getFault().getFaultString());
} else {
serverResponse = returnElement.getValue();
System.out.println(serverResponse);
System.out.println("\nfault == null, got the response properly.\n");
}
}
/*
* This is for debugging purposes. Writes string to a file.
*
* #param message Contents to be written to file
*
* #param fileName the name of the
*/
private static void toFile(String message, String fileName) {
try {
FileWriter fstream = new FileWriter(fileName);
System.out.println("printing to file: ".concat(fileName));
BufferedWriter out = new BufferedWriter(fstream);
out.write(message);
out.close();
} catch (Exception e) {
System.out.println("toFile() Exception");
System.err.println("Error: " + e.getMessage());
}
}
/*
* Using dom to parse the xml. Getting both orderID and the description.
*
* #param xmlToParse XML in String format to parse. Gets the orderID and
* description Is the error handling required? What if orderID or
* description isn't found in the xmlToParse? Use setters and getters?
*
* #param fileName only for debuggining, it can be safely removed any time.
*/
private void domParsing(String xmlToParse, String fileName) {
if (serverResponse == null) {
return;
} else {
try {
System.out.println("in domParsing()");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
System.out.println("serverResponse contains fault");
Document doc = dBuilder.parse(new InputSource(new StringReader(serverResponse)));
doc.getDocumentElement().normalize();
NodeList orderNodeList = doc.getElementsByTagName("Order");
if (orderNodeList.getLength() > 0) {
tempTestStringForDirectory = tempTestStringForDirectory + "\n Got order\n" + "\n" + fileName + "\n" + "got order\n";
for (int x = 0; x < orderNodeList.getLength(); x++) {
System.out.println(orderNodeList.item(x).getAttributes().getNamedItem("orderId").getNodeValue());
}
}
NodeList descriptionNodeList = doc.getElementsByTagName("Description");
if (descriptionNodeList.getLength() > 0) {
System.out.println("getting description");
String tempDescriptionString = descriptionNodeList.item(0).getTextContent();
System.out.println(tempDescriptionString);
tempTestStringForDirectory = tempTestStringForDirectory + "\n Got description" + "\n" + fileName + "\n" + tempDescriptionString + "\n";
}
} catch (Exception e) {
System.out.println("domParsing() Exception");
e.printStackTrace();
}
}
}
/*
* Reads a single file or a whole directory structure
*/
private void listFilesForFolder(final File fileOrFolder) {
String temp = "";
if (fileOrFolder.isDirectory()) {
for (final File fileEntry : fileOrFolder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
if (fileEntry.isFile()) {
temp = fileEntry.getName();
try {
soapXMLtoEndpoint(endpointUrl, fileOrFolder.getAbsolutePath() + "\\" + fileEntry.getName());
domParsing(serverResponse, fileEntry.getName());
} catch (SOAPException e) {
e.printStackTrace();
}
}
}
}
}
if (fileOrFolder.isFile()) {
temp = fileOrFolder.getName();
System.out.println("this is a file");
System.out.println(temp);
try {
soapXMLtoEndpoint(endpointUrl, fileOrFolder.getAbsolutePath());
} catch (SOAPException e) {
e.printStackTrace();
}
domParsing(serverResponse, temp);
}
}
#Override
public void run() {
listFilesForFolder(fileOrFolder);
toFile(tempTestStringForDirectory, "test.txt");
}
public static void main(String[] args) {
String tempURLString = ".../OrderingService";
String tempFileLocation = "C:/Workspace2/Test5/";
SOAPClient soapClient = new SOAPClient(tempURLString, new File(tempFileLocation));
Thread thread = new Thread(soapClient);
thread.start();
System.out.println("program ended");
}
}
I think n threads for n files would be bad? Wouldn't that crash the system, or give too many threads error?
I'm trying to make my program multi threaded. I don't know what I am missing. My program has a logic to know if a single file is passed or a directory is passed. One thread is fine if a single file is passed. But what should I do if a directory is passed? Do I need to create threads in my listFilesForFolder method? Are the threads always started from the main method, or can they be started from other methods? Also, this program is going to be used by other people, so it should be my job to handle the threads properly. All they should have to do is be using my program. So I feel that the thread logic should not belong in the main method but rather listFilesForFolder which is the starting point of my program. Thank you for your help.
From what I have seen, most download managers will try to download at most around 3 files at a time, plus or minus two. I suggest you do the same. Essentially, you could do something like this (Psuedo code)
//Set up a list of objects
fileList={"a","b","c"}
nextIndex=0;
Mutex mutex
//Start_X_threads
String next_object(void){
String nextFile;
try{
mutex.acquire();
try {
if (nextFileIndex<fileList.length)
{
nextFile=fileList(nextFileIndex);
nextFileIndex++;
}
else
nextFile="";
}
finally
{
mutex.release();
}
} catch(InterruptedException ie) {
nextFile="";
}
return nextFile;
}
Each thread :
String nextFile;
do
{
nextFile=nextObject();
//Get nextFile
} while (!nextFile.equals(""))
My app seems to work on most of the machines, but some just don't want to cooperate... The files on the server are fine, server itself isn't down or anything. The problem is that the app downloads all required files (up to 600KB) correctly except one (12MB). I can't figure out what is wrong. My guess is that there's something running in background that blocks the downloading thread of my app, or maybe the router blocks some of the packets? All I can see is that progress bar goes up to 4% (sometimes even up to 8!) and then stops with no errors or exceptions, while all the other downloads go up to 100% without problems. Any ideas?
Here's the class I use to download files (I've downloaded the whole 'download manager' script from http://www.java-tips.org/java-se-tips/javax.swing/how-to-create-a-download-manager-in-java.html):
class Download extends Observable implements Runnable {
private static final int MAX_BUFFER_SIZE = 1024;
public static final String STATUSES[] = { "Pobieranie", "Pauza", "OK", "Anulowany",
"Błąd" };
public static final int DOWNLOADING = 0;
public static final int PAUSED = 1;
public static final int COMPLETE = 2;
public static final int CANCELLED = 3;
public static final int ERROR = 4;
private URL url; // download URL
private int size; // size of download in bytes
private int downloaded; // number of bytes downloaded
private int status; // current status of download
// Constructor for Download.
public Download(URL url) {
this.url = url;
size = -1;
downloaded = 0;
status = DOWNLOADING;
System.err.println("==========Pobieram plik: " + url.toString());
// Begin the download.
download();
}
// Get this download's URL.
public String getUrl() {
//return url.toString();
return getFileName(url);
}
// Get this download's size.
public int getSize() {
return size;
}
// Get this download's progress.
public float getProgress() {
return ((float) downloaded / size) * 100;
}
public int getStatus() {
return status;
}
public void pause() {
status = PAUSED;
stateChanged();
}
public void resume() {
status = DOWNLOADING;
stateChanged();
download();
}
public void cancel() {
status = CANCELLED;
stateChanged();
}
private void error() {
status = ERROR;
stateChanged();
}
private void download() {
Thread thread = new Thread(this);
thread.start();
}
// Get file name portion of URL.
private String getFileName(URL url) {
String fileName = url.getFile();
return fileName.substring(fileName.lastIndexOf('/') + 1);
}
// Download file.
public void run() {
RandomAccessFile file = null;
InputStream stream = null;
try {
// Open connection to URL.
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Specify what portion of file to download.
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
// Connect to server.
connection.connect();
// Make sure response code is in the 200 range.
if (connection.getResponseCode() / 100 != 2) {
error();
}
// Check for valid content length.
int contentLength = connection.getContentLength();
if (contentLength < 1) {
error();
}
/*
* Set the size for this download if it hasn't been already set.
*/
if (size == -1) {
size = contentLength;
stateChanged();
}
File f = new File(Files.download_dir + Files.SEPARATOR + getFileName(url));
if (f.exists()) f.delete();
// Open file and seek to the end of it.
file = new RandomAccessFile(Files.download_dir + Files.SEPARATOR + getFileName(url), "rw");
file.seek(downloaded);
stream = connection.getInputStream();
while (status == DOWNLOADING) {
/*
* Size buffer according to how much of the file is left to download.
*/
byte buffer[];
if (size - downloaded > MAX_BUFFER_SIZE) {
buffer = new byte[MAX_BUFFER_SIZE];
} else {
buffer = new byte[size - downloaded];
}
// Read from server into buffer.
int read = stream.read(buffer);
if (read == -1)
break;
// Write buffer to file.
file.write(buffer, 0, read);
downloaded += read;
//System.out.println("Pobralem juz: " + String.valueOf(downloaded));
stateChanged();
}
/*
* Change status to complete if this point was reached because downloading
* has finished.
*/
if (status == DOWNLOADING) {
status = COMPLETE;
stateChanged();
}
} catch (Exception e) {
error();
} finally {
// Close file.
if (file != null) {
try {
file.close();
} catch (Exception e) {
}
}
// Close connection to server.
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
}
}
}
}
private void stateChanged() {
setChanged();
notifyObservers();
}
}
(If you need more code, just let me know and I'll upload everything somewhere.)