I am trying to send data over TCP/IP in Android using AsynchronousSocketChannel but I am getting android.os.NetworkOnMainThreadException.
When I run my program and attempt to connect to server, the failed method of connect CompletionHandler is executed giving a NetworkOnMainThreadException
In Boost.Asio we run io_context in separate thread. What we need to be done in AsynchronousSocketChannel to run it on separate thread?
Ethernet.java :
public class Ethernet {
private String ip;
private int port;
private Queue<String> recvDataQueue, sendDataQueue;
private InetSocketAddress address;
private String readData;
private InputStream in;
private OutputStream out;
private AsynchronousSocketChannel socket;
private boolean socketAlive, connectionInProgress;
private ByteBuffer readBuffer, sendBuffer;
Ethernet(String ip, int port) {
if (port > 65535 && port < 1024)
port = 6666;
this.ip = ip;
this.port = port;
this.socketAlive = false;
connectionInProgress = false;
address = new InetSocketAddress(ip, port);
this.readBuffer = ByteBuffer.allocate(8192);
}
public boolean connect(){
try{
if(this.socketAlive)
return false;
connectionInProgress = true;
this.socket = AsynchronousSocketChannel.open();
this.socket.connect(this.address, null,
new CompletionHandler<Void, Object>() {
#Override
public void completed(Void result, Object attachment) {
socketAlive = true;
//connectionInProgress = false;
}
#Override
public void failed(Throwable e, Object attachment) {
socketAlive = false;
//connectionInProgress = false;
}
});
return true;
}
catch (Exception e){
String strErr = e.getMessage();
Log.e("Exception", strErr);
}
return false;
}
public long sendData(String writeData){
try{
//this.sendBuffer = ByteBuffer.allocateDirect(writeData.length());
this.sendBuffer = ByteBuffer.wrap(writeData.getBytes(), 0, writeData.length());
//this.socket.write(writeBuffer, 0, writeData.length()), null,
this.socket.write(this.sendBuffer, null,
new CompletionHandler <Integer, Object>() {
#Override
public void completed(Integer result, Object attachment) {
if (result < 0) {
// handle unexpected connection close
socketAlive = false;
//connectionInProgress = false;
}
else if(result < sendBuffer.remaining()){
// got all data, process the buffer
sendBuffer.compact();
socket.write(sendBuffer, null, this); //Test
}
else{
}
}
#Override
public void failed(Throwable e, Object attachment) {
if(socket.isOpen()){
try{
socketAlive = false;
socket.close();
}
catch (Exception ex){
String strErr = e.getMessage();
Log.e("Exception", strErr);
}
}
}
});
}
catch (Exception e){
String strErr = e.getMessage();
Log.e("Exception", strErr);
}
return -1;
}
private void recieveDataSocket() throws Exception {
this.socket.read(this.readBuffer, null, new CompletionHandler<Integer, Object>() {
#Override
public void completed(Integer result, Object attachment) {
if (result < 0) {
socketAlive = false;
}
else {
//recvQueue.add(readBuffer.toString());
}
}
#Override
public void failed(Throwable e, Object attachment) {
if(socketAlive && socket.isOpen()) {
try {
socketAlive = false;
//connectionInProgress = false;
socket.close();
}
catch (final Exception ex){
}
}
}
});
}
public void disconnect(){
try {
if(this.socket.isOpen() && this.socketAlive)
this.socket.close();
}
catch (final Exception ex){
String strErr = ex.getMessage();
Log.e("Exception", strErr);
}
}
}
}
MainActivity.java
Ethernet eth = new Ethernet("192.168.1.22", 6666);
while(true) {
if(!eth.isSocketAlive() && !eth.isConnectionInProgress())
eth.connect();
if(!eth.isSocketAlive())
continue;
eth.sendData("Hello, World!!!\n");
eth.disconnect();
}
AsynchronousSocketChannel uses SocketChannel in non-blocking mode, but Android doesn't check the blocking mode of a channel. Here is some explanation: https://stackoverflow.com/a/52458658/7115065
You should update StrictMode to ignore this exception. I would do it the following way, similar to built-in allowThreadDiskWrites() method.
StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(oldPolicy).permitNetwork().build());
// ... code
StrictMode.setThreadPolicy(oldPolicy);
Related
I am using Network Service Discovery service to discovery peer and connected to them using socket so , so socket created successfully but i am not able to send message or receive message so below is my code
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private NSDHelper mNsdHelper;
private int port;
private Context mContext;
ChatConnection mConnection;
private Button mDiscover, advertise_btn, connect_btn;
private Handler mUpdateHandler;
private TextView mStatusView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStatusView = (TextView) findViewById(R.id.status);
mContext = MainActivity.this;
mUpdateHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String chatLine = msg.getData().getString("msg");
addChatLine(chatLine);
}
};
mConnection = new ChatConnection(mUpdateHandler);
mNsdHelper = new NSDHelper(this);
mNsdHelper.initNSD();
advertise_btn = (Button) findViewById(R.id.advertise_btn);
connect_btn = (Button) findViewById(R.id.connect_btn);
advertise_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Register service
if (mConnection.getLocalPort() > -1) {
mNsdHelper.registerService(mConnection.getLocalPort());
} else {
Log.d(TAG, "ServerSocket isn't bound.");
}
}
});
connect_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
NsdServiceInfo service = mNsdHelper.getChosenServiceInfo();
if (service != null) {
Log.d(TAG, "Connecting.");
mConnection.connectToServer(service.getHost(),
service.getPort());
} else {
Log.d(TAG, "No service to connect to!");
}
}
});
mDiscover = (Button) findViewById(R.id.discover_btn);
mDiscover.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mNsdHelper.discoverServices();
}
});
}
public void clickSend(View v) {
EditText messageView = (EditText) this.findViewById(R.id.chatInput);
if (messageView != null) {
String messageString = messageView.getText().toString();
if (!messageString.isEmpty()) {
mConnection.sendMessage(messageString);
}
messageView.setText("");
}
}
public void addChatLine(String line) {
mStatusView.append("\n" + line);
}
#Override
protected void onPause() {
if (mNsdHelper != null) {
mNsdHelper.stopDiscovery();
}
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
if (mNsdHelper != null) {
mNsdHelper.discoverServices();
}
}
#Override
protected void onDestroy() {
mNsdHelper.tearDown();
mConnection.tearDown();
super.onDestroy();
}
}
ChatConnection
public class ChatConnection {
private Handler mUpdateHandler;
private ChatServer mChatServer;
private ChatClient mChatClient;
private static final String TAG = "ChatConnection";
private Socket mSocket;
private int mPort = -1;
public ChatConnection(Handler handler) {
mUpdateHandler = handler;
mChatServer = new ChatServer(handler);
}
public void tearDown() {
mChatServer.tearDown();
mChatClient.tearDown();
}
public void connectToServer(InetAddress address, int port) {
mChatClient = new ChatClient(address, port);
}
public void sendMessage(String msg) {
if (mChatClient != null) {
mChatClient.sendMessage(msg);
}
}
public int getLocalPort() {
return mPort;
}
public void setLocalPort(int port) {
mPort = port;
}
public synchronized void updateMessages(String msg, boolean local) {
Log.e(TAG, "Updating message: " + msg);
if (local) {
msg = "me: " + msg;
} else {
msg = "them: " + msg;
}
Bundle messageBundle = new Bundle();
messageBundle.putString("msg", msg);
Message message = new Message();
message.setData(messageBundle);
mUpdateHandler.sendMessage(message);
}
private synchronized void setSocket(Socket socket) {
Log.d(TAG, "setSocket being called.");
if (socket == null) {
Log.d(TAG, "Setting a null socket.");
}
if (mSocket != null) {
if (mSocket.isConnected()) {
try {
mSocket.close();
} catch (IOException e) {
// TODO(alexlucas): Auto-generated catch block
e.printStackTrace();
}
}
}
mSocket = socket;
}
private Socket getSocket() {
return mSocket;
}
private class ChatServer {
ServerSocket mServerSocket = null;
Thread mThread = null;
public ChatServer(Handler handler) {
mThread = new Thread(new ServerThread());
mThread.start();
}
public void tearDown() {
mThread.interrupt();
try {
mServerSocket.close();
} catch (IOException ioe) {
Log.e(TAG, "Error when closing server socket.");
}
}
class ServerThread implements Runnable {
#Override
public void run() {
try {
// Since discovery will happen via Nsd, we don't need to care which port is
// used. Just grab an available one and advertise it via Nsd.
mServerSocket = new ServerSocket(0);
setLocalPort(mServerSocket.getLocalPort());
while (!Thread.currentThread().isInterrupted()) {
Log.d(TAG, "ServerSocket Created, awaiting connection");
setSocket(mServerSocket.accept());
Log.d(TAG, "Connected.");
if (mChatClient == null) {
int port = mSocket.getPort();
InetAddress address = mSocket.getInetAddress();
connectToServer(address, port);
}
}
} catch (IOException e) {
Log.e(TAG, "Error creating ServerSocket: ", e);
e.printStackTrace();
}
}
}
}
private class ChatClient {
private InetAddress mAddress;
private int PORT;
private final String CLIENT_TAG = "ChatClient";
private Thread mSendThread;
private Thread mRecThread;
public ChatClient(InetAddress address, int port) {
Log.d(CLIENT_TAG, "Creating chatClient");
this.mAddress = address;
this.PORT = port;
mSendThread = new Thread(new SendingThread());
mSendThread.start();
}
class SendingThread implements Runnable {
BlockingQueue<String> mMessageQueue;
private int QUEUE_CAPACITY = 10;
public SendingThread() {
mMessageQueue = new ArrayBlockingQueue<String>(QUEUE_CAPACITY);
}
#Override
public void run() {
try {
if (getSocket() == null) {
setSocket(new Socket(mAddress, PORT));
Log.d(CLIENT_TAG, "Client-side socket initialized.");
} else {
Log.d(CLIENT_TAG, "Socket already initialized. skipping!");
}
mRecThread = new Thread(new ReceivingThread());
mRecThread.start();
} catch (UnknownHostException e) {
Log.d(CLIENT_TAG, "Initializing socket failed, UHE", e);
} catch (IOException e) {
Log.d(CLIENT_TAG, "Initializing socket failed, IOE.", e);
}
while (true) {
try {
String msg = mMessageQueue.take();
sendMessage(msg);
} catch (InterruptedException ie) {
Log.d(CLIENT_TAG, "Message sending loop interrupted, exiting");
}
}
}
}
class ReceivingThread implements Runnable {
#Override
public void run() {
BufferedReader input;
try {
input = new BufferedReader(new InputStreamReader(
mSocket.getInputStream()));
while (!Thread.currentThread().isInterrupted()) {
String messageStr = null;
messageStr = input.readLine();
if (messageStr != null) {
Log.d(CLIENT_TAG, "Read from the stream: " + messageStr);
updateMessages(messageStr, false);
} else {
Log.d(CLIENT_TAG, "The nulls! The nulls!");
break;
}
}
input.close();
} catch (IOException e) {
Log.e(CLIENT_TAG, "Server loop error: ", e);
}
}
}
public void tearDown() {
try {
getSocket().close();
} catch (IOException ioe) {
Log.e(CLIENT_TAG, "Error when closing server socket.");
}
}
public void sendMessage(String msg) {
try {
Socket socket = getSocket();
if (socket == null) {
Log.d(CLIENT_TAG, "Socket is null, wtf?");
} else if (socket.getOutputStream() == null) {
Log.d(CLIENT_TAG, "Socket output stream is null, wtf?");
}
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(getSocket().getOutputStream())), true);
out.println(msg);
out.flush();
updateMessages(msg, true);
} catch (UnknownHostException e) {
Log.d(CLIENT_TAG, "Unknown Host", e);
} catch (IOException e) {
Log.d(CLIENT_TAG, "I/O Exception", e);
} catch (Exception e) {
Log.d(CLIENT_TAG, "Error3", e);
}
Log.d(CLIENT_TAG, "Client sent message: " + msg);
}
}
}
NSDHelper
public class NSDHelper {
private static final String TAG = NSDHelper.class.getSimpleName();
NsdManager mNsdManager;
public static final String SERVICE_TYPE = "_geoStorm._tcp.";
public String mServiceName = "DROIDDEVICE";
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.RegistrationListener mRegistrationListener;
NsdManager.ResolveListener mResolveListener;
NsdServiceInfo mService;
private Context mContext;
public NSDHelper(Context _context) {
mContext = _context;
mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
}
public void initNSD() {
initializeResolveListener();
initializeDiscoveryListener();
initializeRegistrationListener();
}
/**
* This method is to register NSD
*
* #param port
*/
public void registerService(int port) {
NsdServiceInfo nsdServiceInfo = new NsdServiceInfo();
nsdServiceInfo.setPort(port);
nsdServiceInfo.setServiceName(mServiceName);
nsdServiceInfo.setServiceType(SERVICE_TYPE);
mNsdManager.registerService(nsdServiceInfo, NsdManager.PROTOCOL_DNS_SD,
mRegistrationListener);
}
public void initializeResolveListener() {
mResolveListener = new NsdManager.ResolveListener() {
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "Resolve failed" + errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
}
};
}
public void initializeDiscoveryListener() {
mDiscoveryListener = new NsdManager.DiscoveryListener() {
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onDiscoveryStarted(String serviceType) {
Toast.makeText(mContext, "Discovery Started Successfully ",
Toast.LENGTH_LONG).show();
Log.d(TAG, "Service discovery started");
}
#Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
Toast.makeText(mContext, "Discovery stopped", Toast.LENGTH_LONG).show();
}
#Override
public void onServiceFound(NsdServiceInfo serviceInfo) {
Log.d(TAG, "Service discovery success" + serviceInfo);
if (!serviceInfo.getServiceType().equals(SERVICE_TYPE)) {
Toast.makeText(mContext, "Unknown Service Type", Toast.LENGTH_LONG).show();
} else if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same machine: " + mServiceName);
} else if (serviceInfo.getServiceName().contains(mServiceName)) {
mNsdManager.resolveService(serviceInfo, mResolveListener);
}
Log.d(TAG, serviceInfo.getPort() + "");
// Log.d(TAG, new InetSocketAddress(serviceInfo.getHost());)
}
#Override
public void onServiceLost(NsdServiceInfo serviceInfo) {
Log.e(TAG, "service lost" + serviceInfo);
Toast.makeText(mContext, "service Lost" + serviceInfo, Toast.LENGTH_LONG).show();
if (mService == serviceInfo) {
mService = null;
}
}
};
}
public void initializeRegistrationListener() {
mRegistrationListener = new NsdManager.RegistrationListener() {
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
}
#Override
public void onServiceRegistered(NsdServiceInfo serviceInfo) {
mServiceName = serviceInfo.getServiceName();
}
#Override
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
}
};
}
public void discoverServices() {
if (mNsdManager != null)
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
public void stopDiscovery() {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
public NsdServiceInfo getChosenServiceInfo() {
return mService;
}
public void tearDown() {
mNsdManager.unregisterService(mRegistrationListener);
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
mNsdManager = null;
mRegistrationListener = null;
}
}
I need help in this that how i can send message using socket , coz i stuck i am not getting any nothing , any help would be appreciated.
I need to create an application using android socket level programming, I created a connection between server and client but I need to show waiting server IP list at client side and select one IP from the list and establish a connection between them.
Here is my code for server side
public class Server extends AppCompatActivity {
private static final String TAG = "ServerActivity";
private TextView tvServerStatus;
private TextView recievemsg;
InetAddress receiverAddress;
public static String SERVERIP = "";
DatagramSocket datagramSocket;
public static final int SERVERPORT = 8080;
private Handler handler = new Handler();
Handler updateConversationHandler;
private ServerSocket serverSocket;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_server);
updateConversationHandler = new Handler();
tvServerStatus = (TextView) findViewById(R.id.tvServerStatus);
recievemsg=(TextView)findViewById(R.id.send_msg);
SERVERIP = getLocalIpAddress();
Thread fst = new Thread(new ServerThread());
fst.start();
try {
datagramSocket = new DatagramSocket(8080);
byte[] buffer = "0123456789".getBytes();
byte[] address=SERVERIP.getBytes();
receiverAddress = InetAddress.getByAddress(address);
DatagramPacket packet = new DatagramPacket(
buffer, buffer.length, receiverAddress, 8080);
datagramSocket.send(packet);
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private String getLocalIpAddress() {
String ip = "";
try {
Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
.getNetworkInterfaces();
while (enumNetworkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterfaces
.nextElement();
Enumeration<InetAddress> enumInetAddress = networkInterface
.getInetAddresses();
while (enumInetAddress.hasMoreElements()) {
InetAddress inetAddress = enumInetAddress.nextElement();
if (inetAddress.isSiteLocalAddress()) {
ip += "SiteLocalAddress: "
+ inetAddress.getHostAddress() + "\n";
}
}
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
ip += "Something Wrong! " + e.toString() + "\n";
}
return ip;
}
public class ServerThread implements Runnable {
#Override
public void run() {
try {
Log.e(TAG, "Server IP: " + SERVERIP);
if (SERVERIP != null) {
handler.post(new Runnable() {
#Override
public void run() {
tvServerStatus.setText("Listening On Ip: " + SERVERIP);
}
});
serverSocket = new ServerSocket(SERVERPORT);
while (!Thread.currentThread().isInterrupted()) {
{
try {
// LISTEN FOR INCOMING CLIENTS
Socket client = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(client);
new Thread(commThread).start();
// Log.e(TAG, "Client Socket: " + client);
// new Clients_Handle(client, ROOT_DIRECTORY).start();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
handler.post(new Runnable() {
#Override
public void run() {
tvServerStatus.setText("Couldn't detect internet connection.");
}
});
}
} catch (IOException e) {
handler.post(new Runnable() {
#Override
public void run() {
tvServerStatus.setText("Error");
}
});
e.printStackTrace();
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
recievemsg.setText(recievemsg.getText().toString() + "Client Says: " + msg + "\n");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
// MAKE SURE YOU CLOSE THE SOCKET UPON EXITING
serverSocket.close();
Log.e(TAG,"Socket Closed");
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here is my client side code
public class Clientss extends AppCompatActivity {
private static final String TAG = "Client_Activity";
private EditText etServerIp;
private EditText etMsg;
private Button btnConnectClients;
private Button btnSendMsg;
private TextView textIn;
private String serverIpAddress = "";
private String t;
private boolean connected = false;
DatagramSocket datagramSocket;
DatagramPacket packet;
private Socket socket;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clientss);
Log.e(TAG, "ONCREATE METHOD");
textIn = (TextView)findViewById(R.id.txt_msg);
initializations();
eventClickListener();
try {
datagramSocket = new DatagramSocket(8080);
byte[] buffer = new byte[10];
packet = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(packet);
byte[] buff = packet.getData();
textIn.setText(buff.toString());
System.out.println("this is incoming ip"+buff.toString());
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// textIn.setText(t);
}
private void eventClickListener() {
btnConnectClients.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!connected) {
serverIpAddress = etServerIp.getText().toString().trim();
connectsClient();
}
}
});
btnSendMsg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String msg = etMsg.getText().toString().trim();
ClientResponseTask clientResponseTask=new ClientResponseTask(msg);
clientResponseTask.execute();
}
});
}
private void connectsClient() {
if (!serverIpAddress.equals("")) {
Thread cThread = new Thread(new ClientThread());
cThread.start();
}
}
private void initializations() {
etServerIp = (EditText) findViewById(R.id.etServerIp);
etMsg = (EditText) findViewById(R.id.etMsg);
btnSendMsg = (Button) findViewById(R.id.btnMsgSend);
btnConnectClients = (Button) findViewById(R.id.btnConnect);
}
private class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
Log.e(TAG, "C: Connecting...");
socket = new Socket(serverAddr, Server.SERVERPORT);
System.out.println("this is socket"+socket);
connected = true;
Message msg = handler.obtainMessage();
msg.arg1 = 1;
handler.sendMessage(msg);
//showToast("");
Log.e(TAG, "C: Connected..." + socket);
} catch (Exception e) {
Log.e(TAG, "C: Error", e);
connected = false;
}
}
}
private final Handler handler = new Handler() {
public void handleMessage(Message msg) {
if(msg.arg1 == 1)
Toast.makeText(getApplicationContext(),"Connected...", Toast.LENGTH_LONG).show();
}
};
#Override
protected void onDestroy() {
if (socket != null) try {
socket.close();
Log.e(TAG, "C: Socket Closed.");
} catch (IOException e) {
e.printStackTrace();
} finally
{
try
{
socket.close();
}
catch(Exception e){}
}
super.onDestroy();
}
protected class ClientResponseTask extends AsyncTask<Void,Void,Void> {
String msg;
ClientResponseTask(String msg){
this.msg=msg;
}
#Override
protected Void doInBackground(Void... params) {
if (connected) {
try {
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println(msg);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (Exception e) {
Log.e(TAG, "Error", e);
}
}
else {
connectsClient();
}
return null;
}
}
}
Please help me to find a solution.
i'm begginer with java socket in android. i'm have some problem and need help for solving them.
I'm connect to server Socket with bottom code and every thing is fine. but when call disconnect method and try to connect again i faced with problem such socket is null or BufferedReader object always return null after disconnect and connect again. maybe my disconnect way is wrong. what is the best way for disconnect socket at some time like intrupt internet and connect again?
Here is my code for connecting and disconnecting socket.
public class HelperSocket {
public static Socket socket = null;
public static DataOutputStream writer = null;
public static BufferedReader reader = null;
public static DataInputStream inputStream = null;
public static final String SOCKET_ADDRESS = "aUrlForSocket";
public static final int SOCKET_PORT = 6000;
public static final int SOCKET_TIMEOUT = 30000;
public static Thread clientThread;
public static boolean isConnected = false;
public static boolean connect() {
Utils.Log("StartConnect");
if (!isConnected) {
clientThread = new Thread(new Runnable() {
#Override
public void run() {
try {
InetAddress address = InetAddress.getByName(HelperSocket.SOCKET_ADDRESS);
socket = new Socket(address.getHostAddress(), SOCKET_PORT);
isConnected = true;
socket.setSoTimeout(SOCKET_TIMEOUT);
writer = new DataOutputStream(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
inputStream = new DataInputStream(socket.getInputStream());
while (HelperSocket.isConnected) {
Utils.Log("onWhile" + reader.hashCode());
try {
if (reader.readLine() != null) {
Utils.Log(reader.readLine() + "");
} else {
Utils.Log("getNullFromServer");
//data get null here :)
disconnect();
}
} catch (IOException e) {
Utils.Log("ProblemOnReadData" + e.getMessage());
e.printStackTrace();
}
}
} catch (IOException e) {
Utils.Log("SocketProblemAt connect:" + e.getMessage());
e.printStackTrace();
}
}
});
clientThread.start();
}
return true;
}
public static boolean disconnect() {
isConnected = false;
if (!clientThread.isInterrupted())
clientThread.interrupt();
if (socket != null) {
Utils.Log("SocketAndAllObjectCleared");
try {
socket.shutdownInput();
socket.shutdownOutput();
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
/* stream = null;
reader = null;*/
}
return false;
}
}
I create a reciever in network connectivity change, and need to disconnect socket when device not connect to internet and connect again when internet connection established.
The receiver:
public class BroadcastChangeNet extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Utils.isNetworkConnected()) {
HelperSocket.connect();
Utils.Log("NetWorkConnect");
} else {
HelperSocket.disconnect();
Utils.Log("NetWorkDisConnect");
}
}
}
Checking network situation:
public static boolean isNetworkConnected() {
ConnectivityManager conMgr =
(ConnectivityManager) ApplicationClass.context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo i = conMgr.getActiveNetworkInfo();
if (i == null)
return false;
if (!i.isConnected())
return false;
if (!i.isAvailable())
return false;
return true;
}
From my point of view you simply need to create saprate Jave class, below is my code that i tested successfully,
import android.content.Context;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
/**
* Created by Kintan Patel on 01-08-2016.
*/
public class SocketConnection {
private Socket socket = null;
private OutputStream outputStream;
private DataOutputStream dataOutputStream;
private SessionHelper helper;
public String EstablishConnection(String token) {
// token = your message that write on socket server
String response;
try {
//socket = new Socket("192.168.0.24", 2129); // Testing Server
socket = new Socket("Your IpAddress", PORT NO);
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF(token);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
response = br.readLine();
} catch (UnknownHostException e) {
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
return null;
} catch (SocketException e) {
e.printStackTrace();
response = "Sorry Fail to connect";
return null;
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
response = "Sorry Fail to connect";
return null;
} catch (Exception e) {
e.printStackTrace();
response = "Server Break";
return null;
} finally {
if (socket != null) {
try {
socket.close();
outputStream.close();
dataOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return response;
}
}
Now from your main class simply create the object of SocketConnection class and use EstablishConnection() method,
eg :
SocketConnection connection = new SocketConnection();
String token = "message that you want to write on server";
String response = connecation.EstablishConnection(token);
if you want to use AsynkTask than below is AsynkTask code :
private class ActivationTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
SocketConnection connection = new SocketConnection();
String token = "getActivation|" + params[0] + "|";
return connection.EstablishConnection(token);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.show();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
progressDialog.dismiss();
if (s != null) {
Log.e("RESULT" , s);
}
}
}
The web server on the pc is in c#
In the form1 constructor:
var ws = new WebServer(
request => Task.Run(() => SendResponseAsync(request)),
"http://+:8098/");
ws.Run();
This two methods
public static string GetLocalIPAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
throw new Exception("Local IP Address Not Found!");
}
public void Send(string ipaddress)
{
UdpClient client = new UdpClient();
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, 15000);
byte[] bytes = Encoding.ASCII.GetBytes(ipaddress);
client.Send(bytes, bytes.Length, ip);
client.Close();
}
Then in timer tick event interval set to 1000ms
int countsends = 0;
private void timer2_Tick(object sender, EventArgs e)
{
if (countsends == 10)
{
Send(localipadd);
countsends = 0;
}
countsends += 1;
}
And the WebServer class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
namespace Automatic_Record
{
class WebServer
{
private readonly HttpListener _listener = new HttpListener();
private readonly Func<HttpListenerRequest, Task<string>> _responderMethod;
public WebServer(string[] prefixes, Func<HttpListenerRequest, Task<string>> method)
{
try
{
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required, for example
// "http://localhost:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
_listener.Prefixes.Add(s);
_responderMethod = method;
_listener.Start();
}
catch(AccessViolationException err)
{
string error = err.StackTrace;
}
}
}
On the pc side the c# i'm not getting any errors or exceptions and using break point i can see the pc ip on the network on the router on the method Send on variable ipaddress it's value is 10.0.0.1 i also logged in to my router settings and i saw that the pc is on 10.0.0.1
Now the java side in the android-studio where i'm trying to get the pc ip and to connect to it:
At the top of mainactivity: ( I tried before port 8098 but it didn't work so i tried 15000 but also didn't work still getting timeout message )
private String[] ipaddresses = new String[]{
"http://10.0.0.1:15000/?cmd=nothing"
};
Then a button click method calling from onCreate
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addListenerOnButton();
currentActivity = this;
initTTS();
}
The addListenerOnButton
public void addListenerOnButton()
{
btnClick = (Button) findViewById(R.id.connecttoserverbutton);
btnClick.setOnClickListener(new OnClickListener()
{
byte[] response = null;
#Override
public void onClick(View arg0)
{
text = (TextView) findViewById(R.id.statusTextView);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
for (int i = 0; i < ipaddresses.length; i++)
{
counter = i;
try
{
response = Get(ipaddresses[i]);
}
catch (Exception e)
{
String err = e.toString();
}
if (response!=null)
{
try
{
final String a = new String(response, "UTF-8");
text.post(new Runnable()
{
#Override
public void run()
{
text.setText(a + " Oמ " + ipaddresses[counter]);
}
});
iptouse = ipaddresses[i].substring(0,ipaddresses[i].lastIndexOf("=")+1);
connectedtoipsuccess = true;
Logger.getLogger("MainActivity(inside thread)").info(a);
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
Logger.getLogger("MainActivity(inside thread)").info("encoding exception");
}
Logger.getLogger("MainActivity(inside thread)").info("test1");
break;
}
else
{
}
}
counter = 0;
if (response == null)
{
text.post(new Runnable()
{
#Override
public void run()
{
text.setText("Connection Failed");
}
});
}
}
});
t.start();
}
});
}
And last the Get method
private byte[] Get(String urlIn)
{
URL url = null;
String urlStr = urlIn;
if (urlIn!=null)
urlStr=urlIn;
try
{
url = new URL(urlStr);
} catch (MalformedURLException e)
{
e.printStackTrace();
return null;
}
HttpURLConnection urlConnection = null;
try
{
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
byte[] buf=new byte[10*1024];
int szRead = in.read(buf);
byte[] bufOut;
if (szRead==10*1024)
{
throw new AndroidRuntimeException("the returned data is bigger than 10*1024.. we don't handle it..");
}
else
{
bufOut = Arrays.copyOf(buf, szRead);
}
return bufOut;
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
finally
{
if (urlConnection!=null)
urlConnection.disconnect();
}
}
My android device is also connected to the same network on the router with wifi i checked on the router settings and i see my device.
I used a break point on the android-studio side inside the Get method.
It's getting to the line:
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
Then i click continue and that's it here it's hanging and instead keep going to the next line byte[] buf=new byte[10*1024]; after about 30 seconds it's jumping to: e.printStackTrace();
android.system.ErrnoException: connect failed: ETIMEDOUT (Connection timed out)
failed to connect to /10.0.0.1 (port 15000): connect failed: ETIMEDOUT (Connection timed out)
I can't see any exceptions in the logcat.
I have a problem with receiving irregular sequence of the byte messages I send from another device.
The setup is the following: I have an Android app (client) and Real-Time system (server) with Ethernet both connected in a LAN through router, which talk with raw bytes communication.
From the Android app I send request, which causes the server to respond with several messages - the first one with 8 bytes, the following messages have 27 bytes. I have debugged the server and I am sure the first message it sends is the 8th-byte one, followed by the others.
About the app - I use the Main Activity to handle transmission of data through the socket, and additional thread to handle reception of data.
The thread makes post through Handler to the Main Activity, when new data has been received. In this post is called a process to parse the received data.
TbProtocolProcessor is a class I use to handle my custom protocol. It can create a byte array for me to send as request for specific function, and it has a state-machine to process expected response from the server. InetHandler is nested class I use to handle my connectivity only.
My question is - why would my Android app return me the first message having size 8, but contents like the next messages? Interesting effect is that if I send ONLY the 8-byte message, without any others, it is received and passed to my app correctly.
Here is the code:
public class MainActivity extends AppCompatActivity
{
private TbProtocolProcessor tbProtPrcs = null;
private InetHandler inetHandler = new InetHandler(this);
private static Handler msgHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tbProtPrcs = new TbProtocolProcessor(this);
}
// Implementation of InetControl interface
public void ConnectToIP(String strIP, int port)
{
inetHandler.AttachToIP(strIP, port);
}
public void Disconnect()
{
inetHandler.DetachFromIP();
}
public void GetFilesList()
{
byte[] data = TbProtocolProcessor.buildFilesGetList();
inetHandler.SendData(data, data.length);
TbProtocolProcessor.setExpectedResult(
TbProtocolProcessor.TB_STATE_WAIT_MUL_FILESLIST,
data[1],
1);
}
private class InetHandler
{
protected static final int cTARGET_PORT_UNASSIGNED = 0xFFFF;
protected String targetIP = null;
protected int targetPort = cTARGET_PORT_UNASSIGNED;
protected boolean isConnected = false;
protected Socket socket = null;
protected DataOutputStream sockStrmOut = null;
protected DataInputStream sockStrmIn = null;
protected Context context = null;
public InetHandler(Context ctx) {
if (ctx != null)
{
context = ctx;
}
}
class ClientThread implements Runnable {
byte[] indata = new byte[100];
int inCntr;
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(targetIP);
socket = new Socket(serverAddr, targetPort);
socket.setKeepAlive(true);
// DataOutputStream is used to write primitive data types to stream
sockStrmOut = new DataOutputStream(socket.getOutputStream());
sockStrmIn = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
if (socket.isConnected()) {
isConnected = true;
//Toast.makeText(context, "CONNECTED", Toast.LENGTH_SHORT).show();
//findViewById(R.id.action_connect).setBackgroundColor(0xFF60FF60);
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// TODO:
while (isConnected) {
try {
inCntr = sockStrmIn.read(indata);
}
catch (IOException e) {
e.printStackTrace();
}
if (inCntr > 0) {
msgHandler.post(new Runnable() {
#Override
public void run() {
if ( tbProtPrcs.Process(indata, inCntr) ) {
Toast.makeText(context, "Operation Success", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "Operation ERROR", Toast.LENGTH_SHORT).show();
}
}
});
}
}
}
}
public void AttachToIP(String sIP, int iPort)
{
if ( (isIPValid(sIP)) && (iPort < cTARGET_PORT_UNASSIGNED) )
{
targetIP = sIP;
targetPort = iPort;
// Start the connection thread
new Thread(new ClientThread()).start();
}
}
public void DetachFromIP()
{
try {
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public boolean SendData(byte[] data, int size)
{
boolean bResult = false;
try
{
if ( (data != null) && (size > 0) && (sockStrmOut != null) ) {
Toast.makeText(context, "Sending...", Toast.LENGTH_SHORT).show();
sockStrmOut.write(data, 0, size);
bResult = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return bResult;
}
public boolean isIPValid (String ip) {
try {
if (ip == null || ip.isEmpty()) {
return false;
}
String[] parts = ip.split( "\\." );
if ( parts.length != 4 ) {
return false;
}
for ( String s : parts ) {
int i = Integer.parseInt( s );
if ( (i < 0) || (i > 255) ) {
return false;
}
}
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
}
}
You're assuming that read() fills the buffer. It isn't specified to do that. See the Javadoc. If you want to fill the buffer you must use readFully().
NB isConnected() cannot possibly be false at the point you're testing it.