我已经构建了一个小型的android测试tcp客户端,它连接到Ip,发送 hello world ,并定期发送日期时间。
为了测试这个,我使用 netcat 作为服务器,方式如下:
nc -l 5000
客户端通过套接字连接到服务器,日期时间正确地显示在 netcat 屏幕上,使用wifi或3g网络。
如果以3g启动应用程序并让应用程序在一小段时间(一秒间隔)内发送日期时间并更改为wifi网络,我将获得 EHOSTUNREACH 以获取与我的服务器IP的所有连接,由tcp客户端应用程序或任何其他应用程序在任何端口(例如浏览器)上制作,但仅在发生错误的wifi网络中。
如果我更改为3g或另一个wifi网络没有返回错误,但如果我回到该wifi网络,我会再次收到错误。并保持这种方式,直到我重新启动手机或让Android独立约30分钟。
仅在某些网络中发生这种情况,并且只有在数据发送周期很短的情况下,每次更改时才会发生1秒间隔或更短时间,如果周期为5秒,则每4-5次更改发生1次。
客户端代码如下
private void test(){
AsyncTask<Void,Void,Void> task = new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
int iterador = 0;
try {
if(mSocket!= null && !mSocket.isClosed()){
mSocket.close();
}
if(waitNetworkConnection(getApplicationContext(), 3))
{
mSocket = new Socket(Proxy.NO_PROXY);
mSocket.setReuseAddress(false);
mSocket.setSoTimeout(100);
mSocket.setTcpNoDelay(false);//false seems to work better
mSocket.setKeepAlive(false);
mSocket.setSoLinger(false, 5);
mSocket.setOOBInline(false);
mSocket.connect(new InetSocketAddress("xxx.xxx.xxx", 5000));
PrintWriter out;
OutputStream stream = mSocket.getOutputStream();
OutputStreamWriter outputStream = new OutputStreamWriter(stream);
BufferedWriter buff = new BufferedWriter(outputStream);
out = new PrintWriter(buff, true);
out.println("hello");
out.println("world");
Date date;
do {
try {
Thread.sleep(200);
if(out.checkError() || mSocket.isOutputShutdown())
{
System.out.println("some error has happed let's close the socket");
try {
mSocket.shutdownOutput();
}
catch(Exception e){}
try {
mSocket.shutdownInput();
}
catch(Exception e){}
try {
mSocket.close();
}
catch(Exception e){}
}else
{
if(waitNetworkConnection(getApplicationContext(), 3))
{
if(iterador > 10*5)
{
Thread.sleep(5000);
}
date = new Date();
String msg = "["+String.valueOf(iterador)+"] keeping connection at "+date.toString();
System.out.println("Sending: " + msg);
out.println(msg);
out.flush();
iterador++;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}while(!mSocket.isClosed());
}
}
catch(Exception se){
String err = se.getMessage();
if(null == err){
err = se.toString();
}
System.out.println(err);
}
System.out.println("Socket closed");
new Handler(getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
test();
}
}, 5000);
return null;
}
};
task.execute();
}
public static boolean waitNetworkConnection(Context context, int retries) throws InterruptedException {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = getNetworkToTest(cm);
if (ni == null || !ni.isConnected()) {
// sleep a short while to allow system to switch connecting networks.
Thread.sleep(1000);
int counter = 0;
while (counter < retries && (ni == null || (ni.isAvailable() &&
!ni.isConnected()))) {
Thread.sleep(500);
ni = getNetworkToTest(cm);
counter++;
}
}
return (cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnected());
}
private static NetworkInfo getNetworkToTest(ConnectivityManager cm) {
NetworkInfo[] nis = cm.getAllNetworkInfo();
NetworkInfo ni = cm.getActiveNetworkInfo();
for (int i = 0; i < nis.length; i++) {
if (nis[i].getType() == ConnectivityManager.TYPE_WIFI && nis[i].isAvailable()) {
ni = nis[i];
return(ni);
}
}
return(ni);
}
测试在Samsumg galaxy S3(android 4.1.2)和Samsung Galaxy S2(android 4.1.2)上进行的测试。 路由器发生这种情况的一个网络是D-link 802.11g / 2.4GHz