Following my last thread on socket programming, i have made some very good progress.
But there are still some chronic obstacles hindering me, even though these questions are raised and discussed (on the internet) for the server side, how to solve the client side mirror problem is not mentioned.
If a client is trying to connect to server, every one agrees that you need an algorithm that has to search for available ports on the server side. http://stackoverflow.com/questions/2675362/how-to-find-an-available-port One of the solutions is specifying the port number as "Zero", which then returns an available port. But this done in real time, as a Stack Overflow poster pointed out:
private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
try (
ServerSocket socket = new ServerSocket(0);
) {
return socket.getLocalPort();
}
}If you need to find an open port on a specific interface check ServerSocket documentation for alternative constructors.
Warning: Any code using the port number returned by this method is subject to a race condition - a different process / thread may bind to the same port immediately after we close the ServerSocket instance.
But a bigger problem (which was not treated in the thread nor anywhere else i could find), is that, since the client has to supply the same port number, thus the client has to know before hand what the server's algorithm is searches in real-time while the client is already running!!! How is that possible.
I know there is a robust, viable and simple solution in use (otherwise the world would not work), but no one mentions it any where i could find
The only other solution I could think of is supplying the client side also with "Zero", but when I tried that, the server still kept waiting - no connection
How can i solve this? I would like to use "zero" as I can't guarantee any port i specify otherwise is not bound to a process already, yet I can't know what to port to supply at client side before hand
Even if I tried other solutions like iterating through specified ports to find available ports (at run-time), I am faced with exactly the same problem : the client doesn't know the port before hand, so it can't be included in the client code
Below is the complete Server and Client code
Client side first (android platform)
public class FSendfileActivity extends Activity {
private static final int SELECT_PICTURE = 1;
private String serverIP = "192.168.1.2";
private String selectedImagePath;
private ImageView img;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fsendfile);
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);
}
});
;
Button send = (Button) findViewById(R.id.bSend);
final TextView status = (TextView) findViewById(R.id.tvStatus);
final String qcd = "qcd";
Log.v(qcd, " -------- start 37 **-------");
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Log.v(qcd, " 00");
// Socket sock;
Log.v(qcd, " 01");
new Thread(new Runnable() {
@Override
public void run() {
Socket sock;
try {
Log.v(qcd, " 02");
sock = new Socket(serverIP, 0);
Log.v(qcd, " 03");
System.out.println("Connecting...");
// sendfile
File myFile = new File (selectedImagePath);
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();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
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);
}
}
^
Server side code (pure Java, NOT Android platform)
Adjust int filesize=550000; to the size of the image you will select
public class FileServer {
public static void main(String[] args) throws IOException {
int filesize=550000; // filesize temporary hardcoded
long start = System.currentTimeMillis();
int bytesRead;
int current = 0;
ServerSocket servsock = new ServerSocket(0);
InetAddress IP=InetAddress.getLocalHost();
System.out.println("IP "+IP.getHostAddress()+" ***%% :"+servsock.getLocalPort());
while (true) {
System.out.println("Waiting...");
Socket sock = servsock.accept();
System.out.println("Accepted connection : " + sock);
// receive file
byte [] mybytearray = new byte [filesize];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("C:\\myRoot_folder\\image000028.jpg"); // destination path and name of file
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bos.write(mybytearray, 0 , current);
bos.flush();
long end = System.currentTimeMillis();
System.out.println(end-start);
bos.close();
sock.close();
servsock.close();
}
}
}
^
xml layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tvStatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/tvPath"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Path: " />
<Button
android:id="@+id/bBrowse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Browse" >
</Button>
<Button
android:id="@+id/bSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send" />
<ImageView
android:id="@+id/ivPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ImageView>
</LinearLayout>
^
add to Androidmanifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
output
IP 192.168.1.2 ***%% :53240
Waiting...