I am making an android application that should send and receive some json files through a wifi direct connection (whenever another device is connected, they both trade all their json files).
This question is mostly about what would be the best practice, since I am fairly new both to android and java.
When a wifi direct connection is established one of the two devices (the group owner) becomes the server and opens a server socket; the other connects to said socket and sends one single json file to the server.
I want the client to send all his json files and then receive all the json files from the server, and I'm wondering how it should be done: how do I tell one file is over? Should I send the lenght of the file ahead, or make the client wait for an acknowledgement for when the server is done reading?
Can I signal "End of Data" (by closing the OutputStream?) to stop the reading loop on the receiving end and then start sending another file?
To have some context, this is currently the code I'm using:
Client side
#Override
protected String doInBackground(Void... params) {
Socket socket = new Socket();
try {
Log.d(TAG, "Opening client socket - ");
socket.bind(null);
socket.connect((new InetSocketAddress(mHost, Constants.PORT)), SOCKET_TIMEOUT);
Log.d(TAG, "Client socket - " + socket.isConnected());
OutputStream stream = socket.getOutputStream();
//There is only one file, so the loop here runs only once
File dir = Utils.graffitiDir(context);
for (File tmp : dir.listFiles()) {
FileInputStream in = new FileInputStream(tmp);
Utils.copyFileInOut(in, stream);
}
Log.d(TAG, "Client: Data written");
return "ok";
} catch (IOException e) {
Log.e(TAG, e.getMessage());
return null;
}
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
// Give up
e.printStackTrace();
}
}
}
}
}
Server side
#Override
protected String doInBackground(Void... params) {
try {
ServerSocket serverSocket = new ServerSocket(Constants.PORT);
byte buf[] = new byte[4];
String res;
Log.d(TAG, "Server: Socket opened");
Socket client = serverSocket.accept();
Log.d(TAG, "Server: connection done");
File f = new File(context.getFilesDir(), Constants.DIRECTORY);
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
File newf = new File(f, Calendar.getInstance().getTime().toString());
Log.d(TAG, "server: copying files " + f.toString());
InputStream inputstream = client.getInputStream();
//copyFile(inputstream);
Utils.copyFileInOut(inputstream, new FileOutputStream(newf));
serverSocket.close();
return newf.getAbsolutePath();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
return null;
}
}
The copyFileInOut function:
public static boolean copyFileInOut(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
Log.d("copyfile", "I'm writing");
}
out.close();
inputStream.close();
long endTime=System.currentTimeMillis()-startTime;
Log.d("copyfile", "Time taken to transfer all bytes is : " + endTime);
} catch (IOException e) {
Log.d(TAG, e.toString());
return false;
}
return true;
}
As a sidenote, I've seen a couple of similar questions (Sending and receiving files on socket) where the answer suggested to send the length of the file ahead, but I feel like my situation is a bit different, and I don't have the necessary experience to find out what is the best solution. I apologize if this is an obvious question, but I couldn't find an answer by myself.
In your case you should
1. send the number of files you are going to send first,
2. then send length of a file and that file. repeat for all files.
after this the server can also use the same order of sending number of files, the size of a file, that file repeat for all files.
Related
My goal here is to make a simple HTTP proxy that can perform GET/POST requests, trying to learn about Java Sockets. Would be appreciated if anyone can point me in that direction.
// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples
import java.io.*;
import java.net.*;
/**
* This class implements a simple single-threaded proxy server.
**/
public class SimpleProxyServer {
/** The main method parses arguments and passes them to runServer */
public static void main(String[] args) throws IOException {
try {
// Check the number of arguments
if (args.length != 3)
throw new IllegalArgumentException("Wrong number of arguments.");
// Get the command-line arguments: the host and port we are proxy for
// and the local port that we listen for connections on
String host = args[0];
int remoteport = Integer.parseInt(args[1]);
int localport = Integer.parseInt(args[2]);
// Print a start-up message
System.out.println("Starting proxy for " + host + ":" + remoteport +
" on port " + localport);
// And start running the server
runServer(host, remoteport, localport); // never returns
}
catch (Exception e) {
System.err.println(e);
System.err.println("Usage: java SimpleProxyServer " +
"<host> <remoteport> <localport>");
}
}
/**
* This method runs a single-threaded proxy server for
* host:remoteport on the specified local port. It never returns.
**/
public static void runServer(String host, int remoteport, int localport)
throws IOException {
// Create a ServerSocket to listen for connections with
ServerSocket ss = new ServerSocket(localport);
// Create buffers for client-to-server and server-to-client communication.
// We make one final so it can be used in an anonymous class below.
// Note the assumptions about the volume of traffic in each direction...
final byte[] request = new byte[1024];
byte[] reply = new byte[4096];
// This is a server that never returns, so enter an infinite loop.
while(true) {
// Variables to hold the sockets to the client and to the server.
Socket client = null, server = null;
try {
// Wait for a connection on the local port
client = ss.accept();
// Get client streams. Make them final so they can
// be used in the anonymous thread below.
final InputStream from_client = client.getInputStream();
final OutputStream to_client= client.getOutputStream();
// Make a connection to the real server
// If we cannot connect to the server, send an error to the
// client, disconnect, then continue waiting for another connection.
try { server = new Socket(host, remoteport); }
catch (IOException e) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(to_client));
out.println("Proxy server cannot connect to " + host + ":" +
remoteport + ":\n" + e);
out.flush();
client.close();
continue;
}
// Get server streams.
final InputStream from_server = server.getInputStream();
final OutputStream to_server = server.getOutputStream();
// Make a thread to read the client's requests and pass them to the
// server. We have to use a separate thread because requests and
// responses may be asynchronous.
Thread t = new Thread() {
public void run() {
int bytes_read;
try {
while((bytes_read = from_client.read(request)) != -1) {
to_server.write(request, 0, bytes_read);
to_server.flush();
}
}
catch (IOException e) {}
// the client closed the connection to us, so close our
// connection to the server. This will also cause the
// server-to-client loop in the main thread exit.
try {to_server.close();} catch (IOException e) {}
}
};
// Start the client-to-server request thread running
t.start();
// Meanwhile, in the main thread, read the server's responses
// and pass them back to the client. This will be done in
// parallel with the client-to-server request thread above.
int bytes_read;
try {
while((bytes_read = from_server.read(reply)) != -1) {
to_client.write(reply, 0, bytes_read);
to_client.flush();
}
}
catch(IOException e) {}
// The server closed its connection to us, so close our
// connection to our client. This will make the other thread exit.
to_client.close();
}
catch (IOException e) { System.err.println(e); }
// Close the sockets no matter what happens each time through the loop.
finally {
try {
if (server != null) server.close();
if (client != null) client.close();
}
catch(IOException e) {}
}
}
}
}
Code obtained from http://examples.oreilly.com/jenut/SimpleProxyServer.java
I was wondering how I would be able to extract the HOSTNAME from the inputstream and use that information extracted to pass to the method below.
try { server = new Socket(host, remoteport); }
catch (IOException e) {
PrintWriter out = new PrintWriter(new OutputStreamWriter(to_client));
out.println("Proxy server cannot connect to " + host + ":" +
remoteport + ":\n" + e);
out.flush();
client.close();
continue;
}
I've tried creating a method that converts the InputStream into a String format but it seems to make the program get stuck after assigning it to the variable. (Tried something like this over here - Read/convert an InputStream to a String)
You can create a separate ByteArrayOutputStream to get the information from the InputStream.
...
final OutputStream to_client= client.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
...
And then in the while loop you can write to baos as well
...
while((bytes_read = from_server.read(reply)) != -1) {
to_client.write(reply, 0, bytes_read);
to_client.flush();
baos.write(reply, 0, bytes_read);
}
baos.flush();
...
And you can finally get the string from baos.
String requestString = new String(baos.toByteArray());
Then, you can search the Host header by doing this:
String[] headers = requestString.split("\n");
for (int i = 0; i < headers.length; i++) {
if (headers[i].startsWith("Host")) {
String[] hostHeader = headers[i].split(":");
if (hostHeader.length > 1) {
host = hostHeader[1];
}
}
}
I'm new to Java socket programming and I am doing a basic socket communication between an Android client and a Java server on the PC side. The server could receive the message from the client, but the client seems to have trouble reading messages from the server. I've been wondering why this is happening.
Server:
while(true){
try {
socket = serverSocket.accept();
dataInputStream = new DataInputStream(socket.getInputStream());
System.out.println("ip: " + socket.getInetAddress());
System.out.println("message: " + dataInputStream.readUTF());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Hello Client !!!!!!" + "\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
...
if (socket != null){
try{
socket.close();
socket = null;
}
catch(Exception e){
e.printStackTrace();
}
}
}
Client:
socket = new Socket(serverIP, 8080);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(textOut.getText().toString());
dataInputStream = new DataInputStream(socket.getInputStream());
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
Log.i(TAG, dataInputStream.readUTF());
textIn.setText(dataInputStream.readUTF());
}
catch (Exception e) {
e.printStackTrace();
}
}
});
On server side everything works fine but the Android client just can't receive the data. readUTF does not return anything (also returns a W/System.err in the logcat)
Solution:
I finally resolved the problem by moving the dataInputStream.readUTF() out of the runOnUIThread section. eg. Store it in a temporary string before runOnUiThread. I guess this should be a noob mistake.
Also calling readUTF() in a row was definitely stupid enough.
the Android client just can't receive the data
Your client tries to read two messages, but only one is sent.
Also your server never closes the connection.
I'm trying to create a socket listener to a device that requires an acknowledgement before it sends the next set of data to the server. I'm able to send the acknowledgement but by the time a new connection is created and as a result I lose data. I have pasted my code below.
public void run() {
try {
servSoc = new ServerSocket(this.port);
File file = new File("logs.txt");
// creates the file
Socket server = null;
//FileWriter writer = new FileWriter(file);
while (true) {
try {
System.out.println("Waiting for client on port "
+ servSoc.getLocalPort() + "...");
server = servSoc.accept();
System.out.println("Just connected to "
+ server.getRemoteSocketAddress());
InputStreamReader in = new InputStreamReader(server.getInputStream());
//InputStreamReader in = new InputStreamReader(server.getInputStream());
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
new Thread(new LogWriter(in, out)).start();
// Writes the content to the file
if (servSoc.isClosed()) {
System.out.println("Connection closed....");
servSoc.close();
}
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
s.printStackTrace();
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
} catch (IOException ex) {
java.util.logging.Logger.getLogger(SenselSocketListner.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
} finally {
}
}
public static void main(String args[]) {
int port = 8294;
Thread t = new SenselSocketListner(port);
t.start();
}
My log writer thread is given below.
public class LogWriter implements Runnable {
InputStreamReader in;
DataOutputStream out;
public LogWriter(InputStreamReader in, DataOutputStream out) {
this.in = in;
this.out = out;
}
#Override
public void run() {
try {
File file = new File("logs.txt");
// creates the file
if (!file.exists()) {
System.out.println("Creating File");
file.createNewFile();
}
String inputLine = null;
BufferedReader input = new BufferedReader(in);
System.out.println("Writing data....");
while ((inputLine = input.readLine()) != null) {
//System.out.println("Test");
System.out.println("Sending Acknowledgement....");
out.writeUTF("Upload successful");
out.writeUTF("Ok");
FileWriter fstream = new FileWriter(file, true);
BufferedWriter fbw = new BufferedWriter(fstream);
fbw.write(inputLine);
fbw.newLine();
fbw.flush();
fbw.close();
}
//DataOutputStream out =
//new DataOutputStream(server.getOutputStream());
//out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress() + "\nGoodbye!");
//server.close();
} catch (IOException ex) {
Logger.getLogger(LogWriter.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
}
Person concerned with the device suggested that I might not be sending the acknowledgement fast enough. Please help me to find a way to speed this up, I have notices a delay after the statement "System.out.println("Writing data....");" in the log writer.
Does the device really understand the result of writeUTF()? Unless it is implemented in Java it is highly unlikely. You should surely just be writing the bytes or chars of the message directly.
Other notes:
Creating a new log file per line is wasting time. Open the file before the read loop, and close it afterw the loop.
Closing the server socket if it's already closed doesn't make sense.
You should close the accepted socket when readLine() returns null, in the reading thread.
The while loop in run in LogWriter traps your app until the socket is closed. If you need to converse on a socket, you'll have to know what to expect - as defined by a protocol. If it is one line, just read one line. If it is a text file, you'll have to devise a protocol that informs you about the number of bytes to expect.
Also, logging should be done on a single open log file, without close after each line.
I have written a small Client/Server Program which already worked once but after adding Threads and some real input Data to it, i always get a closed Socket before being able to read the Object (the String). The Program always Prints "Client has already closed Connection!" from Function handleConnection in the ProcessDataThread.
ClientCode:
synchronized private static void sendToServer(){
Socket clientSocket = null;
BufferedOutputStream socketOut = null;
ObjectOutputStream out = null;
try{
String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";
Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);
//TODO load these from file
clientSocket = new Socket( "10.0.2.2", 7777);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
}catch(Exception ex){
Log.e(TAG, "Could not write File to Server.", ex);
}
finally{
try{
if(clientSocket != null){
clientSocket.close();
}
if(out != null){
out.close();
}
}catch(IOException ex){
Log.e(TAG, "Could not close Socket.");
}
}
}
ServerCode:
ReceiverThread:
public void run()
{
try {
ServerSocket server = new ServerSocket(port);
//Only block for 10 Seconds and try again
server.setSoTimeout(10000);
while(!server.isClosed() && !stopped){
//Run
Socket client = null;
try
{
client = server.accept();
System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
new ProcessDataThread(client).start();
}
catch( SocketTimeoutException tx){
//nothing
}
catch ( IOException e ) {
e.printStackTrace();
}
finally {
if ( client != null )
try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
ProcessDataThread:
public class ProcessDataThread extends Thread {
Socket client;
public ProcessDataThread(Socket sock) {
// xmlToProcess = xmlString;
this.client = sock;
}
private String handleConnection() {
BufferedInputStream socketIn = null;
ObjectInputStream in = null;
String xmlToProcess = null;
try {
if(!client.isClosed()){
System.out.println("Trying to read from Stream;");
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
}else{
System.out.println("Client has already closed Connection!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if(client != null){
client.close();
}
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
return xmlToProcess;
}
#Override
public void run() {
String xmlToProcess = handleConnection();
if (xmlToProcess == null || xmlToProcess.isEmpty()) {
// Es konnte kein String vom Client gelesen werden.
return;
}
System.out.println(xmlToProcess);
}
}
I made some changes with jboi's Suggestions. This is what i got now. The error stays the same. I don't even get to reading the Stream in the Server because client.getClosed()
is always true!
In the Client Code:
clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();
in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
//Wait for the Server to Close the Connection
}
In the Server Code
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();
It is very probable that your client has closed the socket in the finally block before the server was able to read the data.
In your clients finally block you should use socket.shutdownOutput, then read on the client all incoming data till EOF and then close the socket.
On your server you read till EOF and then send an object as kind of acknowledge, e.g. Number of bytes in the message. You also end the send with socket.shutdownOutput() as you've done at the client. This puts again an EOF at the end of the data. This EOF is received by the client and it will finally close the socket.
The issue seems to be the client and server are unable to identify each others state:
Client sending data to server, where server has closed the connection
Server sending/reading data to client , where client has closed the connection
Either are unable to coordinate with each other, solutions could be to establish a proper state machine. Some examples in Google if you search for (client and server state machine) gives mathematically definite state machine examples for your application: hope this comment helps.
Hence it's not useful to look into this problem in solution perspective and probably start using protocols in place like : telnet etc .
Ok now i'm feeling stupid.
I closed the Socket inside the Server Code myself.
After accepting a connection the following is executed inside the finally Block:
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
The reason that there is this finally Block was because i didn't use Threads before so the ReceiverThread also did handle the Connection and therefore close the socket after using it.
I then moved the code to the new Thread and forgot to remove that finally block!
You can't use a buffered input stream and another kind of stream on the same socket. The buffered stream will steal data from the other one. Make up your mind. The ObjectInputStream will do everything you need. Just use that.
EDIT Re your edit, 'socket closed' means that you closed your socket and then continued to use it.
I want to send more than one image file from client to server for this I write the code in my application, but it will send only one image.
In client application one frame is there and in server application also there is a frame to start/stop the server.
One more problem is there when Client application send the image file then this image file shown on server computer but when I try to open this image file then nothing is there but when I close server application(server frame) then I am able to see the image.
code:
client site:
public void sendPhotoToServer(String str){ // str is image location
try {
InputStream input = new FileInputStream(str);
byte[] buffer=new byte[1024];
int readData;
while((readData=input.read(buffer))!=-1){
dos.write(buffer,0,readData); // dos is DataOutputStream
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
In server side this code is running into thread:
public void run() {
while (true) {
try {
byte[] buffer = new byte[8192];
fis = new FileOutputStream("C:\\"+(s1++)+".jpg"); // fis is FileOutputStream
while ((count = in.read(buffer)) > 0){ //count is a integer and 'in' is InputStream
fis.write(buffer, 0, count);
fis.flush();
}
} catch (Exception e) {}
}
}
Problem:
only 1st image is copying which is send by the client.
I am able to see this Image only when I close the server application.
no exception is there and i call sendPhotoToServer method in other class consecutively to send all the image file as:
if (photoSourcePath != null) {
clientClass.sendPhotoToServer(photoSourcePath+"\\"+rowData.get(5));
}
Your server side should stop the thread when its job is done. The while loop just keeps running forever and keeps the stream open (that's why you see the image when you shut down the server, the threads only stops then).
Try changing the server side to this:
public void run() {
boolean processing = true;
while (processing) {
try {
byte[] buffer = new byte[8192];
fis = new FileOutputStream("C:\\" + (s1++) + ".jpg"); // fis is
// FileOutputStream
while ((count = in.read(buffer)) > 0) { // count is a integer
// and 'in' is
// InputStream
fis.write(buffer, 0, count);
fis.flush();
}
processing = false;
} catch (Exception e) {
processing = false;
}
}
}