File Downloader with Java Commons IO stuck at 1MB/s+ - java

Lately I've been experimenting with Java and Commons IO trying to create a web file downloader, however I've encountered a problem, in fact it seems that the file download speed does not exceed 1MB/s while the same download from the browser runs smoothly at 3MB /s. Could you help me? I would be really grateful.
This is my downloader code:
package com.application.steammachine;
import com.github.junrar.Archive;
import com.github.junrar.Junrar;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import com.github.junrar.volume.FileVolumeManager;
import javafx.beans.property.SimpleStringProperty;
import javafx.concurrent.Task;
import org.apache.commons.io.IOUtils;
import org.ini4j.Wini;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
public class Downloader extends Task<Void> {
private URL url;
private String fileName;
private Game game;
public Downloader(URL url, String fileName, Game game) {
this.url = url;
this.fileName = fileName;
this.game = game;
}
public class ProgressListener implements ActionListener {
private double bytes = 0;
private double mbDownloaded = 0;
private double fileSize = 0;
private double lastMB = 0;
private long initialTime;
private double speed = 0;
private String downloadedText = "";
private String sizeText;
public ProgressListener(double fileSize){
this.fileSize = fileSize;
initialTime = System.nanoTime();
}
#Override
public void actionPerformed(ActionEvent e) {
bytes = ((DownloadCountingOutputStream) e.getSource()).getByteCount();
updateProgress(bytes, fileSize);
mbDownloaded = round(bytes/1e+6, 2);
if(fileSize >= 1073741824){ //>= 1GB
double temp = ((fileSize/1e+6)/1024);
sizeText = round(temp,2) + " GB";
}else {
double temp = (fileSize/1e+6);
sizeText = round(temp,2) + " MB";
}
if(mbDownloaded >= 1024){
downloadedText = String.valueOf(round(mbDownloaded/1024,2));
}else{
downloadedText = String.valueOf(mbDownloaded);
}
if((System.nanoTime() - initialTime) >= (Math.pow(10, 9))){
speed = round((mbDownloaded - lastMB), 3);
initialTime = System.nanoTime();
lastMB = mbDownloaded;
}
updateMessage(String.valueOf(speed)+"MB/s,"+String.valueOf(downloadedText + "/" + sizeText));
}
}
#Override
protected Void call() throws Exception {
URL dl = this.url;
File fl = null;
String x = null;
OutputStream os = null;
InputStream is = null;
try {
updateMessage("Searching files...,---/---");
fl = new File(Settings.getInstallPath() +"/"+ this.fileName);
os = new FileOutputStream(fl);
is = dl.openStream();
DownloadCountingOutputStream dcount = new DownloadCountingOutputStream(os);
double fileSize = Double.valueOf(dl.openConnection().getHeaderField("Content-Length"));
ProgressListener progressListener = new ProgressListener(fileSize);
dcount.setListener(progressListener);
IOUtils.copy(is, dcount, 512000 );
updateMessage("Concluding...,Almost finished");
} catch (Exception e) {
System.out.println(e);
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(is);
updateMessage(",");
this.cancel(true);
return null;
} finally {
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(is);
updateMessage(",");
updateProgress(0, 0);
this.cancel(true);
return null;
}
}
protected static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = new BigDecimal(Double.toString(value));
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
}
This is the DownloadCountingOutputStream class, which i use for keeping track of the download status:
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;
public class DownloadCountingOutputStream extends CountingOutputStream {
private ActionListener listener = null;
public DownloadCountingOutputStream(OutputStream out) {
super(out);
}
public void setListener(ActionListener listener) {
this.listener = listener;
}
#Override
protected void afterWrite(int n) throws IOException {
super.afterWrite(n);
if (listener != null) {
listener.actionPerformed(new ActionEvent(this, 0, null));
}
}
}
Thanks in adavance

First, there are a couple of simple things you could try to speed up the transfers:
Try using a larger transfer buffer size. Change the 8K buffer size to 64K or 512K.
Get rid of the DownloadCountingOutputStream and transfer directly to the FileOutputStream.
These should be simple to try ... and they may help a bit.
On a Linux system, it may also be worthwhile to replace Apache IOUtils.copy call with code that uses the kernel's zero-copy transfer support. See Efficient data transfer through zero copy for an explanation.
The example in the article is for uploading using transferTo, but downloading using transferFrom should be analogous. The article claims a 65% speedup for large file transfers compared with conventional Java I/O. But that is likely to depend on the characteristics of your network connection.

Related

Sending a file line by line, in 2 seconds intervals, using ticker behaviours

My question is: How to send a line of a file to another agent every 2 seconds using ticker behaviours?
More specifically, in the first iteration, the agent sends the first line. In the second, the agent sends the second line etc.
My code below:
package pack1;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.TickerBehaviour;
import jade.lang.acl.ACLMessage;
import jade.wrapper.ControllerException;
public class Agent2 extends Agent {
private static final long serialVersionUID = 1L;
int nombre_ligne = 0;
BufferedReader lecteurAvecBuffer = null;
#Override
protected void setup() {
FileInputStream fis;
try {
fis = new FileInputStream("/home/hduser/Bureau/word.txt");
#SuppressWarnings("resource")
LineNumberReader l = new LineNumberReader(new BufferedReader(
new InputStreamReader(fis)));
while ((l.readLine()) != null) {
nombre_ligne = l.getLineNumber();
}
lecteurAvecBuffer = new BufferedReader(new FileReader(
"/home/hduser/Bureau/esclave1/abc.txt"));
int a = 1;
while (a <= ((int) nombre_ligne) / 3) {
a++;
String word = lecteurAvecBuffer.readLine();
addBehaviour(new TickerBehaviour(this, 2000) {
private static final long serialVersionUID = 1L;
#Override
protected void onTick() {
ACLMessage message = new ACLMessage(ACLMessage.INFORM);
message.addReceiver(new AID("agent1", AID.ISLOCALNAME));
message.setContent(word);
send(message);
}
});
a++;
}
lecteurAvecBuffer.close();
} catch (FileNotFoundException exc) {
System.out.println("Erreur d'ouverture");
} catch (IOException e) {
e.printStackTrace();
}
}
protected void takeDown() {
System.out.println("Destruction de l'agent");
}
#Override
protected void afterMove() {
try {
System.out.println(" La Destination : "
+ this.getContainerController().getContainerName());
} catch (ControllerException e) {
e.printStackTrace();
}
}
}
You don't say nothing about what is the problem with your code. I guess you get at least a compiler message about:
message.setContent(word);
As you access a local variable from an inner class, you must declare the variable as final in the context, like:
final String word = lecteurAvecBuffer.readLine();

Fork/Join combine with FileChannel to copy file

Recently I am making an exercise using Java 7 FORK/JOIN framework and FileChannel to copy a file. Here is my code (Test.java):
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private ArrayList<FileProcessor> processors = new ArrayList<FileProcessor>();
public Test(){
String outputDir = "C:\\temp";
if (!Files.isDirectory(Paths.get(outputDir))) {
System.out.println("this is not a path");
} else {
try {
//start copying file
ForkJoinPool pool = new ForkJoinPool();
int numberOfThread = 2;
File file = new File("C:\\abc.cdm");
long length = file.length();
long lengthPerCopy = (long)(length/numberOfThread);
long position = 0L;
for (int i = 0; i < numberOfThread; i++) {
FileProcessor processor = null;
if (i == numberOfThread - 1) {
//the last thread
processor = new FileProcessor("abc.cdm", "C:\\abc.cdm", "C:\\temp", position, length - position);
} else {
processor = new FileProcessor("abc.cdm", "C:\\abc.cdm", "C:\\temp", position, lengthPerCopy);
position = position + lengthPerCopy + 1;
}
processors.add(processor);
pool.execute(processor);
}
do {
System.out.printf("******************************************\n");
System.out.printf("Main: Parallelism: %d\n", pool.getParallelism());
System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount());
System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount());
System.out.printf("Main: Steal Count: %d\n", pool.getStealCount());
System.out.printf("******************************************\n");
try
{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e)
{
e.printStackTrace();
}
} while (!isDone()); //when all the thread not been done
pool.shutdown();
System.out.println("copy done");
} catch (Exception ex) {
//out an error here...
}
}
}
private boolean isDone(){
boolean res = false;
for (int i = 0; i < processors.size(); i++) {
res = res || processors.get(i).isDone();
}
return res;
}
public static void main(String args[]) {
Test test = new Test();
}
class FileProcessor extends RecursiveTask<Integer>
{
private static final long serialVersionUID = 1L;
private long copyPosition;
private long copyCount;
FileChannel source = null;
FileChannel destination = null;
//Implement the constructor of the class to initialize its attributes
public FileProcessor(String fileName, String filePath, String outputPath, long position, long count) throws FileNotFoundException, IOException{
this.copyPosition = position;
this.copyCount = count;
this.source = new FileInputStream(new File(filePath)).getChannel().position(copyPosition);
this.destination = new FileOutputStream(new File(outputPath + "/" + fileName), true).getChannel().position(copyPosition);
}
#Override
protected Integer compute()
{
try {
this.copyFile();
} catch (IOException ex) {
Logger.getLogger(FileProcessor.class.getName()).log(Level.SEVERE, null, ex);
}
return new Integer(0);
}
private void copyFile() throws IOException {
try {
destination.transferFrom(source, copyPosition, copyCount);
}
finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
}
}
I run my code,
if number of threads is 1, the file is copied exactly, but when number of theads is 2, file "C:\abc.cdm" is 77KB (78335), but after copied, file "C:\temp\abc.cdm" is just (39KB).
Where did I get wrong, please tell me??
Update: My problem has been solves
The problem is in isDone method, it must be:
boolean res = true;
for (int i = 0; i < processors.size(); i++) {
res = res && processors.get(i).isDone();
}
return res;
Also edit the following lines of codes:
File file = new File(selectedFile[i].getPath());
long length = file.length();
new RandomAccessFile("C:\\temp\abc.cdm", "rw").setLength(length);
This is just a practice for FORK/JOIN usage!
Your isDone() method was indeed wrong and you corrected it in the original question. But there is another issue in the FileProcessor. You assume that setting the position on the destination past the end of the file will automatically grow the file when you transfer to it. This is not the case.
Your first segment will always write because the write position is 0 and the file's length cannot be less than zero. That was the 39K you saw, which is roughly half of the total file size. The second segment never got written.
In order to get your code to run, you can do the following at the start:
File file = new File("C:\\abc.cdm");
long length = file.length();
new RandomAccessFile("C:\\temp\\abc.cdm", "rw").setLength(length);`

How to make video from images using Java + x264 ; cross platform solution required

I have made a software which records my entire day into a video.
Example video : https://www.youtube.com/watch?v=ITZYMMcubdw (Note : >16hrs compressed in 2mins, video speed too high, might cause epilepsy :P )
The approach that I use right now is, Avisynth + x264 + Java.
This is very very efficient. The video for entire day is created in 3-4mins, and reduced to a size of 40-50MB. This is perfect, the only issue is that this solution is not cross platform.
Does anyone have a better idea?
I tried using java based x246 libraries but
They are slow as hell
The video output size is too big
The video quality is not satisfactory.
Some website suggest a command such as :
x264.exe --crf 18 --fps 24 --input-res 1920x1080 --input-csp rgb -o "T:\crf18.mkv" "T:\___BBB\big_buck_bunny_%05d.png"
There are 2 problems with this approach.
As far as I know, x264 does accept image sequence as input, ffmpeg does
The input images are not named in sequence such as image01.png , image02.png etc. They are named as timestamp_as_longinteger.png . So inorder to allow x264 to accept these images as input, I have to rename all of them ( i make a symbolic link for all images in a new folder ). This approach is again unsatisfactory, because I need more flexibility in selecting/unselecting files which would be converted to a video. Right now my approach is a hack.
The best solution is x264. But not sure how I can send it an image sequence from Java. That too, images which are not named in sequential fashion.
BTW The purpose of making video is going back in time, and finding out how time was spend/wasted.
The software is aware of what the user is doing. So using this I can find out (visually) how a class evolved with time. How much time I spend on a particular class/package/module/project/customer. The granuality right now is upto the class level, I wish to take it to the function level. The software is called jitendriya.
Here is a sample graph http://neembuu.com/now/tempimages/firefox.png
Here is 1 solution
How does one encode a series of images into H264 using the x264 C API?
But this is for C. If I have to do the same in java, and in a cross plaform fashion, I will have to resort to JNA/JNI. JNA might have a significant performance hit. JNI would be more work.
FFMpeg also looks like a nice alternative, but I am still not satisfied by any of these solutions looking at the pros and cons.
Solution Adapted.
package weeklyvideomaker;
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import neembuu.release1.util.StreamGobbler;
import org.shashaank.activitymonitor.ScreenCaptureHandler;
import org.shashaank.jitendriya.JitendriyaParams;
/**
*
* #author Shashank
*/
public class DirectVideoScreenHandler implements ScreenCaptureHandler {
private final JitendriyaParams jp;
private String extension="264";
private boolean lossless=false;
private String fps="24/1";
private Process p = null;
private Rectangle r1;
private Robot r;
private int currentDay;
private static final String[]weeks={"sun","mon","tue","wed","thu","fri","sat"};
public DirectVideoScreenHandler(JitendriyaParams jp) {
this.jp = jp;
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public boolean isLossless() {
return lossless;
}
public void setLossless(boolean lossless) {
this.lossless = lossless;
}
public String getFps() {
return fps;
}
public void setFps(String fps) {
this.fps = fps;
}
private static int getday(){
return Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1;
}
public void make()throws IOException,AWTException{
currentDay = getday();
File week = jp.getWeekFolder();
String destinationFile = week+"\\videos\\"+weeks[currentDay]+"_"+System.currentTimeMillis()+"_direct."+extension;
r = new Robot();
r1 = getScreenSize();
ProcessBuilder pb = makeProcess(destinationFile, 0, r1.width, r1.height);
p = pb.start();
StreamGobbler out = new StreamGobbler(p.getInputStream(), "out");
StreamGobbler err = new StreamGobbler(p.getErrorStream(), "err");
out.start();err.start();
}
private static Rectangle getScreenSize(){
return new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
}
private void screenShot(OutputStream os)throws IOException{
BufferedImage bi = r.createScreenCapture(r1);
int[]intRawData = ((java.awt.image.DataBufferInt)
bi.getRaster().getDataBuffer()).getData();
byte[]rawData = new byte[intRawData.length*3];
for (int i = 0; i < intRawData.length; i++) {
int rgb = intRawData[i];
rawData[ i*3 + 0 ] = (byte) (rgb >> 16);
rawData[ i*3 + 1 ] = (byte) (rgb >> 8);
rawData[ i*3 + 2 ] = (byte) (rgb);
}
os.write(rawData);
}
private ProcessBuilder makeProcess(String destinationFile, int numberOfFrames,
int width, int height){
LinkedList<String> commands = new LinkedList<>();
commands.add("\""+encoderPath()+"\"");
if(true){
commands.add("-");
if(lossless){
commands.add("--qp");
commands.add("0");
}
commands.add("--keyint");
commands.add("240");
commands.add("--sar");
commands.add("1:1");
commands.add("--output");
commands.add("\""+destinationFile+"\"");
if(numberOfFrames>0){
commands.add("--frames");
commands.add(String.valueOf(numberOfFrames));
}else{
commands.add("--stitchable");
}
commands.add("--fps");
commands.add(fps);
commands.add("--input-res");
commands.add(width+"x"+height);
commands.add("--input-csp");
commands.add("rgb");//i420
}
return new ProcessBuilder(commands);
}
private String encoderPath(){
return jp.getToolsPath()+File.separatorChar+"x264_64.exe";
}
#Override public void run() {
try {
if(p==null){
make();
}
if(currentDay!=getday()){// day changed
destroy();
return;
}
if(!r1.equals(getScreenSize())){// screensize changed
destroy();
return;
}
screenShot(p.getOutputStream());
} catch (Exception ex) {
Logger.getLogger(DirectVideoScreenHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void destroy()throws Exception{
p.getOutputStream().flush();
p.getOutputStream().close();
p.destroy();
p = null;
}
}
package weeklyvideomaker;
import org.shashaank.jitendriya.JitendriyaParams;
/**
*
* #author Shashank
*/
public class DirectVideoScreenHandlerTest {
public static void main(String[] args)throws Exception {
JitendriyaParams jp = new JitendriyaParams.Builder()
.setToolsPath("F:\\GeneralProjects\\JReminder\\development_environment\\tools")
.setOsDependentDataFolderPath("J:\\jt_data")
.build();
DirectVideoScreenHandler w = new DirectVideoScreenHandler(jp);
w.setExtension("264");
w.setFps("24/1");
w.setLossless(false);
w.make();
for (int i = 0; ; i++) {
w.run();
Thread.sleep(1000);
}
}
}

Is there a way to have FileChannels close automatically?

I am currently developing an application that requires random access to many (60k-100k) relatively large files.
Since opening and closing streams is a rather costly operation, I'd prefer to keep the FileChannels for the largest files open until they are no longer needed.
The problem is that since this kind of behaviour is not covered by Java 7's try-with statement, I'm required to close all the FileChannels manually.
But that is becoming increasingly too complicated since the same files could be accessed concurrently throughout the software.
I have implemented a ChannelPool class that can keep track of opened FileChannel instances for each registered Path. The ChannelPool can then be issued to close those channels whose Path is only weakly referenced by the pool itself in certain intervals.
I would prefer an event-listener approach, but I'd also rather not have to listen to the GC.
The FileChannelPool from Apache Commons doesn't address my problem, because channels still need to be closed manually.
Is there a more elegant solution to this problem? And if not, how can my implementation be improved?
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
public class ChannelPool {
private static final ChannelPool defaultInstance = new ChannelPool();
private final ConcurrentHashMap<String, ChannelRef> channels;
private final Timer timer;
private ChannelPool(){
channels = new ConcurrentHashMap<>();
timer = new Timer();
}
public static ChannelPool getDefault(){
return defaultInstance;
}
public void initCleanUp(){
// wait 2 seconds then repeat clean-up every 10 seconds.
timer.schedule(new CleanUpTask(this), 2000, 10000);
}
public void shutDown(){
// must be called manually.
timer.cancel();
closeAll();
}
public FileChannel getChannel(Path path){
ChannelRef cref = channels.get(path.toString());
System.out.println("getChannel called " + channels.size());
if (cref == null){
cref = ChannelRef.newInstance(path);
if (cref == null){
// failed to open channel
return null;
}
ChannelRef oldRef = channels.putIfAbsent(path.toString(), cref);
if (oldRef != null){
try{
// close new channel and let GC dispose of it
cref.channel().close();
System.out.println("redundant channel closed");
}
catch (IOException ex) {}
cref = oldRef;
}
}
return cref.channel();
}
private void remove(String str) {
ChannelRef ref = channels.remove(str);
if (ref != null){
try {
ref.channel().close();
System.out.println("old channel closed");
}
catch (IOException ex) {}
}
}
private void closeAll() {
for (Map.Entry<String, ChannelRef> e : channels.entrySet()){
remove(e.getKey());
}
}
private void maintain() {
// close channels for derefenced paths
for (Map.Entry<String, ChannelRef> e : channels.entrySet()){
ChannelRef ref = e.getValue();
if (ref != null){
Path p = ref.pathRef().get();
if (p == null){
// gc'd
remove(e.getKey());
}
}
}
}
private static class ChannelRef{
private FileChannel channel;
private WeakReference<Path> ref;
private ChannelRef(FileChannel channel, WeakReference<Path> ref) {
this.channel = channel;
this.ref = ref;
}
private static ChannelRef newInstance(Path path) {
FileChannel fc;
try {
fc = FileChannel.open(path, StandardOpenOption.READ);
}
catch (IOException ex) {
return null;
}
return new ChannelRef(fc, new WeakReference<>(path));
}
private FileChannel channel() {
return channel;
}
private WeakReference<Path> pathRef() {
return ref;
}
}
private static class CleanUpTask extends TimerTask {
private ChannelPool pool;
private CleanUpTask(ChannelPool pool){
super();
this.pool = pool;
}
#Override
public void run() {
pool.maintain();
pool.printState();
}
}
private void printState(){
System.out.println("Clean up performed. " + channels.size() + " channels remain. -- " + System.currentTimeMillis());
for (Map.Entry<String, ChannelRef> e : channels.entrySet()){
ChannelRef cref = e.getValue();
String out = "open: " + cref.channel().isOpen() + " - " + cref.channel().toString();
System.out.println(out);
}
}
}
EDIT:
Thanks to fge's answer I have now exactly what I needed. Thanks!
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
public class Channels {
private static final LoadingCache<Path, FileChannel> channelCache =
CacheBuilder.newBuilder()
.weakKeys()
.removalListener(
new RemovalListener<Path, FileChannel>(){
#Override
public void onRemoval(RemovalNotification<Path, FileChannel> removal) {
FileChannel fc = removal.getValue();
try {
fc.close();
}
catch (IOException ex) {}
}
}
)
.build(
new CacheLoader<Path, FileChannel>() {
#Override
public FileChannel load(Path path) throws IOException {
return FileChannel.open(path, StandardOpenOption.READ);
}
}
);
public static FileChannel get(Path path){
try {
return channelCache.get(path);
}
catch (ExecutionException ex){}
return null;
}
}
Have a look here:
http://code.google.com/p/guava-libraries/wiki/CachesExplained
You can use a LoadingCache with a removal listener which would close the channel for you when it expires, and you can specify expiry after access or write.

Java Server Non Blocking Query

I am using the following code to read some data from Android client. All is going fine. But now i am asked to make this server code non blocking. Is there any suggestions for this ? I was trying to use threads but dont know how ? I am beginner in Java :)
Thanks
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.Date;
import javax.imageio.ImageIO;
public class Server {
//Server Constructor
public Server()
{}
//Variables Initialization
private static ServerSocket server;
byte[] imagetemp;
private static Socket socket1;
private static boolean newImage;
private static Sdfdata data;
private static boolean cond;
public static int port;
private static int number = 0;
//Image Availability return method
public boolean imageAvailable()
{
return newImage;
}
public boolean clientchk()
{
return socket1.isClosed();
}
//Image Flag set by Vis group when image read.
public void setImageFlag(boolean set)
{
newImage = set;
}
// Send the data to the Vis Group
public Sdfdata getData()
{
return data;
}
//Starts the Server
public static boolean start(int port1)
{
try {
port=port1;
server = new ServerSocket(port1);
System.out.println("Waiting for Client to Connect");
//New thread here
socket1=server.accept();
} catch (IOException e) {
System.out.println("Cannot Connect");
e.printStackTrace();
return false;
}
return true;
}
//Stops the Server
public boolean stop()
{
try {
socket1.close();
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// Starts the server
start(4444);
// DataInput Stream for reading the data
DataInputStream in = null;
try {
in = new DataInputStream(socket1.getInputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
cond=true;
do {
try
{
//Read Image Data
int length = in.readInt();
//Create an ByteArray of length read from Client for Image transfer
Sdfdata data = new Sdfdata(length);
//for (int i=0; i<length; i++)
//{ data.image[i] = in.readbyte(); }
if (length > 0) {
in.readFully(data.image);
}
//Read Orientation
data.orientation[0] = in.readFloat(); //Orientation x
data.orientation[1] = in.readFloat(); //Orientation y
data.orientation[2] = in.readFloat(); //Orientation z
//Read GPS
data.longitude = in.readDouble();
data.latitude = in.readDouble();
data.altitude = in.readDouble();
//Display orientation and GPS data
System.out.println(data.orientation[0] + " " + data.orientation[1] + " " + data.orientation[2]);
System.out.println(data.longitude + " " + data.latitude + " " + data.altitude);
String fileName = "IMG_" + Integer.toString(++number) + ".JPG";
System.out.println("FileName: " + fileName);
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(data.image);
fos.close();
/*InputStream ins = new ByteArrayInputStream(data.image);
BufferedImage image = ImageIO.read(ins);
ImageIO.write(image, "JPG", new File (fileName));
*/
//set image flag
newImage = true;
} catch (Exception e) {
//System.out.println("EOF Or ? " + e);
cond =false;
socket1.close();
server.close();
start(port);
}
}while (cond);
}
}
Your code starts a server, waits for a connection, reads some data from the first connected client, and then exits after writing this data to a file.
Being asked to make your server "non-blocking" could mean that you are being asked to change it to use asynchronous IO (probably unlikely), or it could mean that you're being asked to handle more than one client at a time - because currently you can only serve one client and then your program exits.
This question is hard to answer because your current code is very far away from where you need it to be and it seems like some reading up on networking, sockets, and Java programming in general would be a good way to start.
I'd recommend Netty for doing anything network-related in Java and their samples and documentation are good and easy to follow. Good luck!

Categories