Netty client, stops after connection to server - java

I just started with Netty.
Currently I am trying to send an Object to a Server. I wrote some client in Java, and it's working fine. I also wrote an Android App that receives messages from a server. I tried to add some code for handling Objects to the Client part, but there is a problem.
It connects, but it's not sending messages. The Server is the same, so is the Object. Manifest is ok. I've tried multiple times to lunch Java client and Android client. Everything is working for Java. I am desperate already.
Here is my code
Client
public final class ObjectEchoClient {
public static ChannelHandlerContext ctx;
static final String HOST = System.getProperty("host", "192.168.0.101");
static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
public static void startClient() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_KEEPALIVE, true) // (4)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ObjectEchoClientHandler());
}
});
// Start the connection attempt.
b.connect(HOST, PORT).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
Android MainActivity
public class MainActivity extends Activity {
public static UnixTime m;
public static int id = 12345678;
public static ChannelHandlerContext ctx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
socketTest();
final Button btn1 = (Button)findViewById(R.id.button1);
btn1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
//*
if(ObjectEchoClient.ctx != null)
{
Package p = new Package();
p.setId(id);
ObjectEchoClient.ctx.writeAndFlush(p);
}
else
{
Log.e("test", "off");
}
//*/
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public static void socketTest()
{
new Thread (new Runnable() {
#Override
public void run() {
try {
ObjectEchoClient.startClient();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}).start();
}
P.S. If I add some message to the handler at the channelActive method in the ObjectEchoClientHandler(), it will be sent. but I need to send it when I will need to.
P.P.S Hendler
public class ObjectEchoClientHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
ObjectEchoClient.ctx = ctx;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

I am a bit rusty here but when you call:
b.connect(HOST, PORT).sync().channel().closeFuture().sync();
are you not closing the channel as soon as it's opened ?
Sending a message on channel active is sending during the brief period the channel is connected, no ?
I'm still a netty3 diehard but looking at the 5 samples, to connect you want to:
ChannelFuture f = b.connect(HOST, PORT).sync();
And then later, to stop the client:
f.channel().closeFuture().sync();

So the problem was in the writeAndFlush(); method. For Android it's not flushing properly data. So You need to flush it, once again.
ObjectEchoClient.ctx.writeAndFlush(p);
ctx.flush();

Related

Android socket io event and Channel

How to add event and channel?
private void initSocketConnection() {
try {
mSocket = IO.socket("URL");
connectSocket();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
private void connectSocket() {
try {
mSocket.connect();
mSocket.on(Socket.EVENT_CONNECT, onConnect);
mSocket.on(Socket.EVENT_CONNECT_ERROR, onError);
mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
} catch (Exception e) {
e.printStackTrace();
}
}
private Emitter.Listener onDisconnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.e("SOCKET_TEST", "DISCONNECTION SUCCESSFULL");
}
};
/**
* Receiver class for socket connected event
*/
private Emitter.Listener onConnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.e("SOCKET_TEST", "CONNECTION SUCCESSFULL");
}
};
/**
* Receiver for socket failed events
*/
private Emitter.Listener onError = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.e("SOCKET_TEST", "CONNECTION FAIL " + args.toString());
}
};
I send a request, returns 32:44/socket.io,"Invalid namespace"
need to send event and channel
I use the library https://github.com/socketio/socket.io-client-java I do everything according to the documentation but nothing works.
Instead of creating a socket with just:
val socket = IO.socket("https://something.com/socket.io")
try the next code:
val opts = IO.Options()
opts.path = "/socket.io"
val socket = IO.socket("https://something.com", opts)
I had the same issue getting 4/socket.io, "Invalid namespace" trying to connect to the socket, and the code above fixed it.

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.read(byte[])' on a null object reference

I am trying to create a Chat Application using WiFip2p.Everything is done in this application. Before send and receive message app was working good. After that, I got this error. I am getting this error when I connect to another device. It shows a null object reference. I don't know why I need a solution can anyone help me thank you.
public class WiFi_Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wi_fi_);
FINDVIEWBYID();
CLICKLISTINER();
}
Handler handler=new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
switch (msg.what)
{
case MESSAGE_READ:
byte[] readbuffer=(byte[])msg.obj;
String tempmez=new String(readbuffer,0,msg.arg1);
txt_message.setText(tempmez);
break;
}
return true;
}
});
private void FINDVIEWBYID() {
btn_onoff=findViewById(R.id.onOff);
btn_discover=findViewById(R.id.discover);
btn_send=findViewById(R.id.sendButton);
listView=findViewById(R.id.peerListView);
txt_connectionsts=findViewById(R.id.connectionStatus);
txt_message=findViewById(R.id.readMsg);
edit_message=findViewById(R.id.writeMsg);
wifiManager= (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiP2pManager= (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel=wifiP2pManager.initialize(this,getMainLooper(),null);
broadcastReceiver=new Wifi_broadcast_reciever(wifiP2pManager,channel,this);
intentFilter=new IntentFilter();
intentFilter.addAction(wifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(wifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(wifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(wifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
}
private void CLICKLISTINER() {
btn_onoff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (wifiManager.isWifiEnabled())
{
wifiManager.setWifiEnabled(false);
btn_onoff.setText("ON");
}
else
{
wifiManager.setWifiEnabled(true);
btn_onoff.setText("OFF");
}
}
});
btn_discover.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
wifiP2pManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
txt_connectionsts.setText("Discovery Started");
}
#Override
public void onFailure(int reason) {
txt_connectionsts.setText("Discovery starting failuree"+String.valueOf(reason));
}
});
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final WifiP2pDevice wifiP2pDevice=devicearray[position];
WifiP2pConfig config=new WifiP2pConfig();
config.deviceAddress=wifiP2pDevice.deviceAddress;
wifiP2pManager.connect(channel, config, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Toast.makeText(WiFi_Activity.this, "Connect with"+ wifiP2pDevice.deviceName, Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(int reason) {
Toast.makeText(WiFi_Activity.this, "Not connected", Toast.LENGTH_SHORT).show();
}
});
}
});
btn_send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String msz=edit_message.getText().toString();
sendRecieve.write(msz.getBytes());
}
});
}
WifiP2pManager.PeerListListener peerListListener=new WifiP2pManager.PeerListListener() {
#Override
public void onPeersAvailable(WifiP2pDeviceList peerslist) {
if (!peerslist.getDeviceList().equals(peers));
{
peers.clear();
peers.addAll(peerslist.getDeviceList());
devicename_array=new String[peerslist.getDeviceList().size()];
devicearray=new WifiP2pDevice[peerslist.getDeviceList().size()];
int index= 0;
for (WifiP2pDevice device:peerslist.getDeviceList())
{
devicename_array[index]=device.deviceName;
devicearray[index]=device;
index++;
}
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(getApplicationContext(),R.layout.support_simple_spinner_dropdown_item,devicename_array);
listView.setAdapter(arrayAdapter);
}
if (peers.size()==0)
{
Toast.makeText(WiFi_Activity.this, "No discover show", Toast.LENGTH_SHORT).show();
}
}
};
WifiP2pManager.ConnectionInfoListener connectionInfoListener=new WifiP2pManager.ConnectionInfoListener() {
#Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
final InetAddress owneraddress= info.groupOwnerAddress;
if (info.groupFormed && info.isGroupOwner)
{
txt_connectionsts.setText("Host");
serverclass=new Serverclass();
serverclass.start();
}
else if (info.groupFormed)
{
txt_connectionsts.setText("Client");
clientclass = new Clientclass(owneraddress);
clientclass.start();
}
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(broadcastReceiver,intentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
public class Serverclass extends Thread
{
Socket socket;
ServerSocket serverSocket;
#Override
public void run() {
try {
serverSocket=new ServerSocket(1111);
socket=serverSocket.accept();
sendRecieve=new SendRecieve(socket);
sendRecieve.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Clientclass extends Thread
{
Socket socket;
String host_address;
public Clientclass(InetAddress hostaddress){
host_address=hostaddress.getHostAddress();
socket=new Socket();
sendRecieve=new SendRecieve(socket);
sendRecieve.start();
}
#Override
public void run() {
try {
socket.connect(new InetSocketAddress(host_address,1111),500);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class SendRecieve extends Thread
{
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
public SendRecieve(Socket skt)
{
socket=skt;
try {
inputStream=socket.getInputStream();
outputStream=socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
byte[] buffer=new byte[2048];
int bytes;
while (socket!=null)
{
try {
bytes=inputStream.read(buffer);
if (bytes>0)
{
handler.obtainMessage(MESSAGE_READ,bytes,-1,buffer).sendToTarget();
}
} catch (IOException e) {
Log.d("error",e.getMessage());
}
}
}
public void write(byte[] bytes)
{
try {
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I am getting this error on this part of code:-
#Override
public void run() {
byte[] buffer=new byte[2048];
int bytes;
while (socket!=null)
{
try {
bytes=inputStream.read(buffer);
if (bytes>0)
{
handler.obtainMessage(MESSAGE_READ,bytes,-1,buffer).sendToTarget();
}
} catch (IOException e) {
Log.d("error",e.getMessage());
}
}
}
The only thing I can see as being an issue is that you're catching (and ignoring) errors from getInputStream() and getOutputStream(). The exception is stopping execution, so if getInputStream() errors out, it doesn't get set. Both of your streams would be null.
Since you're at least printing the stacktrace, check for other stacktraces before the actual crash. It may tell you more about what went wrong.
To get around this, I suggest not catching the exception and instead making the constructor throw IOException. If you catch it early, it will cause less problems for you later on.
Edit: I've looked at your classes a bit more, and I see that you don't set the address of the Socket in time. Do that before you get the data streams for it. Not using the fields will work.
private Socket socket;
public SendRecieve(Socket skt) {
this.socket = skt;
}
#Override
public void run() {
try {
InputStream in = socket.getInputStream();
... etc
} ...
}
You calling Sendreceiver start before Clientclas run executes, so the following is necessary:
public class Clientclass extends Thread {
Socket socket;
String host_address;
public Clientclass(InetAddress hostaddress){
host_address=hostaddress.getHostAddress();
socket=new Socket();
}
#Override
public void run() {
try {
socket.connect(new InetSocketAddress(host_address,1111),500);
sendRecieve=new SendRecieve(socket);
sendRecieve.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}

creating connection within android device using sockets

I am trying to create a connection between two applications using android. I have tried to use sockets to connect. I have created two application
One which accepts the connection when client wants to connect
and another application that requests to connect.
I have successfully run this code in same manner in pc in java in pc network. Is the way of connecting to android also same?
My server class implementation
public class MainActivity extends AppCompatActivity {
private Button startButton;
private ServerSocket server;
private Socket connection;
private TextView statusText;
private ObjectOutputStream output;
private ObjectInputStream input;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusText=(TextView)findViewById(R.id.statusText);
startButton=(Button)findViewById(R.id.startButton);
startButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
startRunning();
}
}
);
}
private void startRunning() {
try{
server=new ServerSocket(8080);
while(true)
{
try{
waitForConnection();
setUpStreams();
whileChatting();
}catch(Exception e){}
}
} catch(Exception e){}
}
public void waitForConnection()
{
setMyStatus("Waiting for client to connect...");
try {
connection= server.accept();
setMyStatus("Now connected to "+ connection.getInetAddress().getHostName());
} catch (IOException e) {
e.printStackTrace();
}
}
public void setUpStreams()
{
try {
output= new ObjectOutputStream(connection.getOutputStream());
output.flush();
input= new ObjectInputStream(connection.getInputStream());
setMyStatus("Streams are now setup. Ready to go...");
} catch (IOException e) {
e.printStackTrace();
}
}
public void whileChatting()
{
setMyStatus("You can now start chatting...");
}
public void setMyStatus(String msg) {
statusText.setText(msg);
}
}
I will use the tasks like async task later. But i am just trying to set up connection in these application.
My client implementation goes like this
public class MainActivity extends AppCompatActivity {
private Button startButton;
private Socket connection;
private TextView statusText;
public ObjectOutputStream output;
public ObjectInputStream input;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusText=(TextView)findViewById(R.id.statusText);
startButton=(Button)findViewById(R.id.startButton);
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startRunning();
}
});
}
private void startRunning() {
connectToServer();
setUpStreams();
whileChatting();
}
public void connectToServer()
{
setMyStatus("Connecting to server. Please wait...");
try {
connection= new Socket(InetAddress.getByName("127.0.0.1"),8080);
setMyStatus("Connected to Server."+ connection.getInetAddress().getHostName());
} catch (IOException e) {
e.printStackTrace();
}
}
public void setUpStreams()
{
try {
output= new ObjectOutputStream(connection.getOutputStream());
output.flush();
input= new ObjectInputStream(connection.getInputStream());
setMyStatus("Streams are now setup. Ready to go...");
} catch (IOException e) {
e.printStackTrace();
}
}
public void whileChatting()
{
setMyStatus("You can now start chatting...");
}
public void setMyStatus(String msg) {
statusText.setText(msg);
}
}
The error I got is in the case of client that tries to connect to server
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.OutputStream java.net.Socket.getOutputStream()' on a null object reference
at com.myapp.client.clientdemo.MainActivity.setUpStreams(MainActivity.java:71)
at com.myapp.client.clientdemo.MainActivity.startRunning(MainActivity.java:46)
at com.myapp.client.clientdemo.MainActivity.access$000(MainActivity.java:16)
at com.myapp.client.clientdemo.MainActivity$1.onClick(MainActivity.java:33)
It's because "connection" was never created. Probably because it failed to connect or it timed out and it moved on to the next code. If it timed out or didn't connect, then you need to catch that exception and retry to connect before moving on with your later code.
Socket can be tricky if you do not catch all the erroneous states they can get into.
simply wrap your try and catch with a while loop until the condition is met like this:
while(!connected & !closed){
try {
connection= new Socket(InetAddress.getByName("127.0.0.1"),8080);
connected = true;
//now it is connected and will exit the loop and continue with other code
} catch (SocketTimeoutException socketTimeoutException) {
//add this for safety
} catch (IOException e) {
e.printStackTrace();
}
}

Android client only connecting once to server with LipeRMI

I have an Android client connecting to a Java server with LipeRMI (http://lipermi.sourceforge.net/).
To test this communication I have a button in my interface that when clicked sends a String "Test". It gets to the server and the server returns the String. It works fine, the problem is that it only works once. The server only accepts one time.
My Server code is the following:
public class TestServer implements TestService {
public TestServer() {
try {
CallHandler callHandler = new CallHandler();
callHandler.registerGlobal(TestService.class, this);
Server server = new Server();
server.bind(7777, callHandler);
server.addServerListener(new IServerListener() {
#Override
public void clientDisconnected(Socket socket) {
System.out.println("Client Disconnected: " + socket.getInetAddress());
}
#Override
public void clientConnected(Socket socket) {
System.out.println("Client Connected: " + socket.getInetAddress());
}
});
System.out.println("Server Listening");
} catch (LipeRMIException | IOException e) {
e.printStackTrace();
}
}
#Override
public String getResponse(String data) {
System.out.println("getResponse called");
System.out.println("The information received was: " + data);
return "Your data: " + data;
}
And in the Android client, in my MainActivity I have the following:
public class MainActivity extends Activity {
private String serverIP = "192.168.3.8";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGet = (Button) findViewById(R.id.send);
btnGet.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new Conn().execute();
}
});
}
class Conn extends AsyncTask<Void, Void, MainActivity> {
#Override
protected MainActivity doInBackground(Void... params) {
Looper.prepare();
try {
CallHandler callHandler = new CallHandler();
Client client = new Client(serverIP, 7777, callHandler);
TestService testService = (TestService) client.getGlobal(TestService.class);
String msg = testService.getResponse("Test");
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
Looper.loop();
return null;
}
}
They have the TestService interface in common so that I can use the methods from the server.
How can I change the server so that it can accept any number of times a call from the Android Client?
I had the same issue and I deleted the Looper.prepare() and Looper.loop() calls in the doInBackground method from AsyncTask. It solved the problem in my case.

Android app using LipeRMI is connecting to server but not calling the method

I have an android app and a server, both using lipeRMI.
My android app successfully connects to the server. But the method it's supposed to call, is not being called.
Server Code:
public interface TestService {
public String getResponse(String data);
}
public class TestServer implements TestService {
public TestServer() {
try {
CallHandler callHandler = new CallHandler();
callHandler.registerGlobal(TestService.class, this);
Server server = new Server();
server.bind(7777, callHandler);
server.addServerListener(new IServerListener() {
#Override
public void clientDisconnected(Socket socket) {
System.out.println("Client Disconnected: " + socket.getInetAddress());
}
#Override
public void clientConnected(Socket socket) {
System.out.println("Client Connected: " + socket.getInetAddress());
}
});
System.out.println("Server Listening");
} catch (LipeRMIException | IOException e) {
e.printStackTrace();
}
}
#Override
public String getResponse(String data) {
System.out.println("getResponse called");
return "Your data: " + data;
}
public static void main(String[] args) {
TestServer testServer = new TestServer();
}
}
The android code:
interface TestService {
public String getResponse(String data);
}
public class MainActivity extends Activity {
private String serverIP = "192.168.1.7";
EditText et= null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGet = (Button) findViewById(R.id.button1);
et= (EditText)findViewById(R.id.editText2);
btnGet.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new Conn().execute();
}
});
}
class Conn extends AsyncTask<Void, Void, MainActivity> {
#Override
protected MainActivity doInBackground(Void... params) {
Looper.prepare();
try {
Toast.makeText(MainActivity.this, "Inside conn my nigga", Toast.LENGTH_SHORT).show();
CallHandler callHandler = new CallHandler();
Client client = new Client(serverIP, 7777, callHandler);
TestService testService = (TestService) client.getGlobal(TestService.class);
String msg = testService.getResponse("qwe");
//Toast.makeText(MainActivity.this, testService.getResponse("abc"), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
Looper.loop();
return null;
}
}
}
I tried using the above code also using a simple Runnable thread instead of AsyncTask(I was paranoid AsyncTask'd be causing the problem) but it went in vain.
The server gives this output:
Server Listening
Client Connected: /192.168.1.5
Client Disconnected: /192.168.1.5
No matter how many times I click the Button1 of my android app.
Any help will be really appreciated. :)
Thank you for your time!
I had this situation when packages were different. You should make sure that TestService packages are same at Android application and server.
If you use your own class in TestService interface, it should have same packages too and should implement Serializable.

Categories