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");
Related
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.
I'm transferring Byte arrays of different kinds of files(.png, .txt, etc..) My socket starts sending the data and client starts receiving it. For some reason .pngs doesen't look same as they do on the server side. (Sometimes it says image is unreadable, sometimes only some parts of image are shown.. etc)? I'm wondering how could I make it so that the sent data would actually be the same as the sent data? Any suggestions what I'm doing wrong? (Note! If .png file has alpha channel, image seems always to be completely unreadable.)
Client side of the data transfer:
try
{
sInput = new ObjectInputStream(socket.getInputStream());
Input = socket.getInputStream();
}
catch (IOException eIO) {
System.out.println("Exception creating new Input/output Streams: " + eIO);
return false;
}
.
.
.
LoadCache[] filedata = (LoadCache[]) sInput.readObject(); //This contains the path and size of file
while(number < filedata.length){
byte[] mybytearray = new byte[(int) LoadCache.getSize(filedata[number])];
String result = Reader.UpdateCache(LoadCache.getPath(filedata[number]));
number++;
if(result != "skip" && result != "Stop"){
BufferedOutputStream Bos = new BufferedOutputStream(new FileOutputStream(result));
int BytesRead = Input.read(mybytearray, 0, mybytearray.length);
Bos.write(mybytearray, 0, BytesRead);
Bos.close();
}
}
Server side of the data transfer:
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
OutputStream Output;
BufferedInputStream buffIn;
.
.
.
try{
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
Output = socket.getOutputStream();
} catch (Exception e){
System.out.println("Couldn't create Input/Output streams");
}
.
.
.
File[] Data = Reader.getFiles(Action.getString(Incomingdata.getAction(datain)));
LoadCache LoadedCache[] = new LoadCache[Data.length];
for(int i = 0; i<Data.length; i++){
Path filePath = Paths.get(Data[i].getPath());
Path relativePath = base.relativize(filePath); //= filePath - base (so to say)
LoadedCache[i] = new LoadCache(relativePath.toString(), Data[i].length());
}
System.out.println(LoadedCache.length);
try {
sOutput.writeObject(LoadedCache);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
for(File file : Data){
try {
if(file.isFile()){
byte[] bytearray = new byte[(int) file.length()];
buffIn = new BufferedInputStream(new FileInputStream(file));
buffIn.read(bytearray, 0, bytearray.length);
Output.write(bytearray, 0, bytearray.length);
Output.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
buffIn.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Also! Now (I'm not quite sure anymore if I got this earlier) Client gives me java.util.zip.ZipException: incorrect header check -Exception (And none of the files is zipped)
Something Runnable:
Public class Client {
private ObjectInputStream sInput; // to read from the socket
private static ObjectOutputStream sOutput; // to write on the socket
private static Socket socket;
public static Client client;
public static Player player;
public static boolean loadingFiles;
String server;
int port;
boolean connected;
Client(String server, int port) {
this.server = server;
this.port = port;
this.connected = true;
}
public static boolean isConnected(Client client){
return client.connected;
}
private void disconnect() {
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
}
public boolean start() {
// try to connect to the server
try {
socket = new Socket(server, port);
}
// if it failed we catch the exception
catch(Exception ec) {
System.out.println("Error connecting to server: " + ec);
return false;
}
System.out.println("Connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
/* Creating Data Streams */
try
{
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
}
catch (IOException eIO) {
System.out.println("Exception creating streams: " + eIO);
return false;
}
// creates the Thread to listen from the server
new ListenFromServer().start();
String Cache;
if(Reader.ReadCache(Frame.drive +"//FM_Cache/version") == "WeHadToMakeNewFile"){ //If we don't have that file. We create it, but now it's empty.
Cache = "New";
}
else{ //If we do have cache and it has "version" we send our version to server.
Cache = Reader.ReadCache(Frame.drive +"FM_Cache/version");
}
send(new Incomingdata("", "", new Action(0, Cache, 0, 0)));
// success we inform the caller that it worked
return true;
}
public static void Connect() {
// default values
int portNumber = 16304;
String serverAddress = "0.0.0.0"; //I'm using my own ip here..
// create the Client object
client = new Client(serverAddress, portNumber);
// test if we can start the connection to the Server
if(client.start()){
client.connected = true;
}
}
public static void Disconnect(Client client) {
client.connected = false;
client.disconnect();
}
class ListenFromServer extends Thread {
public void run() {
loadingFiles = true;
while(true) {
try {
int number = 0;
LoadCache[] filedata = (LoadCache[]) sInput.readObject();
while(number < filedata.length){
byte[] mybytearray = new byte[(int) LoadCache.getSize(filedata[number])];
String result = Reader.UpdateCache(LoadCache.getPath(filedata[number]));
number++;
if(result != "skip" && result != "Stop"){
BufferedOutputStream Bos = new BufferedOutputStream(new FileOutputStream(result));
int BytesRead = sInput.read(mybytearray, 0, mybytearray.length);
Bos.write(mybytearray, 0, BytesRead);
Bos.close();
}
}
System.out.println("Cache has been patched succesfully!");
Client.loadingFiles = false;
}catch(EOFException e){
System.out.println("Problem reading the data streams! " +e);
break;
}
catch(IOException e) {
System.out.println(e);
break;
}
catch(ClassNotFoundException e2) {
}
}
}
}
public static void send(Incomingdata incomingdata) {
try {
sOutput.writeObject(incomingdata);
}
catch(IOException e) {
System.out.println("Exception writing to server: " + e);
}
}
}
Incomingdata:
package com.connection;
import com.connection.Action;
public class Incomingdata implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = -1309997274550304156L;
private String Username, Password;
private Action action;
public Incomingdata(String Username, String Password, Action action){
this.Username = Username;
this.action = action;
this.Password = Password;
}
public static String getUsername(Incomingdata Incomingdata){
return Incomingdata.Username;
}
public static String getPassword(Incomingdata Incomingdata){
return Incomingdata.Password;
}
public static Action getAction(Incomingdata Incomingdata){
return Incomingdata.action;
}
}
LoadingCache:
package com.connection;
import java.io.Serializable;
public class LoadCache implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7267682639705707967L;
String path;
long size;
public LoadCache(String path, long size){
this.path = path;
this.size = size;
}
public static long getSize(LoadCache cache) {
return cache.size;
}
public static String getPath(LoadCache filedata) {
return filedata.path;
}
}
Action.java:
package com.connection;
import com.connection.Action;
public class Action implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 4389420849399916526L;
int type, x, y;
String string;
public Action(int type, String string, int x, int y){
this.type = type;
this.string = string;
this.x = x;
this.y = y;
}
public static int getType(Action action) {
return action.type;
}
public static String getString(Action action) {
return action.string;
}
public static int getX(Action action) {
return action.x;
}
public static int getY(Action action) {
return action.y;
}
}
And Reader for Client. This should be the last class you need to run the client.
package com.game.loader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import com.connection.Client;
import com.game.Frame;
import com.game.menu.GameMenu;
public class Reader {
public static String ReadCache(String string) {
int CurrentLine = 0;
String returnement = "";
try {
BufferedReader Reader = new BufferedReader(new FileReader(new File(string)));
for(String line = Reader.readLine(); line != null; line = Reader.readLine()){
if(CurrentLine == 0){
returnement = line;
}
CurrentLine++;
}
} catch (FileNotFoundException e) {
new File(Frame.drive +"//FM_Cache").mkdirs();
return "WeHadToMakeNewFile";
} catch (IOException e) {
e.printStackTrace();
}
return returnement;
}
public static String UpdateCache(String path) {
String[] pieces = path.split("/");
String returnement = "skip";
System.out.println(Frame.drive + "//FM_Cache/" + path);
if(new File(Frame.drive +"//FM_Cache/" +path).exists()){
returnement = (Frame.drive +"//FM_Cache/" +path);
}
else{ //If file doesen't exit we make one and parent folders.
File file = new File(Frame.drive +"//FM_Cache/" +path);
file.getParentFile().mkdirs();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
returnement = (Frame.drive +"//FM_Cache/" +path);
}
return returnement;
}
}
Runnable server:
package com.server;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.ServerSocket;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import org.apache.commons.io.IOUtils;
import com.connection.Action;
import com.connection.Incomingdata;
import com.connection.LoadCache;
import com.game.loader.Reader;
import com.game.player.Player;
public class Server {
//Every connection got their own unique id
private static int uniqueId;
//List all the clients
private static ArrayList<ClientThread> al;
private static boolean running = false;
#SuppressWarnings("unused")
private SimpleDateFormat sdf;
final Path base = Paths.get("Data", "Cache");
public Server(int port) {
sdf = new SimpleDateFormat("HH:mm:ss");
al = new ArrayList<ClientThread>();
}
public void start() {
running = true;
try {
//Server socket
ServerSocket serverSocket = new ServerSocket(Screen.portnumber);
System.out.println("Server is running and waiting for Clients to connect.");
while(running){
Socket socket = serverSocket.accept();
if(!running){ //this will make server running stop.
System.out.println("Closing the server..");
break;
}
ClientThread t = new ClientThread(socket);
al.add(t); //saving new client to our arraylist.
t.run();
}
try{
serverSocket.close();
for(int i = 0; i< al.size(); i++){//We forget about all the clients.
//Maybe also save all the data here?
ClientThread tc = al.get(i);
try{
tc.sInput.close();
tc.sOutput.close();
tc.socket.close();
}
catch(IOException ioE){}
}
} catch(Exception e){e.printStackTrace();}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void close() {
running = false;
try {
new Socket("localhost", Screen.portnumber);
} catch (Exception e) { System.out.println("Can't disconnect.."); }
}
synchronized void remove(int id) {
// scan the array list until we find the Id
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
// found it
if(ct.id == id) {
al.remove(i);
return;
}
}
}
public static boolean isRunning(){
return running;
}
class ClientThread extends Thread {
//The socket where to listen/talk
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
BufferedInputStream buffIn;
//my unique id (easier for deconnection)
int id;
//Objects that we will be receiving
Incomingdata datain;
//the date we connect
String date;
Player player;
boolean Connected = false;
//Constructor
ClientThread(Socket socket){
id = uniqueId++;
this.socket = socket;
try{
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
} catch (Exception e){
System.out.println("Couldn't create Input/Output streams");
}
date = new Date().toString();
}
// what will run forever
public void run() {
// to loop until LOGOUT
Connected = true;
while(Connected) {
try {
datain = (Incomingdata) sInput.readObject();
}
catch (IOException e) {
System.out.println("Exception reading Streams: " + e);
break;
}
catch(ClassNotFoundException e2) {
break;
}
if(!Incomingdata.getUsername(datain).isEmpty()){
switch(Action.getType(Incomingdata.getAction(datain))) { //CHANGE!!
case 0://Log in/off
System.out.println(Incomingdata.getUsername(datain) +", " +Incomingdata.getPassword(datain) + " trying to connect.");
if(Player.getPassword(Reader.ReadPlayerData("Data/Players/" +Incomingdata.getUsername(datain) +".txt")) == Incomingdata.getPassword(datain)){
player = Reader.ReadPlayerData("Data/Players/" +Incomingdata.getUsername(datain) +".txt");
System.out.println(Player.getUsername(player) +"Just connected!");
Player.isOnline(player);
}
break;
case 1://Talk
System.out.println(Incomingdata.getUsername(datain) + ": " +Action.getString(Incomingdata.getAction(datain)));
break;
case 2://Move
break;
}
}
else if(Action.getString(Incomingdata.getAction(datain)) != null){
File[] Data = Reader.getFiles(Action.getString(Incomingdata.getAction(datain)));
LoadCache LoadedCache[] = new LoadCache[Data.length];
for(int i = 0; i<Data.length; i++){
Path filePath = Paths.get(Data[i].getPath());
Path relativePath = base.relativize(filePath); //= filePath - base (so to say)
LoadedCache[i] = new LoadCache(relativePath.toString(), Data[i].length());
}
System.out.println(LoadedCache.length);
try {
sOutput.writeObject(LoadedCache);
sOutput.flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
for(File file : Data){
try {
if(file.isFile()){
byte[] bytearray = new byte[(int) file.length()];
buffIn = new BufferedInputStream(new FileInputStream(file));
buffIn.read(bytearray, 0, bytearray.length);
sOutput.write(bytearray, 0, bytearray.length);
sOutput.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
buffIn.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Cache updated!");
}
}
// remove myself from the arrayList containing the list of the
System.out.println(Player.getUsername(player) +", " +Player.getPassword(player) +" disconnected.");
remove(id);
close();
}
// try to close everything
private void close() {
// try to close the connection
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {}
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {};
try {
if(socket != null) socket.close();
}
catch (Exception e) {}
}
}
}
Reader.java for server:
package com.game.loader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import org.apache.commons.io.filefilter.FileFileFilter;
import com.game.player.CharacterClass;
import com.game.player.Equipment;
import com.game.player.Friends;
import com.game.player.Inventory;
import com.game.player.Orbs;
import com.game.player.Player;
import com.game.player.Quest;
import com.game.world.Tile;
public class Reader {
public static Player temporary;
static int stage = 0;
private static int count = 0;
private static int totalfolders = 0;
private static File[] files = new File[NumberOfFiles("Data/Cache/")];
public static Player ReadPlayerData(String string) {
Player player = null;
int CurrentLine = 0;
String[] All = new String[100]; //This may need to be extended.
try {
BufferedReader Reader = new BufferedReader(new FileReader(new File(string)));
for(String line = Reader.readLine(); line != null; line = Reader.readLine()){
All[CurrentLine] = line;
CurrentLine++;
}
} catch (FileNotFoundException e) {
System.out.println("Someone is trying to log in using wrong username.");
} catch (IOException e) {
e.printStackTrace();
}
player = new Player(string, All[0], new Tile(Integer.parseInt(All[1].split(", ")[0]), Integer.parseInt(All[1].split(", ")[1]), Integer.parseInt(All[1].split(", ")[2])),
Integer.parseInt(All[2]), Integer.parseInt(All[3]), Integer.parseInt(All[4]), new CharacterClass(All[5]), new Orbs(All[6].split(", ")), null, new Inventory(All[8].split(", ")),
null, new Equipment(All[10].split(", ")), new Friends(All[11].split(", ")), /* All[12] = guild,*/ Integer.parseInt(All[13]), true, false, null, null, Integer.parseInt(All[18]), /*All[19] = StartDate,*/ All[20]);
temporary = player;
return player;
}
public static boolean CacheReader(String string) {
File[] all = new File(string).listFiles(); //We list all the files from path
int folders = 0;
for(int i = 0; i < all.length; i++){
if(!all[i].isDirectory()) { //folders are not added to this list. :)
System.out.println("((i = " +i +") - (folders = " +folders +")) + (stage = " +stage +") = " +(i-folders+stage));
files[i-folders+stage] = all[i];
}
else{
folders++;
totalfolders++;
}
}
stage += all.length-folders; //We add number of files from every directory to stage.
for(int i = 0; i < all.length; i++){ //Then we seek for all the sub-directories
if(all[i].isDirectory()){
CacheReader(all[i].getPath()); //and add all the files from sub-directories to out file list
}
}
return true;
}
public static File[] getFiles(String string) {
if(string == "New"){
}
return files;
}
public static int NumberOfFiles(String string) {
File[] filenames;
filenames = new File(string).listFiles();
count += filenames.length; //We add all the files from the File(string) Note!: Also folders
for(int i = 0; i < filenames.length; i++){
if(filenames[i].isDirectory()){
NumberOfFiles(filenames[i].getPath());
count--;
}
}
return count;
}
}
Umm.. I think you can remove everything related to player, since it's not part of cache update system.. also there are some unused imports in those, I didn't remove all of them. Most of TextArea.Addline();s I changed to System.out.println(); if you find one, you can aswell replace it with System.out.println(); or if you don't need it you can remove it. What ever.. I just would like to find an answer..
try to write the byte array to the ObjectOutputStream as an object:
final byte[] bytearray = new byte[(int) file.length()];
buffIn = new BufferedInputStream(new FileInputStream(file));
buffIn.read(bytearray, 0, bytearray.length);
sOutput.writeObject(bytearray);
And to read it as an Object:
final BufferedOutputStream Bos =
new BufferedOutputStream(new FileOutputStream(result));
byte[] mybytearray = (byte[])sInput.readObject();
Bos.write(mybytearray, 0, BytesRead);
I hope it helps.
Don't use multiple streams to read from the same socket, or write to it either. Use the object streams for everything.
Your copy loops are incorrect, because they aren't loops. You can't assume that read() fills the buffer. The canonical stream copy loop in Java is like so:
int count;
byte[] buffer = new byte[8192]; // or more, code works with any size >= 1
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
I have written a java code to transfer files from one server to another using the concept of socket programming. I got the codes from another java forum that meet my requirements. The program is said to transfer large sized files (like .mkv , .mprg movies) from one machine to another and can be used to transfer files of all formats. But after running the codes I found that the program is not able to transfer large sized files such as movies and even pdf of sizes 80mb or 111mb. The program has used bytebuffer but still error occurs. The codes are as follows (I got them from this site http://www.coderpanda.com/java-socket-programming-transferring-large-sized-files-through-socket/)
ClientMain.java
import java.io.IOException;
import java.net.Socket;
public class ClientMain
{
private DirectoryTxr transmitter = null;
Socket clientSocket = null;
private boolean connectedStatus = false;
private String ipAddress;
String srcPath = null;
String dstPath = "";
public ClientMain()
{
}
public void setIpAddress(String ip)
{
this.ipAddress = ip;
}
public void setSrcPath(String path)
{
this.srcPath = path;
}
public void setDstPath(String path)
{
this.dstPath = path;
}
private void createConnection()
{
Runnable connectRunnable = new Runnable()
{
public void run()
{
while (!connectedStatus)
{
try
{
clientSocket = new Socket(ipAddress, 22);
connectedStatus = true;
transmitter = new DirectoryTxr(clientSocket, srcPath, dstPath);
}
catch (IOException io)
{
io.printStackTrace();
}
}
}
};
Thread connectionThread = new Thread(connectRunnable);
connectionThread.start();
}
public static void main(String[] args)
{
ClientMain main = new ClientMain();
main.setIpAddress("localHost");
main.setSrcPath("C:/Transfer/");
main.setDstPath("C:/Receive");
main.createConnection();
}
}
DirectoryTxr.java
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class DirectoryTxr
{
Socket clientSocket = null;
String srcDir = null;
String dstDir = null;
byte[] readBuffer = new byte[1024];
private InputStream inStream = null;
private OutputStream outStream = null;
int state = 0;
final int permissionReqState = 1;
final int initialState = 0;
final int dirHeaderSendState = 2;
final int fileHeaderSendState = 3;
final int fileSendState = 4;
final int fileFinishedState = 5;
private boolean isLive = false;
private int numFiles = 0;
private int filePointer = 0;
String request = "May I send?";
String respServer = "Yes,You can";
String dirResponse = "Directory created...Please send files";
String fileHeaderRecvd = "File header received ...Send File";
String fileReceived = "File Received";
String dirFailedResponse = "Failed";
File[] opFileList = null;
public DirectoryTxr(Socket clientSocket, String srcDir, String dstDir)
{
try
{
this.clientSocket = clientSocket;
inStream = clientSocket.getInputStream();
outStream = clientSocket.getOutputStream();
isLive = true;
this.srcDir = srcDir;
this.dstDir = dstDir;
state = initialState;
readResponse();
sendMessage(request);
state = permissionReqState;
}
catch (IOException io)
{
io.printStackTrace();
}
}
private void sendMessage(String message)
{
try
{
sendBytes(request.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
private void readResponse()
{
Runnable readRunnable = new Runnable()
{
public void run()
{
while (isLive)
{
try
{
int num = inStream.read(readBuffer);
if (num > 0)
{
byte[] tempArray = new byte[num];
System.arraycopy(readBuffer, 0, tempArray, 0, num);
processBytes(tempArray);
}
}
catch (SocketException se)
{
System.exit(0);
}
catch (IOException io)
{
io.printStackTrace();
isLive = false;
}
}
}
};
Thread readThread = new Thread(readRunnable);
readThread.start();
}
private void sendDirectoryHeader()
{
File file = new File(srcDir);
if (file.isDirectory())
{
try
{
String[] childFiles = file.list();
numFiles = childFiles.length;
String dirHeader = "$" + dstDir + "#" + numFiles + "&";
sendBytes(dirHeader.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException en)
{
en.printStackTrace();
}
}
else
{
System.out.println(srcDir + " is not a valid directory");
}
}
private void sendFile(String dirName)
{
File file = new File(dirName);
if (!file.isDirectory())
{
try
{
int len = (int) file.length();
int buffSize = len / 8;
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel channel = raf.getChannel();
int numRead = 0;
while (numRead >= 0)
{
ByteBuffer buf = ByteBuffer.allocate(1024 * 100000);
numRead = channel.read(buf);
if (numRead > 0)
{
byte[] array = new byte[numRead];
System.arraycopy(buf.array(), 0, array, 0, numRead);
sendBytes(array);
}
}
System.out.println("Finished");
}
catch (IOException io)
{
io.printStackTrace();
}
}
}
private void sendHeader(String fileName)
{
try
{
File file = new File(fileName);
if (file.isDirectory())
return;
String header = "&" + fileName + "#" + file.length() + "*";
sendHeader(header);
sendBytes(header.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
private void sendBytes(byte[] dataBytes)
{
synchronized (clientSocket)
{
if (outStream != null)
{
try
{
outStream.write(dataBytes);
outStream.flush();
}
catch (IOException io)
{
io.printStackTrace();
}
}
}
}
private void processBytes(byte[] data)
{
try
{
String parsedMessage = new String(data, "UTF-8");
System.out.println(parsedMessage);
setResponse(parsedMessage);
}
catch (UnsupportedEncodingException u)
{
u.printStackTrace();
}
}
private void setResponse(String message)
{
if (message.trim().equalsIgnoreCase(respServer) && state == permissionReqState)
{
state = dirHeaderSendState;
sendDirectoryHeader();
}
else if (message.trim().equalsIgnoreCase(dirResponse) && state == dirHeaderSendState)
{
state = fileHeaderSendState;
if (LocateDirectory())
{
createAndSendHeader();
}
else
{
System.out.println("Vacant or invalid directory");
}
}
else if (message.trim().equalsIgnoreCase(fileHeaderRecvd) && state == fileHeaderSendState)
{
state = fileSendState;
sendFile(opFileList[filePointer].toString());
state = fileFinishedState;
filePointer++;
}
else if (message.trim().equalsIgnoreCase(fileReceived) && state == fileFinishedState)
{
if (filePointer < numFiles)
{
createAndSendHeader();
}
System.out.println("Successfully sent");
}
else if (message.trim().equalsIgnoreCase(dirFailedResponse))
{
System.out.println("Going to exit....Error ");
}
else if (message.trim().equalsIgnoreCase("Thanks"))
{
System.out.println("All files were copied");
}
}
private void closeSocket()
{
try
{
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private boolean LocateDirectory()
{
boolean status = false;
File file = new File(srcDir);
if (file.isDirectory())
{
opFileList = file.listFiles();
numFiles = opFileList.length;
if (numFiles <= 0)
{
System.out.println("No files found");
}
else
{
status = true;
}
}
return status;
}
private void createAndSendHeader()
{
File opFile = opFileList[filePointer];
String header = "&" + opFile.getName() + "#" + opFile.length() + "*";
try
{
state = fileHeaderSendState;
sendBytes(header.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e)
{
}
}
private void sendListFiles()
{
createAndSendHeader();
}
}
ServerMain.java
public class ServerMain {
public ServerMain() {
}
public static void main(String[] args) {
DirectoryRcr dirRcr = new DirectoryRcr();
}
}
DirectoryRcr.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class DirectoryRcr
{
String request = "May I send?";
String respServer = "Yes,You can";
String dirResponse = "Directory created...Please send files";
String dirFailedResponse = "Failed";
String fileHeaderRecvd = "File header received ...Send File";
String fileReceived = "File Received";
Socket socket = null;
OutputStream ioStream = null;
InputStream inStream = null;
boolean isLive = false;
int state = 0;
final int initialState = 0;
final int dirHeaderWait = 1;
final int dirWaitState = 2;
final int fileHeaderWaitState = 3;
final int fileContentWaitState = 4;
final int fileReceiveState = 5;
final int fileReceivedState = 6;
final int finalState = 7;
byte[] readBuffer = new byte[1024 * 100000];
long fileSize = 0;
String dir = "";
FileOutputStream foStream = null;
int fileCount = 0;
File dstFile = null;
public DirectoryRcr()
{
acceptConnection();
}
private void acceptConnection()
{
try
{
ServerSocket server = new ServerSocket(22);
socket = server.accept();
isLive = true;
ioStream = socket.getOutputStream();
inStream = socket.getInputStream();
state = initialState;
startReadThread();
}
catch (IOException io)
{
io.printStackTrace();
}
}
private void startReadThread()
{
Thread readRunnable = new Thread()
{
public void run()
{
while (isLive)
{
try
{
int num = inStream.read(readBuffer);
if (num > 0)
{
byte[] tempArray = new byte[num];
System.arraycopy(readBuffer, 0, tempArray, 0, num);
processBytes(tempArray);
}
sleep(100);
} catch (SocketException s)
{
}
catch (IOException e)
{
e.printStackTrace();
}
catch (InterruptedException i)
{
i.printStackTrace();
}
}
}
};
Thread readThread = new Thread(readRunnable);
readThread.start();
}
private void processBytes(byte[] buff) throws InterruptedException
{
if (state == fileReceiveState || state == fileContentWaitState)
{
if (state == fileContentWaitState)
state = fileReceiveState;
fileSize = fileSize - buff.length;
writeToFile(buff);
if (fileSize == 0)
{
state = fileReceivedState;
try
{
foStream.close();
}
catch (IOException io)
{
io.printStackTrace();
}
System.out.println("Received " + dstFile.getName());
sendResponse(fileReceived);
fileCount--;
if (fileCount != 0)
{
state = fileHeaderWaitState;
}
else
{
System.out.println("Finished");
state = finalState;
sendResponse("Thanks");
Thread.sleep(2000);
System.exit(0);
}
System.out.println("Received");
}
}
else
{
parseToUTF(buff);
}
}
private void parseToUTF(byte[] data)
{
try
{
String parsedMessage = new String(data, "UTF-8");
System.out.println(parsedMessage);
setResponse(parsedMessage);
}
catch (UnsupportedEncodingException u) {
u.printStackTrace();
}
}
private void setResponse(String message)
{
if (message.trim().equalsIgnoreCase(request) && state == initialState)
{
sendResponse(respServer);
state = dirHeaderWait;
}
else if (state == dirHeaderWait)
{
if (createDirectory(message))
{
sendResponse(dirResponse);
state = fileHeaderWaitState;
}
else
{
sendResponse(dirFailedResponse);
System.out.println("Error occurred...Going to exit");
System.exit(0);
}
} else if (state == fileHeaderWaitState)
{
createFile(message);
state = fileContentWaitState;
sendResponse(fileHeaderRecvd);
}
else if (message.trim().equalsIgnoreCase(dirFailedResponse))
{
System.out.println("Error occurred ....");
System.exit(0);
}
}
private void sendResponse(String resp)
{
try
{
sendBytes(resp.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
private boolean createDirectory(String dirName)
{
boolean status = false;
dir = dirName.substring(dirName.indexOf("$") + 1, dirName.indexOf("#"));
fileCount = Integer.parseInt(dirName.substring(dirName.indexOf("#") + 1, dirName.indexOf("&")));
if (new File(dir).mkdir())
{
status = true;
System.out.println("Successfully created directory " + dirName);
}
else if (new File(dir).mkdirs())
{
status = true;
System.out.println("Directories were created " + dirName);
}
else if (new File(dir).exists())
{
status = true;
System.out.println("Directory exists" + dirName);
}
else
{
System.out.println("Could not create directory " + dirName);
status = false;
}
return status;
}
private void createFile(String fileName)
{
String file = fileName.substring(fileName.indexOf("&") + 1, fileName.indexOf("#"));
String lengthFile = fileName.substring(fileName.indexOf("#") + 1, fileName.indexOf("*"));
fileSize = Integer.parseInt(lengthFile);
dstFile = new File(dir + "/" + file);
try
{
foStream = new FileOutputStream(dstFile);
System.out.println("Starting to receive " + dstFile.getName());
}
catch (FileNotFoundException fn)
{
fn.printStackTrace();
}
}
private void writeToFile(byte[] buff)
{
try
{
foStream.write(buff);
}
catch (IOException io)
{
io.printStackTrace();
}
}
private void sendBytes(byte[] dataBytes)
{
synchronized (socket)
{
if (ioStream != null)
{
try
{
ioStream.write(dataBytes);
}
catch (IOException io)
{
io.printStackTrace();
}
}
}
}
}
Note that:-
ClientMain.java and DirectoryTxr.java are the two classes under client application.
ServerMain.java and DirectoryRcr.java are the two classes under Server application.
run the ClientMain.java and ServerMain.java simultaneously
Also specify the source directory, destination directory and host address of the machine in which server is running in the ClientMain.java(as per your computer). Here we are not specifying source file ,instead a source directory or folder is specifying.So the entire files of source directory will be transferred.
I would really appreciate if someone can help me with the problem.
You can check this code. This code can send files till 2GB of file size. Checked and working. Basically what I do here is first I send the file size and file name in an object then I start sending the file. First of all let me show you the class whose object will carry the File's details and send it to Receiver.
FileTransfer Class:
public class FileDetails implements Serializable {
String name;
long size;
public void setDetails(String name, long size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public long getSize() {
return size;
}
}
Sender:
ServerSocket sendServer = null;
Socket sendSocket;
FileDetails details;
byte data[];
try {
File file = new File("File Url");
// Getting file name and size
if (file.length() > Integer.MAX_VALUE) {
System.out.println("File size exceeds 2 GB");
} else {
sendServer = new ServerSocket(5050);
System.out.println("Waiting for Client...");
sendSocket = sendServer.accept();
// File Object for accesing file Details
System.out.println("Connected to Client...");
data = new byte[2048]; // Here you can increase the size also which will send it faster
details = new FileDetails();
details.setDetails(file.getName(), file.length());
// Sending file details to the client
System.out.println("Sending file details...");
ObjectOutputStream sendDetails = new ObjectOutputStream(sendSocket.getOutputStream());
sendDetails.writeObject(details);
sendDetails.flush();
// Sending File Data
System.out.println("Sending file data...");
FileInputStream fileStream = new FileInputStream(file);
BufferedInputStream fileBuffer = new BufferedInputStream(fileStream);
OutputStream out = sendSocket.getOutputStream();
int count;
while ((count = fileBuffer.read(data)) > 0) {
System.out.println("Data Sent : " + count);
out.write(data, 0, count);
out.flush();
}
out.close();
fileBuffer.close();
fileStream.close();
}
} catch (Exception e) {
System.out.println("Error : " + e.toString());
}
Receiver's code :
int port = 5050;
try {
System.out.println("Connecting to Server...");
Socket receiveSocket = new Socket("IP of Server", port);
System.out.println("Connected to Server...");
// Getting file details
System.out.println("Getting details from Server...");
ObjectInputStream getDetails = new ObjectInputStream(receiveSocket.getInputStream());
FileDetails details = (FileDetails) getDetails.readObject();
System.out.println("Now receiving file...");
// Storing file name and sizes
String fileName = details.getName();
System.out.println("File Name : " + fileName);
byte data[] = new byte[2048]; // Here you can increase the size also which will receive it faster
FileOutputStream fileOut = new FileOutputStream("D:\\" + fileName);
InputStream fileIn = receiveSocket.getInputStream();
BufferedOutputStream fileBuffer = new BufferedOutputStream(fileOut);
int count;
int sum = 0;
while ((count = fileIn.read(data)) > 0) {
sum += count;
fileBuffer.write(data, 0, count);
System.out.println("Data received : " + sum);
fileBuffer.flush();
}
System.out.println("File Received...");
fileBuffer.close();
fileIn.close();
} catch (Exception e) {
System.out.println("Error : " + e.toString());
}
Hope this helps you.
You don't need all this. The canonical way to copy a stream in Java is as follows. It works for any buffer size greater than zero. I generally use 8192. There is certainly no necessity to read entire files into memory. It just wastes time and space.
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you know the size in advance and need to keep the socket open for another transfer:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
where total is a long initialized to zero before this loop, and length is the length you know in advance.
I am trying to send a json string , from my BlackBerry OS < 7.X application to my Server. I am trying to use an HTTP Post request. What i have done so far is :
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php/" + jsonString;
try {
HttpConnection httpConn;
httpConn = (HttpConnection) Connector.open(httpURL + getConnectionString());
httpConn.setRequestMethod(HttpConnection.POST);
httpConn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
DataOutputStream _outStream = new DataOutputStream(httpConn.openDataOutputStream());
byte[] request_body = httpURL.getBytes();
for (int i = 0; i < request_body.length; i++) {
_outStream.writeByte(request_body[i]);
}
DataInputStream _inputStream = new DataInputStream(httpConn.openInputStream());
StringBuffer _responseMessage = new StringBuffer();
int ch;
while ((ch = _inputStream.read()) != -1) {
_responseMessage.append((char) ch);
}
String res = (_responseMessage.toString());
String response = res.trim();
System.out.println("!!!!!!!!!!!!!! Response is: " + response);
httpConn.close();
} catch (Exception e) {
Dialog.alert("Error - " + e.toString());
}
The code works in a way that i dont fully understand. The author of the above code suggested to use as an httpURL the URL of the server + my json string. The final result is that on my server instead of arriving the json string , is arriving a string like that :
http://ip_of_my_server/phpServer/receiver2.php/ + jsonString
I am not familiar with java. I have previously done this for WP7 and iOS and in the httpUrl i put my servers URL and then with a command i was "appending" my json string to the http request and everything worked as expected.
How can i append the json string to the above HttpRequest , instead of adding it to the URL so that in the server arrives the JSON String only?
EDIT (providing the rest of the code that was used)
//used to specify connection type ( wifi - 3g - etc )
public static String getConnectionString() {
String connectionString = null;
// Wifi is the preferred transmission method
if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED) {
connectionString = ";interface=wifi";
}
// Is the carrier network the only way to connect?
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT) {
String carrierUid = getCarrierBIBSUid();
if (carrierUid == null) {
// Has carrier coverage, but not BIBS. So use the carrier's TCP network
connectionString = ";deviceside=true";
} else {
// otherwise, use the Uid to construct a valid carrier BIBS request
connectionString = ";deviceside=false;connectionUID="+carrierUid + ";ConnectionType=mds-public";
}
}
// Check for an MDS connection instead (BlackBerry Enterprise Server)
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS) {
connectionString = ";deviceside=false";
}
// If there is no connection available abort to avoid hassling the user unnecessarily
else if (CoverageInfo.getCoverageStatus() == CoverageInfo.COVERAGE_NONE) {
connectionString = "none";
}
// In theory, all bases are covered by now so this shouldn't be reachable.But hey, just in case ...
else {
connectionString = ";deviceside=true";
}
System.out.println("!!!!!!!!!!!!!! Connection type is: " + connectionString);
return connectionString;
}
/**
* Looks through the phone's service book for a carrier provided BIBS
* network
*
* #return The uid used to connect to that network.
*/
private synchronized static String getCarrierBIBSUid() {
ServiceRecord[] records = ServiceBook.getSB().getRecords();
int currentRecord;
for (currentRecord = 0; currentRecord < records.length; currentRecord++) {
if (records[currentRecord].getCid().toLowerCase().equals("ippp")) {
if (records[currentRecord].getName().toLowerCase()
.indexOf("bibs") >= 0) {
return records[currentRecord].getUid();
}
}
}
return null;
}
The the first line should be simply your URL
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php";
And you should only send the json string to the server as request.
instead of byte[] request_body = httpURL.getBytes();
use byte[] request_body = jsonString.getBytes();
Here is the method for OS 5.0 and above
public static HttpConnection getHttpConnection(String url, byte[] postData) {
HttpConnection conn = null;
OutputStream out = null;
try {
conn = (HttpConnection) new ConnectionFactory().getConnection(url).getConnection();
if (conn != null) {
if (postData == null) {
conn.setRequestMethod(HttpConnection.GET);
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
} else {
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Length", String.valueOf(postData.length));
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
out = conn.openOutputStream();
out.write(postData);
out.flush();
}
if (conn.getResponseCode() != 0) {
return conn;
}
}
} catch (Exception e) {
} finally {
try {
out.close();
} catch (Exception e2) {
}
}
//Only if exception occurs, we close the connection.
//Otherwise the caller should close the connection himself.
try {
conn.close();
} catch (Exception e1) {
}
return null;
}
Here is the complete class if you want it to work with OS 4.2 and above. You may need to replace the constant COVERAGE_DIRECT by its value 1, if you want to compile it with < 4.5.
public class ConnectionHelper {
/**
* Returns the working connection type. The connection types can be BIS, BES, TCP, WAP2, TCPIP
*/
public static HttpConnection getHttpConnection(String url, byte[] postData) {
int[] preferredOrder = new int[] { CONNECTION_WIFI, CONNECTION_BIS, CONNECTION_BES, CONNECTION_UNITE, CONNECTION_WAP2, CONNECTION_TCPIP, };
for (int i = 0; i < preferredOrder.length; i++) {
int type = preferredOrder[i];
if (isPresent(type)) {
HttpConnection conn = null;
OutputStream out = null;
try {
conn = (HttpConnection) Connector.open(convertURL(type, url));
if (conn != null) {
if (postData == null) {
conn.setRequestMethod(HttpConnection.GET);
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
} else {
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(postData.length));
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
out = conn.openOutputStream();
out.write(postData);
out.flush();
}
if (conn.getResponseCode() != 0) {
return conn;
}
}
} catch (Exception e) {
} finally {
try {
out.close();
} catch (Exception e2) {
}
}
}
}
// Only if exception occurs, we close the connection.
// Otherwise the caller should close the connection himself.
try {
conn.close();
} catch (Exception e1) {
}
return null;
}
/** Stores transport ServiceBooks if found. Otherwise, null */
private static ServiceRecord srMDS, srWiFi, srBIS, srWAP2, srUnite;
private static final int CONNECTION_DEFAULT = 0;
private static final int CONNECTION_BIS = 1;
private static final int CONNECTION_BES = 2;
private static final int CONNECTION_TCPIP = 3;
private static final int CONNECTION_WIFI = 4;
private static final int CONNECTION_WAP2 = 5;
private static final int CONNECTION_UNITE = 6;
private static final int CONFIG_TYPE_BES = 1;
private static final String UNITE_NAME = "Unite";
private static void checkTransportAvailability() {
initializeTransportAvailability();
}
/**
* Initializes the ServiceRecord instances for each transport (if available). Otherwise leaves it null. Also determines if sufficient coverage is available for each transport
* and sets coverage* flags.
*/
private static void initializeTransportAvailability() {
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.getRecords();
for (int i = 0; i < records.length; i++) {
ServiceRecord myRecord = records[i];
String cid, uid;
if (myRecord.isValid() && !myRecord.isDisabled()) {
cid = myRecord.getCid().toLowerCase();
uid = myRecord.getUid().toLowerCase();
// BIS
if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") != -1) {
srBIS = myRecord;
}
// BES
if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") == -1) {
srMDS = myRecord;
}
// WiFi
if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") != -1) {
srWiFi = myRecord;
}
// Wap2.0
if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") == -1 && uid.indexOf("mms") == -1) {
srWAP2 = myRecord;
}
// Unite
if (getConfigType(myRecord) == CONFIG_TYPE_BES && myRecord.getName().equals(UNITE_NAME)) {
srUnite = myRecord;
}
}
}
}
/**
* Gets the config type of a ServiceRecord using getDataInt below
*
* #param record
* A ServiceRecord
* #return configType of the ServiceRecord
*/
private static int getConfigType(ServiceRecord record) {
return getDataInt(record, 12);
}
/**
* Gets the config type of a ServiceRecord. Passing 12 as type returns the configType.
*
* #param record
* A ServiceRecord
* #param type
* dataType
* #return configType
*/
private static int getDataInt(ServiceRecord record, int type) {
DataBuffer buffer = null;
buffer = getDataBuffer(record, type);
if (buffer != null) {
try {
return ConverterUtilities.readInt(buffer);
} catch (EOFException e) {
return -1;
}
}
return -1;
}
/**
* Utility Method for getDataInt()
*/
private static DataBuffer getDataBuffer(ServiceRecord record, int type) {
byte[] data = record.getApplicationData();
if (data != null) {
DataBuffer buffer = new DataBuffer(data, 0, data.length, true);
try {
buffer.readByte();
} catch (EOFException e1) {
return null;
}
if (ConverterUtilities.findType(buffer, type)) {
return buffer;
}
}
return null;
}
private static String convertURL(int connectionType, String url) {
switch (connectionType) {
case CONNECTION_BES:
url += ";deviceside=false";
break;
case CONNECTION_BIS:
url += ";deviceside=false" + ";ConnectionType=mds-public";
break;
case CONNECTION_TCPIP:
url += ";deviceside=true";
break;
case CONNECTION_WIFI:
url += ";interface=wifi";
break;
case CONNECTION_WAP2:
url += ";deviceside=true;ConnectionUID=" + srWAP2.getUid();
break;
case CONNECTION_UNITE:
url += ";deviceside=false;ConnectionUID=" + srUnite.getUid();
break;
}
return url;
}
private static boolean isPresent(int connectionType) {
checkTransportAvailability();
switch (connectionType) {
case CONNECTION_BIS:
return (srBIS != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_BIS_B));
case CONNECTION_BES:
return (srMDS != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS));
case CONNECTION_WIFI:
return (srWiFi != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT, RadioInfo.WAF_WLAN, false));
case CONNECTION_TCPIP:
return (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT));
case CONNECTION_WAP2:
return (srWAP2 != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT));
case CONNECTION_UNITE:
return (srUnite != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS));
case CONNECTION_DEFAULT:
return true;
}
return false;
}
}
And finally post your data.
public void sendJson(String jsonString) {
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php";
HttpConnection httpConn = null;
try {
httpConn = getHttpConnection(httpURL, jsonString.getBytes());
if(httpConn.getResponseCode() == 200) {
//If you need the output, then read it. Otherwise comment it.
byte[] data = IOUtilities.streamToBytes(httpConn.openInputStream());
String response = new String(data);
System.out.println("!!!!!!!!!!!!!! Response is: " + response);
}
} catch (Exception e) {
}
finally {
try {
httpConn.close();
} catch (Exception e2) {
}
}
}
I'm using jersey's HttpServerFactory to create a simple embedded HttpServer that hosts a couple of rest services. We just needed something small quick and lightweight. I need to host a small static html page inside the same server instance. Is there a simple way to add a static handler to the server? Is there a pre-defined handler I can use? It seems like a pretty common task, I'd hate to re-write code for it if it already exists.
server = HttpServerFactory.create(url);
server.setExecutor(Executors.newCachedThreadPool());
server.createContext("/staticcontent", new HttpHandler() {
#Override
public void handle(HttpExchange arg0) throws IOException {
//What goes here?
}
});
server.start();
Here is a safe version. You may want to add a couple of MIME types, depending on which ones are common (or use another method if your platform has that).
package de.phihag.miniticker;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class StaticFileHandler implements HttpHandler {
private static final Map<String,String> MIME_MAP = new HashMap<>();
static {
MIME_MAP.put("appcache", "text/cache-manifest");
MIME_MAP.put("css", "text/css");
MIME_MAP.put("gif", "image/gif");
MIME_MAP.put("html", "text/html");
MIME_MAP.put("js", "application/javascript");
MIME_MAP.put("json", "application/json");
MIME_MAP.put("jpg", "image/jpeg");
MIME_MAP.put("jpeg", "image/jpeg");
MIME_MAP.put("mp4", "video/mp4");
MIME_MAP.put("pdf", "application/pdf");
MIME_MAP.put("png", "image/png");
MIME_MAP.put("svg", "image/svg+xml");
MIME_MAP.put("xlsm", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
MIME_MAP.put("xml", "application/xml");
MIME_MAP.put("zip", "application/zip");
MIME_MAP.put("md", "text/plain");
MIME_MAP.put("txt", "text/plain");
MIME_MAP.put("php", "text/plain");
};
private String filesystemRoot;
private String urlPrefix;
private String directoryIndex;
/**
* #param urlPrefix The prefix of all URLs.
* This is the first argument to createContext. Must start and end in a slash.
* #param filesystemRoot The root directory in the filesystem.
* Only files under this directory will be served to the client.
* For instance "./staticfiles".
* #param directoryIndex File to show when a directory is requested, e.g. "index.html".
*/
public StaticFileHandler(String urlPrefix, String filesystemRoot, String directoryIndex) {
if (!urlPrefix.startsWith("/")) {
throw new RuntimeException("pathPrefix does not start with a slash");
}
if (!urlPrefix.endsWith("/")) {
throw new RuntimeException("pathPrefix does not end with a slash");
}
this.urlPrefix = urlPrefix;
assert filesystemRoot.endsWith("/");
try {
this.filesystemRoot = new File(filesystemRoot).getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.directoryIndex = directoryIndex;
}
/**
* Create and register a new static file handler.
* #param hs The HTTP server where the file handler will be registered.
* #param path The path in the URL prefixed to all requests, such as "/static/"
* #param filesystemRoot The filesystem location.
* For instance "/var/www/mystaticfiles/".
* A request to "/static/x/y.html" will be served from the filesystem file "/var/www/mystaticfiles/x/y.html"
* #param directoryIndex File to show when a directory is requested, e.g. "index.html".
*/
public static void create(HttpServer hs, String path, String filesystemRoot, String directoryIndex) {
StaticFileHandler sfh = new StaticFileHandler(path, filesystemRoot, directoryIndex);
hs.createContext(path, sfh);
}
public void handle(HttpExchange he) throws IOException {
String method = he.getRequestMethod();
if (! ("HEAD".equals(method) || "GET".equals(method))) {
sendError(he, 501, "Unsupported HTTP method");
return;
}
String wholeUrlPath = he.getRequestURI().getPath();
if (wholeUrlPath.endsWith("/")) {
wholeUrlPath += directoryIndex;
}
if (! wholeUrlPath.startsWith(urlPrefix)) {
throw new RuntimeException("Path is not in prefix - incorrect routing?");
}
String urlPath = wholeUrlPath.substring(urlPrefix.length());
File f = new File(filesystemRoot, urlPath);
File canonicalFile;
try {
canonicalFile = f.getCanonicalFile();
} catch (IOException e) {
// This may be more benign (i.e. not an attack, just a 403),
// but we don't want the attacker to be able to discern the difference.
reportPathTraversal(he);
return;
}
String canonicalPath = canonicalFile.getPath();
if (! canonicalPath.startsWith(filesystemRoot)) {
reportPathTraversal(he);
return;
}
FileInputStream fis;
try {
fis = new FileInputStream(canonicalFile);
} catch (FileNotFoundException e) {
// The file may also be forbidden to us instead of missing, but we're leaking less information this way
sendError(he, 404, "File not found");
return;
}
String mimeType = lookupMime(urlPath);
he.getResponseHeaders().set("Content-Type", mimeType);
if ("GET".equals(method)) {
he.sendResponseHeaders(200, canonicalFile.length());
OutputStream os = he.getResponseBody();
copyStream(fis, os);
os.close();
} else {
assert("HEAD".equals(method));
he.sendResponseHeaders(200, -1);
}
fis.close();
}
private void copyStream(InputStream is, OutputStream os) throws IOException {
byte[] buf = new byte[4096];
int n;
while ((n = is.read(buf)) >= 0) {
os.write(buf, 0, n);
}
}
private void sendError(HttpExchange he, int rCode, String description) throws IOException {
String message = "HTTP error " + rCode + ": " + description;
byte[] messageBytes = message.getBytes("UTF-8");
he.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
he.sendResponseHeaders(rCode, messageBytes.length);
OutputStream os = he.getResponseBody();
os.write(messageBytes);
os.close();
}
// This is one function to avoid giving away where we failed
private void reportPathTraversal(HttpExchange he) throws IOException {
sendError(he, 400, "Path traversal attempt detected");
}
private static String getExt(String path) {
int slashIndex = path.lastIndexOf('/');
String basename = (slashIndex < 0) ? path : path.substring(slashIndex + 1);
int dotIndex = basename.lastIndexOf('.');
if (dotIndex >= 0) {
return basename.substring(dotIndex + 1);
} else {
return "";
}
}
private static String lookupMime(String path) {
String ext = getExt(path).toLowerCase();
return MIME_MAP.getOrDefault(ext, "application/octet-stream");
}
}
This will do the trick, though it does allow anyone to walk the tree by requesting ../../../
You can change ./wwwroot to any valid java filepath.
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String root = "./wwwroot";
URI uri = t.getRequestURI();
System.out.println("looking for: "+ root + uri.getPath());
String path = uri.getPath();
File file = new File(root + path).getCanonicalFile();
if (!file.isFile()) {
// Object does not exist or is not a file: reject with 404 error.
String response = "404 (Not Found)\n";
t.sendResponseHeaders(404, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
} else {
// Object exists and is a file: accept with response code 200.
String mime = "text/html";
if(path.substring(path.length()-3).equals(".js")) mime = "application/javascript";
if(path.substring(path.length()-3).equals("css")) mime = "text/css";
Headers h = t.getResponseHeaders();
h.set("Content-Type", mime);
t.sendResponseHeaders(200, 0);
OutputStream os = t.getResponseBody();
FileInputStream fs = new FileInputStream(file);
final byte[] buffer = new byte[0x10000];
int count = 0;
while ((count = fs.read(buffer)) >= 0) {
os.write(buffer,0,count);
}
fs.close();
os.close();
}
}
}