I made a Client-Server chat via sockets and it works great. Now I want to include an option for the server(Android phone) to grap a screenshot from the client(pc application). Creating the screenshot works fine, but the transfer from the client to the server fails every time.
CLIENT-SIDE / SENDER:
Before I wrote the image directly to an output stream, but I get an error on the server side and so I tried this way, but it's just the same.
public class ClientScreenshotThread implements Runnable {
// - Software Init - //
private Socket transferSocket;
private BufferedImage screenshot;
private Robot robot;
private BufferedWriter outToServer;
private FileInputStream inStream;
private DataOutputStream outStream;
// - Var Init - //
private final int SERVER_TRANSFER_PORT = 65000;
private int screenWidth, screenHeight;
// -------------------------------------------------- //
public ClientScreenshotThread() {
}
#Override
public void run() {
try {
SocketAddress sockaddr = new InetSocketAddress(Client.SERVER_IP, SERVER_TRANSFER_PORT);
transferSocket = new Socket();
transferSocket.connect(sockaddr, 5000); // 5sec Timeout
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
robot = new Robot();
screenWidth = dimension.width;
screenHeight = dimension.height;
Rectangle screen = new Rectangle(screenWidth, screenHeight);
screenshot = robot.createScreenCapture(screen);
ImageIO.write(screenshot, "png", new File("/Users/chris/Downloads/screenshot.png"));
File file = new File("/Users/chris/Downloads/screenshot.png");
inStream = new FileInputStream(file);
byte[] buffer = new byte[4096];
// prepare server for receiving the screenshot
outToServer = new BufferedWriter(new OutputStreamWriter(transferSocket.getOutputStream()));
outToServer.write("#!<cmd>screenshot");
outToServer.newLine();
outToServer.flush();
// send the screenshot to the server
outStream = new DataOutputStream(transferSocket.getOutputStream());
int n;
int i = 0;
while((n = inStream.read(buffer)) != -1) {
i++;
System.out.println(i + ". Byte[" + n + "]");
outStream.write(buffer, 0, n);
outStream.flush();
}
} catch(AWTException e1) {
System.out.println("AWT: " + e1.getMessage().toString());
} catch(IOException e2) {
System.out.println("IO: " + e2.getMessage().toString());
} finally {
try {
// close streams and socket
inStream.close();
outToServer.close();
transferSocket.close();
} catch(IOException e) {
System.out.println(e.getMessage().toString());
}
}
}
}
SERVER-SIDE / RECEIVER:
I always get a "NullPointerException" at:
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
public class ServerTransferThread implements Runnable {
// - Software Init - //
private ServerSocket serverTransferSocket;
private Handler handler;
private BufferedReader inFromClient;
private DataInputStream inStream;
private ByteArrayOutputStream content;
private FileOutputStream fileOutStream;
// - Var Init - //
private final String TAG = "xxx";
private final int SERVER_TRANSFER_PORT = 65000;
// -------------------------------------------------- //
public ServerTransferThread(Handler _handler) {
this.handler = _handler;
}
#Override
public void run() {
Log.d(TAG, "ServerTransferThread: run()");
try {
serverTransferSocket = new ServerSocket(SERVER_TRANSFER_PORT);
while(ServerActivity.SERVER_STATE == true) {
Socket socket = serverTransferSocket.accept();
Log.d(TAG, "ServerTransferThread: accepted()");
inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.d(TAG, "ServerTransferThread: bufferedReader()");
String message = "";
if((message = inFromClient.readLine()) != null) {
if(message.equals("#!<cmd>screenshot")) {
receiveScreenshot(socket);
}
}
}
} catch(IOException e) {
Log.e(TAG, "ServerTransferThread 1: " + e.getMessage().toString());
} finally {
try {
inFromClient.close();
serverTransferSocket.close();
} catch (IOException e) {
Log.e(TAG, "ServerTransferThread 2: " + e.getMessage().toString());
}
}
}
private void receiveScreenshot(Socket socketX) {
Log.d(TAG, "ServerTransferThread: receiveScreenshot()");
try {
handler.sendMessage(buildMessage("> Receiving screenshot.."));
inStream = new DataInputStream(socketX.getInputStream());
byte[] buffer = new byte[4096];
content = new ByteArrayOutputStream();
inStream = new DataInputStream(socketX.getInputStream());
int n;
while((n = inStream.read()) != -1) {
content.write(buffer, 0, n); // HERE I "OUT OF MEMORY"
content.flush();
}
File directory = new File(ServerActivity.APP_FOLDER_PATH);
File screenshot = new File(ServerActivity.APP_FOLDER_PATH + "/" + "screenshot.png");
if(!directory.exists())
directory.mkdirs();
if(!screenshot.exists()) {
screenshot.createNewFile();
}
else {
screenshot.delete();
screenshot.createNewFile();
}
fileOutStream = new FileOutputStream(screenshot);
Bitmap bmp = BitmapFactory.decodeByteArray(content.toByteArray(), 0, content.size());
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
handler.sendMessage(buildMessage("> Screenshot received sucessfully!"));
} catch(IOException e1) {
Log.e(TAG, "ServerTransferThread 3: " + e1.getMessage().toString());
} finally {
try {
inStream.close();
content.close();
fileOutStream.close();
socketX.close();
} catch (IOException e) {
Log.e(TAG, "ServerTransferThread 4: " + e.getMessage().toString());
}
}
}
private Message buildMessage(String text) {
Log.d(TAG, "ServerTransferThread: buildMessage()");
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("MESSAGE", text);
msg.setData(bundle);
return msg;
}
Here is my Logcat output:
08-20 19:01:18.285: D/skia(5383): --- SkImageDecoder::Factory returned null
08-20 19:01:18.295: W/dalvikvm(5383): threadid=12: thread exiting with uncaught exception (group=0x40c6b1f8)
08-20 19:01:18.295: E/AndroidRuntime(5383): FATAL EXCEPTION: Thread-3051
08-20 19:01:18.295: E/AndroidRuntime(5383): java.lang.NullPointerException
08-20 19:01:18.295: E/AndroidRuntime(5383): at net.api.speak.wifi.ServerTransferThread.receiveScreenshot(ServerTransferThread.java:114)
08-20 19:01:18.295: E/AndroidRuntime(5383): at net.api.speak.wifi.ServerTransferThread.run(ServerTransferThread.java:58)
08-20 19:01:18.295: E/AndroidRuntime(5383): at java.lang.Thread.run(Thread.java:856)
08-20 19:01:27.820: D/Speak WiFi(5383): Server: onDestroy()
08-20 19:01:27.830: E/Speak WiFi(5383): Server: Socket closed
08-20 19:01:27.830: E/Speak WiFi(5383): ServerThread: Socket closed
EDIT: After some troubles I've found a final solution for the file transfer problem! There it is:
Final Server side:
int bytecount = 2048;
byte[] buf = new byte[bytecount];
OutputStream OUT = socket.getOutputStream();
BufferedOutputStream BuffOUT = new BufferedOutputStream(OUT, bytecount);
FileInputStream in = new FileInputStream(itemPath);
int i = 0;
while ((i = in.read(buf, 0, bytecount)) != -1) {
BuffOUT.write(buf, 0, i);
BuffOUT.flush();
}
Final Client side:
FileOutputStream outToFile = new FileOutputStream(FileName);
int bytecount = 2048;
byte[] buf = new byte[bytecount];
// Create an inputstream for the file data to arrive
InputStream IN = socket.getInputStream();
BufferedInputStream BuffIN = new BufferedInputStream(IN, bytecount);
// Receiving file..
int i = 0;
int filelength = 0;
while((i = BuffIN.read(buf, 0, bytecount)) != -1) {
filelength += i;
outToFile.write(buf, 0, i);
outToFile.flush();
}
Could you write the received bytes directly to a FileOutputStream.
Converting the png to a bitmap on a rather limited device like a smartphone will cause problems sometimes.
Do you need to create the Bitmap object on the receiver side?
If not, you can do something like this:
InputStream is = socketX.getInputStream();
FileOutputStream outputFile = new FileOutputStream(screenshot);
int n;
while ((n = is.read(data, 0, data.length)) != -1) {
outputFile.write(data, 0, n);
}
I haven't tested the code.
The NullPointerException is because the BitmapFactory.decodeByteArray returns: The decoded bitmap, or null if the image could not be decode.
Server-side (inside receiveScreenshot() method), the part that writes the InputStream bytes into the ByteArrayOutputStream 'content' variable is not correct, because inStream.read() should be inStream.read(buffer)
The Out of Memory error can be explained because read() method only reads one byte at a time, and then for each byte you always write a full buffer of 4096 bytes.
Edit: To compress OutputStream to png once you have written all the bytes inside the fileOutputStream and when you don't want to directly provide the bytes (because in your case it is what didn't work):
// Write bytes inside fileOutStream
Bitmap bmp = BitmapFactory.decodeFile(screenshot.getAbsolutePath());
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
fileOutStream.close();
This should work for your needs, but it's a pity to decode the file since you should already know the bytes inside..
Related
I have implemented a file transfer program using java socket. In this program, a file is sent from the client and its then downloaded in the Server. The program works almost correctly but the problem is the length of the received byte is always greater than the byte length sent from the client. for example, I sent 678888589 bytes from the client, but when I check the length of the received file at the server, I got 678925260 bytes. And for that reason, I am getting different checksum on the server side.
Here is my code:
Client Class:
public class Client
{
final static int ServerPort = 1234;
public static final int BUFFER_SIZE = 1024 * 50;
private static byte[] buffer;
public static void main(String args[]) throws UnknownHostException, IOException
{
Scanner scn = new Scanner(System.in);
buffer = new byte[BUFFER_SIZE];
for(int i=0;i<8;i++) {
Socket s1 = new Socket(ip, ServerPort);
DataOutputStream dos1 = new DataOutputStream(s1.getOutputStream());
SendMessage message = new SendMessage(s1, "test.mp4",dos1);
Thread t = new Thread(message);
System.out.println("Adding this client to active client list");
t.start();
}
}
}
class SendMessage implements Runnable{
String file_name;
Socket s;
public final int BUFFER_SIZE = 1024 * 50;
private byte[] buffer;
DataOutputStream dos;
public SendMessage(Socket sc,String file_name,DataOutputStream dos) {
this.file_name = file_name;
this.s=sc;
buffer = new byte[BUFFER_SIZE];
this.dos = dos;
}
#Override
public void run() {
File file = new File(file_name);
try {
sendFile(file, dos);
dos.close();
while(true) {
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void sendFile(File file, DataOutputStream dos) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE+1];
if(dos!=null&&file.exists()&&file.isFile())
{
FileInputStream input = new FileInputStream(file);
dos.writeLong(file.length());
System.out.println(file.getAbsolutePath());
int read = 0;
int totalLength = 0;
while ((read = input.read(buffer)) != -1) {
dos.write(buffer);
totalLength +=read;
System.out.println("length "+read);
}
input.close();
System.out.println("File successfully sent! "+totalLength);
}
}
}
Server Class
// Server class
public class Server
{
// Vector to store active clients
static Vector<ClientHandler> ar = new Vector<>();
// counter for clients
static int i = 0;
public static void main(String[] args) throws IOException
{
// server is listening on port 1234
ServerSocket ss = new ServerSocket(1234);
Socket s;
// running infinite loop for getting
// client request
while (true)
{
// Accept the incoming request
s = ss.accept();
System.out.println("New client request received : " + s);
// obtain input and output streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
System.out.println("Creating a new handler for this client...");
// Create a new handler object for handling this request.
ClientHandler mtch = new ClientHandler(s,"client " + i, dis, dos);
// Create a new Thread with this object.
Thread t = new Thread(mtch);
System.out.println("Adding this client to active client list");
// add this client to active clients list
ar.add(mtch);
// start the thread.
t.start();
// increment i for new client.
// i is used for naming only, and can be replaced
// by any naming scheme
i++;
}
}
}
// ClientHandler class
class ClientHandler implements Runnable
{
Scanner scn = new Scanner(System.in);
private String name;
final DataInputStream dis;
final DataOutputStream dos;
Socket s;
boolean isloggedin;
public static final int BUFFER_SIZE = 1024*50;
private byte[] buffer;
// constructor
public ClientHandler(Socket s, String name,
DataInputStream dis, DataOutputStream dos) {
this.dis = dis;
this.dos = dos;
this.name = name;
this.s = s;
this.isloggedin=true;
buffer = new byte[BUFFER_SIZE];
}
#Override
public void run() {
String received;
BufferedOutputStream out = null;
String outputFile = "out_"+this.name+".mp4";
BufferedInputStream in = null;
try {
in = new BufferedInputStream(s.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out = new BufferedOutputStream(new FileOutputStream(outputFile));
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// while (true)
// {
try
{
long length = -1;
length = dis.readLong();
if(length!=-1)System.out.println("length "+length);
// String checkSum = dis.readUTF();
// System.out.println(checkSum);
int len=0;
long totalLength = 0;
// int len = 0;
while ((len = in.read(buffer,0,BUFFER_SIZE)) > 0) {
out.write(buffer, 0, len);
totalLength+=len;
// if(len<BUFFER_SIZE)break;
// System.out.println("length "+len);
if(len<=0)break;
}
File file = new File(outputFile);
System.out.println("total length1 "+totalLength+ " dif "+(totalLength-length));
System.out.println("output length "+file.length());
} catch (IOException e) {
e.printStackTrace();
}
}
private static String checksum(String filepath, MessageDigest md) throws IOException {
// file hashing with DigestInputStream
try (DigestInputStream dis = new DigestInputStream(new FileInputStream(filepath), md)) {
while (dis.read() != -1) ; //empty loop to clear the data
md = dis.getMessageDigest();
}
// bytes to hex
StringBuilder result = new StringBuilder();
for (byte b : md.digest()) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
It would be great if anyone can tell me what I am doing wrong. also, how can I verify the checksum on serverside. Another issue is the server side code get blocked in this block.
while ((len = in.read(buffer,0,BUFFER_SIZE)) > 0) {
out.write(buffer, 0, len);
System.out.println("length "+len);
if(len<=0)break;
}
It can't break the loop unless the client is disconnected. Although the file is recieved properly.
Regards.
You made a small mistake on the client code. You were writing out the full buffer instead of what is read from the file.
while ((read = input.read(buffer)) != -1) {
dos.write(buffer,0,read);
totalLength += read;
System.out.println("length " + read);
}
[I am asking this because I have checked previous questions and none have answered my questions specific to the code here]
I am relatively new to client server coding. I have Android as client and Java server. The system at the moment works like this:: Android client selects/loads a Jpeg image from sdcard, sends int size, string text and image file to server and server sends back integer and a text file with data back to client
My problem at the moment it works perfectly (randomly) only roughly ~60% of the runs. The remainder of the time it blocks permanently and I have to restart server to continue. [Certainly, a little over half of the time, the client-server system sends and receives without a glitch, but ~40% to 45% (permanent block) failure rate is unacceptable]
When it blocks there is no crash dump, stacktrace or error to read. I have searched previous similar blocking questions and tried to close sockets and inputstream/outputstream and wrappers in different orders varying the permutations, but the success/permanent block rate remained the same
Because there is no stack trace and the randomness, I have no clue what causes the block. Except that using print statements all the server and client code the last prints that hang permanently is in the bytes receiving do-while loop in the server code
I am at a loss on what to do to solve this. I'm hoping experienced minds in this field would help solve this. Full code is below.
Java Server code
public class FileServer {
public static void main(String[] args) throws IOException {
int bytesRead;
int current = 0;
//===============================================
FileInputStream fis = null;
BufferedInputStream bis = null;
OutputStream os = null;
ServerSocket servsock = null;
Socket sock = null;
//==============================================
InetAddress IP=InetAddress.getLocalHost();
servsock = new ServerSocket(57925);
System.out.println("IP "+IP.getHostAddress()+" ***%% :"+servsock.getLocalPort());
while (true) {
sock = servsock.accept();
System.out.println("Accepted connection : " + sock);
InputStream is = sock.getInputStream();
//=========================================================
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//=================== read integer from client ============
String number = br.readLine();
System.out.println("integer received from client is "+String.valueOf(number));
byte [] mybytearray = new byte [Integer.valueOf(number)];
//=================== read filename string =====================================
String filename = br.readLine();
System.out.println("integer received from client is "+filename);
//===================== read file data stream bytes ================================
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
System.out.println("1 bytesRead "+bytesRead+" mybytearray.length "+mybytearray.length);
do {
bytesRead = is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
System.out.println("2 current "+current+" bytesRead "+bytesRead);
} while(current < Integer.valueOf(number));
//============================== initialise filename ======================
FileOutputStream fos = new FileOutputStream("C:\\Server root folder\\"+filename+".jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
//========================== write bytes to server HDD =======================
bos.write(mybytearray, 0 , current);
System.out.println("4 current "+current);
bos.flush();
long end = System.currentTimeMillis();
// System.out.println("AT SERVER: bytesRead "+bytesRead+" current "+current);
// bos.close();
// ======================== write to-be-rendered data to text file ======================
File pathPlusfile = new File("C:/Server root folder/"+filename+".txt");
appendToFile( pathPlusfile, "file name:: "+filename+"* *", 20999 );
/**/ //================== Send Data in text file to Client ============================================
// send file
mybytearray = new byte [(int)pathPlusfile.length()];
fis = new FileInputStream(pathPlusfile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
//===============================================
os = sock.getOutputStream();
//=========================== send integer to client ===============
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
number = Integer.toString(mybytearray.length);
String sendMessage = number + "\n";
bw.write(sendMessage);
bw.flush();
//========================== send file to client ===================
System.out.println("Sending " + filename + "(" + mybytearray.length + " bytes)");
os.write(mybytearray,0,mybytearray.length);
os.flush();
//========================= close =================================
System.out.println("number "+number);
System.out.println("Done.");
bos.close();
bw.close();
osw.close();
os.close();
// fos.close();
// bis.close();
// fis.close();
// br.close();
isr.close();
is.close();
closeFile( );
// servsock.close();
// sock.close();
}
}
BufferedReader bufferedReader = null;
String stringObjectData = "";
public int numFromFile = 0;
static BufferedWriter bufferedWriter = null;
public static void appendToFile( File myPathPlusFile, String S, int num ){
try{
bufferedWriter = new BufferedWriter(new FileWriter(myPathPlusFile, true));
bufferedWriter.append( S );
bufferedWriter.append( " " );
bufferedWriter.append( Integer.toString(num) );
bufferedWriter.newLine();
bufferedWriter.flush();
}
catch (IOException e){
e.printStackTrace();
}
}
public static void closeFile( ){
try{
bufferedWriter.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Android Client code
public class FSendfileActivity extends Activity {
private static final int SELECT_PICTURE = 1;
private Socket sock;
private String serverIP = "192.168.1.4";
private String selectedImagePath;
private ImageView img;
final static String qcd = "qcd";
String ImageDir2Client;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
Button send;
//====================
public static String FILE_TO_RECEIVED=null;
String cFilename = null;
int bytesRead = -1;
int current = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fsendfile);
ImageDir2Client = Environment.getExternalStorageDirectory().getAbsolutePath();
cFilename = "fromServer000019ggg";
FILE_TO_RECEIVED = ImageDir2Client + "/client root/"+cFilename+".txt";
img = (ImageView) findViewById(R.id.ivPic);
((Button) findViewById(R.id.bBrowse)).setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult( Intent.createChooser( intent, "Select Picture" ), SELECT_PICTURE );
}
});
send = (Button) findViewById(R.id.bSend);
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
new Thread(new Runnable() {
#Override
public void run() {
try {
sock = new Socket();
connection(sock, serverIP, 57925);
//=================== prepare buffer to read file ====================
File myFile = new File (selectedImagePath);
byte [] mybytearray = new byte [(int)myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
//=============== read file from sdcard to buffer ==========
bis.read(mybytearray,0,mybytearray.length);
//=================================================================
OutputStream os = sock.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
//============================= send size integer ===================
String number = Integer.toString(mybytearray.length);
String sendMessage = number + "\n";
bw.write(sendMessage); // send size integer here
//============================= send file name =====================
String sendMessage2 = cFilename + "\n";
bw.write(sendMessage2); // send size filename here
osw.flush();
bw.flush();
//==================================================================
os.write(mybytearray,0,mybytearray.length); // send file
os.flush();
//================= client receiving data ==============================
InputStream is = sock.getInputStream();
//=================== read integer from client ==========
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
number = br.readLine();
//========================= set incoming file size=============================
mybytearray = new byte [Integer.valueOf(number)];
//========================read file bytes in chunks===============================
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead = is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(current < Integer.valueOf(number));
fos = new FileOutputStream(FILE_TO_RECEIVED);
bos = new BufferedOutputStream(fos);
bos.write(mybytearray, 0 , current);
bos.flush();
try{
bos.close();
osw.close();
os.close();
// fos.close();
// bw.close();
// br.close();
// isr.close();
bis.close();
sock.close();
// fis.close();
}
catch(Exception e){
e.printStackTrace();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try{
}
catch(Exception e){
e.printStackTrace();
}
}
}
}).start();
}
});
}
public static void connection(Socket s, String serverIP, int port) {
try {
Log.v(qcd, " before connecting ****...");
s.connect(new InetSocketAddress(serverIP, port), 120000);
Log.v(qcd, " socket connection DONE!! ");
} catch (UnknownHostException e) {
e.printStackTrace();
Log.v(qcd, " Unknown host..."+e);
} catch (IOException e) {
e.printStackTrace();
Log.v(qcd, " Failed to connect... "+e);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
img.setImageURI(null);
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
TextView path = (TextView) findViewById(R.id.tvPath);
path.setText("Image Path : " + selectedImagePath);
img.setImageURI(selectedImageUri);
}
}
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
I finally fixed the code. I've had to test it over again all day long, to make sure it wasn't a false positive, so far its held on.
I hope this answer will help someone.
Originally I was using the same InputStream instance to read integer data, string data and file data at the server and the same outputStream instance to send integer data, string data and file data at the client. And at the client, they were wrapped in bufferOutputstream and bufferWritter and at server they were wrapped in bufferedInputstream and bufferedReader objects.
I think I was losing data at this point and thus the reason for the inconsistency
So to solve I had to create and use separate Outputstream instances for each data sent from the client. (note to send the file byte data - outputstream object wasn't wrapped)
Very subtle but solved it
I'm trying to transfer files over a socket in Java, my current approach for the server is:
Create new Thread
Thread sends file name using dos.writeUTF()
Thread sends file size using dos.writeLong()
Thread sends file using dos.write()
Where each Thread represents a client and dos is an instance of DataOutputStream.
Now, on the client I'm doing the same thing but reading instead of writing:
Read file name using dis.readUTF()
Read file size using dis.readLong()
Read file using dis.read()
Where dis is an instance of DataInputStream.
The problem is: when sending one file, everything goes right, but when I try to send 3 files, one after another, it looks like the server is writing everything correctly to the stream as expected but the client (After the first file, which means this starts happening from the second file) is stuck on dis.readUTF() and can't move on.
I've tried fixing this for days but can't get anything to work.
Here's the source code:
SERVER:
Main.java
public class Main {
public static void main(String[] args) {
boolean boolDebug = true;//TODO REMOVE THIS!!
ServerSocket serverSock = null;
List<Socket> clientSocks;
List<ClientThread> clientThreads;
try {
serverSock = new ServerSocket(9090);
} catch(Exception e){
e.printStackTrace();
}
clientSocks = new ArrayList<>();
clientThreads = new ArrayList<>();
ServerSocket finalServerSock = serverSock;
System.out.println();
System.out.println("Listening for incoming connections\n");
new Thread(){
#Override
public void run() {
super.run();
while (true) {
try {
Socket newSock = finalServerSock.accept();
clientSocks.add(newSock); //FIXME Remove sockets when closed
Thread thread = new ClientThread(newSock, usr, psw);
thread.start();
clientThreads.add((ClientThread)thread);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
}
ClientThread.java
public class ClientThread extends Thread {
private Socket socket;
private DataInputStream inStream;
private DataOutputStream outStream;
private String dbUser;
private String dbPassword;
public ClientThread(Socket socket, String DbUser, String DbPass) {
this.socket = socket;
this.dbUser = DbUser;
this.dbPassword = DbPass;
}
#Override
public void run() {
try {
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
sendFile("a.txt");
sendFile("b.txt");
sendFile("c.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
void sendFile(String file){
try {
File f = new File(file);
outStream.writeUTF(file);
outStream.writeLong(f.length());
FileInputStream fis = new FileInputStream(f);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
outStream.write(buffer);
}
fis.close();
}catch(Exception e){
e.printStackTrace();
}
}
int getSize(byte[] buffer,long remaining){
try {
return Math.toIntExact(Math.min(((long) buffer.length), remaining));
}catch(ArithmeticException e){
return 4096;
}
}
}
CLIENT:
Main.java
class Main {
static int getSize(byte[] buffer, long remaining) {
try {
return Math.toIntExact(Math.min(((long) buffer.length), remaining));
} catch (ArithmeticException e) {
return 4096;
}
}
static void saveFile(Socket clientSock,DataInputStream dis) throws IOException {
String fileName = dis.readUTF();
File f = new File(fileName);
FileOutputStream fos = new FileOutputStream(f);
byte[] buffer = new byte[4096];
long filesize = dis.readLong();
int read = 0;
int totalRead = 0;
long remaining = filesize;
while ((read = dis.read(buffer, 0, getSize(buffer, remaining))) > 0) {
totalRead += read;
remaining -= read;
System.out.println("read " + totalRead + " bytes.");
fos.write(buffer, 0, read);
}
fos.close();
}
public static void main(String[] args) throws Exception {
Socket sock = new Socket("192.168.2.17", 9090);
DataInputStream dis = new DataInputStream(sock.getInputStream());
saveFile(sock,dis);
saveFile(sock,dis);
saveFile(sock,dis);
}
}
Many thanks in advance, looking forward to fix this :(
Fixed by changing
while (fis.read(buffer) > 0) {
outStream.write(buffer);
}
to
int count;
while ((count = fis.read(buffer)) > 0) {
outStream.write(buffer, 0, count);
}
Inside ClientThread.java on the server side
In school we have a project where we have to send a file from server to a client. The problem we have is that when we transfer the file from the server to the client, the server shutsdown the connection. Here is our code so far:
Client:
public static void main(String argv[]) throws Exception {
int port = 8888; //default
if (argv.length
> 0) {
port = Integer.parseInt(argv[0]);
}
Socket clientSocket = new Socket("127.0.0.1", port);
PrintStream outToServer = new PrintStream(
clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
File f = new File("dictionaryPart.txt");
String serverCommand = inFromServer.readLine().toLowerCase();
while (serverCommand != null) {
System.out.println(serverCommand);
switch (serverCommand) {
case "velkommen":
outToServer.println("Hej");
break;
case "file":
f = copy(clientSocket, f);
String matches = CrackerCentralized.checkFile(f);
System.out.println(matches);
outToServer.println(matches);
break;
}
serverCommand = inFromServer.readLine().toLowerCase();
}
}
public static File copy(Socket clientSocket, File f) {
try {
int filesize = 2022386;
int bytesRead;
int currentTot = 0;
byte[] buffer = new byte[filesize];
InputStream is = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(buffer, 0, buffer.length);
currentTot = bytesRead;
while (bytesRead != -1) {
bytesRead = is.read(buffer, currentTot, (buffer.length - currentTot));
if (bytesRead >= 0) {
currentTot += bytesRead;
}
}
bos.write(buffer, 0, currentTot);
bos.flush();
bos.close();
} catch (IOException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
}
return f;
}
Server:
try {
PrintStream outToClient = new PrintStream(connection.getOutputStream());
OutputStream os = connection.getOutputStream();
BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));
outToClient.println("file");
final byte[] buffer = new byte[(int) f.length()];
input.read(buffer, 0, buffer.length);
os.write(buffer, 0, buffer.length);
os.write(-1);
os.flush();
System.out.println(connection.isClosed());
os.close();
System.out.println(connection.isClosed());
} catch (IOException ex) {
Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex);
}
I am aware of WHY the connection keeps on closing. We close the socket's output by writing
output.close();
But I don't know in what other way we must try to do this to make the server keep listening for the clients answer (match/no match), so that the server knows wether it should send more files or if the client was successful.. Is it even possible to send at file without shutting down the connection to the server? I've googled all day the last 2 days without any luck
Thanks for reading and for your help.
In order to implement what you are asking, you need to establish a communication protocol that the server and client understand. Something needs to be transmitted that says, "I'm starting to send information to you," and something that says, "I'm done sending stuff." There could be more -- such as information delimiting (e.g. Mime multipart form boundary). But at a minimum, you need the start and stop tokens.
Expanding on that: Look at the code in its simplest form: server:loop{write()} -> client:loop{read()}. Closing the stream on the server-side sends the -1 value to the client, which is usually consumed as the stop signal. If you want to maintain the connection indefinitely, and write to the client at different times, something has to be sent that says, "This transaction is complete". The following is pseudo-ish code -- freehand, not compiled.
// SERVER
private Socket socket; // initialized somewhere
private static final byte[] STOP = "</COMMS>".getBytes();
public void sendData(byte[] bytes) throws IOException{
OutputStream out = socket.getOutputStream();
if(bytes != null){
out.write(bytes,0,bytes.length);
}
out.write(STOP);
} // notice we exit the method without closing the stream.
// CLIENT
private Socket socket; // initialized somewhere
private static final byte[] STOP = "</COMMS>".getBytes();
private static final int BUFFER_SIZE = 1024 << 8;
private InputStream in;
public byte[] receiveData(){
if(in == null){
in = socket.getInputStream();
}
byte[] content;
byte[] bytes = new byte[BUFFER_SIZE];
int bytesRead;
while((bytesRead = in.read(bytes)) != -1){ // normal termination
if(receivedStop(bytes,bytesRead)){ // see if stopped
removeStopBytes(bytes,bytesRead); // get rid of the STOP bytes
content = buildContent(content,bytes,bytesRead); // transfer bytes to array
break;
}
content = buildContent(content,bytes,bytesRead); // transfer bytes to array
}
return content;
}
Again, that was freehand and not compiled or tested. I'm sure it's not fully correct but hopefully you get the gist. The server writes content but never closes the stream. The client reads the stream looking for the STOP content, building up the final content until the stop is reached.
Thanks to madConan for the reply, it gave me a good idea of how to do it. I will post my code here, so others can use it in future.
SERVER CODE
public void run() {
try {
PrintStream outToClient = new PrintStream(connection.getOutputStream());
OutputStream os = connection.getOutputStream();
BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));
outToClient.println("file");
copy(input, os, f);
System.out.println(connection.isClosed());
} catch (IOException ex) {
Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void copy(final InputStream is, final OutputStream os, File f) throws IOException {
final byte[] stop = "stop".getBytes();
final byte[] buffer = new byte[(int) f.length()];
is.read(buffer, 0, buffer.length);
os.write(buffer, 0, buffer.length);
os.write(stop);
os.flush();
}
CLIENT CODE
public static File recieveData(Socket clientSocket, File f) {
try {
InputStream in = clientSocket.getInputStream();
FileOutputStream output = new FileOutputStream(f);
byte[] content;
byte[] bytes = new byte[1024 << 8];
int bytesRead;
while (true) {
if (recieveStop(f)) {
removeStop(f);
break;
}
bytesRead = in.read(bytes);
output.write(bytes, 0, bytesRead);
}
} catch (IOException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
}
return f;
}
public static boolean recieveStop(File f) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(f));
String currentLine;
String lastLine = "";
while ((currentLine = br.readLine()) != null) {
lastLine = currentLine;
}
if (lastLine.equals("stop")) {
return true;
}
} catch (FileNotFoundException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
return false;
}
public static void removeStop(File f) {
try {
RandomAccessFile raFile = new RandomAccessFile(f, "rw");
long length = raFile.length();
raFile.setLength(length - 4);
raFile.close();
} catch (FileNotFoundException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
Hope this will help others with the same problem.
I wrote some client - server program, that shares data but at server side i got EOFException after reciving data. I tried to fix it on my own but it is hard to find own errors.
The error is caused by this line: Message command =(Message) serInputStream.readObject();
Here is some output from server:
java.io.EOFException
at Java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2577)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1315)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at transfer.Serwerus.run(Serwerus.java:42)
Server code:
import java.io.*;
import java.net.*;
public class Serwerus implements Runnable
{
public InputStream is;
public FileOutputStream fos;
public BufferedOutputStream bos;
public ObjectOutputStream serOutputStream;
public ObjectInputStream serInputStream;
ServerSocket socket;
private String clientMessage, clientFileName;
private int clientFileSize;
public Serwerus()
{
try
{
socket = new ServerSocket(6060);
System.out.println("Server started....");
}
catch(IOException e)
{
System.err.println("Error: " + e);
e.printStackTrace();
}
}
#Override
public void run()
{
try
{
Socket sock = socket.accept();
System.out.println("Client accepted");
serOutputStream = new ObjectOutputStream(sock.getOutputStream());
serInputStream = new ObjectInputStream(sock.getInputStream());
while (true)
{
Message command =(Message) serInputStream.readObject();
System.out.println("after readObject");
if (command.getCommand().startsWith("FileU"))
{
System.out.println("Name = " + command.getfileName() + ", size= " + command.getfileSize());
serOutputStream.writeObject(new Message("Bring", "", 0));
//ReciveData(socket, command.getfileName(), command.getfileSize());
}
else if(command.getCommand().startsWith("Wait"))
{
System.out.println("hohoho");
ReciveData(sock, command.getfileName(), command.getfileSize());
}
else if(command.getCommand().startsWith("Quit"))
{
System.exit(1);
}
else
{
System.out.println("Unknow");
}
}
}
catch(ClassNotFoundException | IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
serInputStream.close();
serOutputStream.close();
socket.close();
}
catch (IOException e)
{
System.err.println("Fallen on closing socket.\n Error: " + e);
}
}
}
public void SendData(Socket sock, String filePath) throws Exception
{
File myFile = new File (filePath);
System.out.println("File name = " + myFile.getName() + " File len = " + (int)myFile.length());
byte [] mybytearray = new byte [(int)myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
OutputStream os = sock.getOutputStream();
System.out.println("Sending...");
os.write(mybytearray,0,mybytearray.length);
os.flush();
sock.close();
System.out.println("Sending finished");
}
public void ReciveData(Socket sock, String filePath, int fileSize)
{
System.out.println("Recive in progress, filesize = " + fileSize);
int bytesRead = 0, current = 0;
byte[] array = new byte[fileSize];
try
{
is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream(filePath);
bos = new BufferedOutputStream(fos);
do
{
System.out.println(bytesRead);
bytesRead = is.read(array);
current += bytesRead;
}
while(bytesRead > -1);
bos.write(array, 0 , current);
bos.flush();
bos.close();
fos.close();
// sock.close();
System.out.println("Reciveing finished");
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
public static void main (String [] args ) throws IOException
{
new Thread(new Serwerus()).start();
}
}
Client code:
import java.io.*;
import java.net.*;
public class Clientus implements Runnable
{
InputStream is;
FileOutputStream fos;
BufferedOutputStream bos;
ObjectOutputStream cliOutputStream;
ObjectInputStream cliInputStream;
Socket socket;
File actFile;
private String serverMessage, serverFileName;
private int serverFileSize;
public Clientus()
{
try
{
socket = new Socket("localhost", 6060);
cliOutputStream = new ObjectOutputStream(socket.getOutputStream());
cliInputStream = new ObjectInputStream(socket.getInputStream());
File file = new File(<filepath>);
actFile = file;
}
catch (Exception e)
{
System.err.println("Error: " + e);
e.printStackTrace();
}
}
#Override
public void run()
{
try
{
cliOutputStream.writeObject(new Message("FileU", actFile.getPath(), (int) actFile.length()));
cliOutputStream.flush();
//while (true)
//{
Message command =(Message) cliInputStream.readObject();
if (command.getCommand().startsWith("File"))
{
String name = command.getfileName();
int size = command.getfileSize();
System.out.println("Name = " + command.getfileName() + ", size= " + command.getfileSize());
if(size != 0 && !"".equals(name))
{
//ReciveData(socket, 0);
}
}
else if(command.getCommand().startsWith("Bring"))
{
cliOutputStream.writeObject(new Message("Wait", "D:\\KP2\\Serwer\\dupa.txt",(int) actFile.length()));
cliOutputStream.flush();
try
{
SendData(socket, actFile.getPath());
//this.socket.close();
}
catch (Exception ex)
{
System.err.println("Error with: SendData()");
}
}
else if(command.getCommand().startsWith("Quit"))
{
System.exit(1);
}
else
{
System.out.println("Command unknown");
}
//}
}
catch(ClassNotFoundException | IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
socket.close();
cliOutputStream.close();
cliInputStream.close();
}
catch (IOException e)
{
System.err.println("Fallen on closing socket.\n Error: " + e);
}
}
}
public void SendData(Socket sock, String filePath) throws Exception
{
byte [] mybytearray = new byte [(int) new File(filePath).length()];
FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
OutputStream os = sock.getOutputStream();
System.out.println("Sending...");
os.write(mybytearray,0,mybytearray.length);
fis.close();
bis.close();
os.close();
System.out.println("Sending finished");
}
public void ReciveData(Socket sock, String fileName, int fileSize)
{
int bytesRead, current = 0;
byte[] array = new byte[fileSize+1];
try
{
is = sock.getInputStream();
fos = new FileOutputStream(<file_path>);
bos = new BufferedOutputStream(fos);
bytesRead = is.read(array,0,array.length);
current = bytesRead;
do
{
bytesRead = is.read(array, current, (array.length - current));
if(bytesRead >= 0)
current += bytesRead;
}
while(bytesRead > -1);
bos.write(array, 0 , current);
bos.flush();
long end = System.currentTimeMillis();
//System.out.println("Send time: " + (end - start));
bos.close();
sock.close();
System.out.println("Reciveing finished");
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
public static void main (String [] args ) throws IOException
{
new Thread(new Clientus()).start();
}
}
Can anyone help?
Your client may be disconnected after sending data and because your server is waiting for more data, the EOFException will occurr.
To fix this problem, you can add try-catch block to catching this exception when the client disconnects.
You are using both the ObjectOutputStream and the socket's own OutputStream to send data on, and you are getting out of sync. When you send the raw data directly over the socket you aren't sending the length first, so the receiver doesn't know how many bytes belong to this transmission. In fact it just reads everything until EOS, so next time you call ObjectInputStream.readObject() it naturally gets an EOFException. To fix this:
Use the ObjectInputStream and ObjectOutputStream for everything.
Before sending the file, send its length, via writeLong().
At the receiver, when receiving the file, first get its length, via readLong(), then read exactly that many bytes from the ObjectInputStream and copy them to the file.