I'm developing an Android application (client) and want it to connect with my Java server using TCP communication, and so far everything is going well.
Server Code:
import java.net.*;
import java.io.*;
import globalvariables.GlobalVariables;
import interface_package.ServerInterface;
import java.util.Timer;
/**
*
* #author wsserver
*/
public class ThreadedAndroidServer {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
GlobalVariables.init();
//Prevzemi staticen interface
GlobalVariables.sinterface = new ServerInterface();
GlobalVariables.sinterface.show();
//INFINITE LOOP
while(true)
int port = GlobalVariables.portNo;
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("Server has started listening on port " + port);
GlobalVariables.sinterface.setServerStatus("Server has started listening on port " + port);
} catch (IOException e) {
System.out.println("Error: Cannot listen on port " + port + " : " + e);
GlobalVariables.sinterface.setServerStatus("Error: Cannot listen on port " + port + " : " + e);
System.exit(1);
}
while (true) // infinite loop - loops once for each client
{
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept(); //waits here (forever) until a client connects
System.out.println("Server has just accepted socket connection from a client");
GlobalVariables.sinterface.setServerStatus("Server has just accepted socket connection from a client");
} catch (IOException e) {
System.out.println("Accept failed: " + e);
GlobalVariables.sinterface.setServerStatus("Accept failed: " + e);
break;
}
// Create the Handle Connection object - our new thread object - only create it
ThreadedHandleConnection con = new ThreadedHandleConnection(clientSocket);
if (con == null) //If it failed send and error message
{
try {
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject("error: Cannot open socket thread");
os.flush();
os.close();
} catch (Exception ex) //failed to even send an error message
{
System.out.println("Cannot send error back to client: " + ex);
GlobalVariables.sinterface.setServerStatus("Cannot send error back to client: " + ex);
}
} else {
con.start();
} // otherwise we have not failed to create the HandleConnection object
// start this thread now
}
try // do not get here at the moment
{
System.out.println("Closing server socket.");
GlobalVariables.sinterface.setServerStatus("Closing server socket.");
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close server socket. " + e.getMessage());
GlobalVariables.sinterface.setServerStatus("Could not close server socket. " + e.getMessage());
}
}
}
Connection Handler:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package tcpServer_package;
import java.net.*;
import java.io.*;
import java.util.*;
import busimesslogic_package.Functions;
/**
*
* #author wsserver
*/
public class ThreadedHandleConnection extends Thread {
private Socket clientSocket; // Client socket object
private ObjectInputStream is; // Input stream
private ObjectOutputStream os; // Output stream
// The constructor for the connecton handler
public ThreadedHandleConnection(Socket clientSocket) {
this.clientSocket = clientSocket;
}
// The main thread execution method
public void run() {
try {
this.is = new ObjectInputStream(clientSocket.getInputStream());
this.os = new ObjectOutputStream(clientSocket.getOutputStream());
while (this.readCommand()) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
// Receive and process incoming command from client socket
private boolean readCommand() {
String wholeCommand = null;
try {
wholeCommand = (String) is.readObject();
} catch (Exception e) {
wholeCommand = null;
}
if (wholeCommand == null) {
this.closeSocket();
return false;
}
System.out.println("Received: "+wholeCommand);
//GET COMMAND PARAMETARS
String[] commParams = wholeCommand.split(";");
//GET COMMAND TYPE
int type = Integer.parseInt(commParams[0]);
//SELECT COMMAND PROCEDURE
Functions functions = new Functions();
String IPaddress = clientSocket.getRemoteSocketAddress().toString();
IPaddress = IPaddress.substring(IPaddress.indexOf("/")+1, IPaddress.indexOf(":"));
switch (type) {
case 1: {
String sendText = getTextToSend();
send(sendText);
break;
}
default:{
sendError("0;"+wholeCommand);
break;
}
}
System.gc();
return true;
}
// Send a message back through to the client socket as an Object
private void send(Object o) {
try {
System.out.println("Sending " + o);
this.os.writeObject(o);
this.os.flush();
} catch (Exception ex) {
ex.printStackTrace();
}
}
// Send a pre-formatted error message to the client
public void sendError(String msg) {
this.send("error:" + msg); //remember a string IS-A object!
}
// Close the client socket
public void closeSocket() //close the socket connection
{
try {
this.os.close();
this.is.close();
this.clientSocket.close();
} catch (Exception ex) {
System.err.println(ex.toString());
}
}
}
Android Client Code:
package com.example.zpbitolaoperator;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import android.util.Log;
public class TCPClient{
//Comunication variables
private static Socket socket;
private static ObjectOutputStream os;
private static ObjectInputStream is;
//Server parametars
static String serverIP;
static int port;
//Communication status
static boolean connectionStatus = false;
public static boolean connectToServer() {
try // open a new socket to port: and create streams
{
serverIP = GlobalVariables.serverIP;
port = GlobalVariables.portNo;
socket = new Socket(serverIP, port);
os = new ObjectOutputStream(socket.getOutputStream());
is = new ObjectInputStream(socket.getInputStream());
Log.d("DEBUG", "Connected to Server");
connectionStatus = true;
return true;
} catch (Exception ex) {
Log.d("DEBUG", "Failed to Connect to Server " +ex.toString(), ex.getCause());
connectionStatus = false;
return false;
}
}
public static boolean closeConnection(String message){
try{
socket.close();
Log.d("DEBUG", "Closed connection to Server");
return true;
} catch (Exception ex){
Log.d("DEBUG", "Failed to close connection to Server " +ex.toString(), ex.getCause());
return false;
}
}
private static String sendMessage(String message) {
String returnString;
send(message);
returnString = (String) receive();
if (returnString != null) {
Log.d("DEBUG", "Server returned: " + returnString);
}else{
return returnString = "ERROR";
}
return returnString;
}
// method to send a generic object.
private static void send(Object o) {
try {
Log.d("DEBUG", "Sending: " + o);
os.writeObject(o);
os.flush();
} catch (Exception ex) {
Log.d("DEBUG", "Sending to server " +ex.toString(), ex.getCause());
}
}
// method to receive a generic object.
private static Object receive() {
Object o = null;
try {
o = is.readObject();
} catch (Exception ex) {
Log.d("DEBUG", "Receive from server " +ex.toString(), ex.getCause());
}
return o;
}
/**
* Isprakja poraka do server
* #param message
* #return ili ERROR ili poraka
*/
public synchronized static String sendToServer(String message) {
String rez = "";
try {
rez = sendMessage(message);
} catch (Exception ex) {
Log.d("DEBUG", "Send to server " +ex.toString(), ex.getCause());
}
return rez;
}
public static boolean getCommunicationStatus(){
return connectionStatus;
}
}
I am sending String data to my server (comand;param1;param2....), the server proces that data and returns some data do the android application. The android application is the TCP Client and the java application is the server. For every connection the server creates thread (infinite) that handles that connection. The problem is that my server cant send something without the client sending the request first. The ObjectInputStream readObject() blocks the thread until the client send some data. I want to use the same socket to send in the other direction (java -> android and the android application send some data back) .I know that this can be done by opening another socket where the Android will be the server and the java application will be the client. Is this posible and how?
If you want to be able to concurrently receive data from a client and send data to the client then you'll have to either use two threads per client (one to receive and one to send) or use non-blocking IO.
Related
public class NewClass {
ServerSocket myServerSocket;
boolean ServerOn = true;
public NewClass() {
try {
myServerSocket = new ServerSocket(8888);
} catch (IOException ioe) {
System.out.println("Could not create server socket on port 8888. Quitting.");
System.exit(-1);
}
while (ServerOn) {
try {
Socket clientSocket = myServerSocket.accept();
ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
cliThread.start();
} catch (IOException ioe) {
System.out.println("Exception found on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
try {
myServerSocket.close();
System.out.println("Server Stopped");
} catch (Exception ioe) {
System.out.println("Error Found stopping server socket");
System.exit(-1);
}
}
public static void main(String[] args) {
new NewClass();
}
class ClientServiceThread extends Thread {
Socket myClientSocket;
boolean m_bRunThread = true;
public ClientServiceThread() {
super();
}
ClientServiceThread(Socket s) {
myClientSocket = s;
}
public void run() {
BufferedReader in = null;
PrintWriter out = null;
System.out.println(
"Accepted Client Address - " + myClientSocket.getInetAddress().getHostName());
try {
in = new BufferedReader(new InputStreamReader(myClientSocket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(myClientSocket.getOutputStream()));
while (m_bRunThread) {
String clientCommand = in.readLine();
if (clientCommand != null) {
System.out.println("Client Says :" + clientCommand);
}
if (!ServerOn) {
System.out.print("Server has already stopped");
out.println("Server has already stopped");
out.flush();
m_bRunThread = false;
}
if (clientCommand.equalsIgnoreCase("quit")) {
m_bRunThread = false;
System.out.print("Stopping client thread for client : ");
} else if (clientCommand.equalsIgnoreCase("end")) {
m_bRunThread = false;
System.out.print("Stopping client thread for client : ");
ServerOn = false;
} else {
out.println("Server Says : " + clientCommand);
out.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
out.close();
myClientSocket.close();
System.out.println("...Stopped");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
Client Code
public class Client {
public static void main(String[] args) throws IOException {
Socket s = new Socket(InetAddress.getLocalHost(), 8888);
PrintWriter out =new PrintWriter(s.getOutputStream(), true);
out.print("KKKKKKKKKKKKK \r\n");
out.flush();
out.close();
}
The purpose of the above code is to create server socket and client socket to pass data between server and client.When the client sends the data to server .server grab the message and print it on the screen but with following exception.The pop up from the String clientCommand = in.readLine(); line which appeared on server code.
java.net.SocketException: Connection reset
Your code is invalid. Your server code relies on the client implementing the protocol correctly, which this client doesn't. Bad habit. Defensive coding is required. If clientCommand == null you must exit this read loop and close the socket. Your present code will attempt to write to the closed connection, which produces exactly this exception ... later.
We are creating a java listener to read multiple device data those are configured on particular server ip and port.Device following below rule.
device send a login packet.
server will return ack packet in response.
after receive ack device will send information packet.
server reads that data.
on last step we stuck, we are sending the ack but cant get the information packet back from device(though we check the generated ack through opensource sofware).For ref we are attaching code.(if we remove while(true) than get login packet but after that socket connection will close and again device will send login packet but if we keep it then we dont get any packet)
//--------------Main class------------------------------------------
public class Main {
public static void main(String[] args) {
Server server = new Server(listen_port, pool_size, pm);
new Thread(server).start();
logger.info("Server Started .....");
}
}
//--------------------------------------------------------------
public class Server implements Runnable {
private ServerSocket serverSocket = null;
public void run()
{
this.m_stop = false;
while (!this.m_stop)
try {
this.m_pool.execute(new Handler(this.serverSocket.accept()));
} catch (IOException e) {
LOGGER.debug("Unable to accept connection ", e);
}
}
}
//--------------------------------------------------------------
public class Handler implements Runnable {
private Socket m_clientSocket;
private String imei;
public Handler(Socket socket) {
this.m_clientSocket = socket;
}
public void run() {
DataOutputStream clientDataOS = null;
DataInputStream clientDataIS = null;
try {
logger.info("data is coming");
m_clientSocket.setSoTimeout(300000);
clientDataIS = new DataInputStream(this.m_clientSocket.getInputStream());
clientDataOS = new DataOutputStream(this.m_clientSocket.getOutputStream());
while (true) {
String pkt = "";
logger.info("Waiting for input strem");
byte[] byte_pkt = IOUtils.toByteArray(clientDataIS);
logger.info("Got input stream");
for (byte b : byte_pkt) {
pkt += String.format("%02X ", b);
}
logger.info(pkt);
if (byte_pkt.length > 0) {
logger.info("");
if (Byte.valueOf(byte_pkt[3]) == 1) {
imei = "xyz";
logger.info("login packet");
byte[] rep_pkt = Utils.getReceptionPacket(byte_pkt);//send back to device
clientDataOS.write(rep_pkt);
clientDataOS.flush();
} else if (Byte.valueOf(byte_pkt[3]) == 34) {
logger.info("information packet");
Utils.processPackets(byte_pkt);
} else {
logger.info("Unkown packet format");
}
logger.info(imei);
} else {
logger.info("InputStream is empty.");
}
}
} catch (SocketException se) {
logger.error("Failure on reading data", se);
} catch (IOException e) {
logger.error("Failure on reading data", e);
} catch (Exception e) {
logger.error("Error while processing data", e);
} finally {
try {
IOUtils.closeQuietly(clientDataOS);
IOUtils.closeQuietly(clientDataIS);
this.m_clientSocket.close();
} catch (IOException e) {
logger.debug("Error when sending out response ::", e);
}
}
}
}
Right now I am playing a little arround with Client-Server application for example to communicate via a java application with a raspberry pi which runs a server application.
Well by this I found a problem and I dont find a possible solution. Using the following code I can connect twice to server but after 2 connects it will not accept any more connections. For example I start the Client the first time, and it works everything nicely. Then I close the client and start it again and it works again. But if I close it and start it a 3rd time, it will do nothing. The server will not accept the connection. I tried it with different pcs in my private network but never got a 3rd connection running.
Here is the Code I am running on the server:
public class Receiver {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private ServerSocket serverSocket;
private boolean isRunning;
public Receiver(int port) {
isRunning = true;
try {
serverSocket = new ServerSocket(port);
logger.log(Level.FINER, "start listening at port " + port);
logger.log(Level.FINER, "established successful.");
} catch (IOException e) {
logger.log(Level.SEVERE, "Error while opening socket:\n" + LogUtil.getStackTrace(e));
System.exit(1);
}
}
/**
* server starts to listen at the specific port
*/
public void listenServer() {
logger.log(Level.FINER, "Server is listening");
while (isRunning) {
try {
final Socket clientsocket = serverSocket.accept();
logger.log(Level.FINER, "Server accepted Connection from " + clientsocket.getInetAddress());
new Thread(new Runnable() {
#Override
public void run() {
handleConnection(clientsocket);
}
}).start();
} catch (IOException e) {
logger.log(Level.SEVERE, "Connection with Client failed.");
}
}
}
/**
* handles the given connection
*
* #param clientSocket
* the given client socket for this connection
*/
private void handleConnection(Socket clientSocket) {
ObjectInputStream instream = null;
ObjectOutputStream outstream = null;
try {
outstream = new ObjectOutputStream(clientSocket.getOutputStream());
instream = new ObjectInputStream(clientSocket.getInputStream());
final RequestProcessor processor = new RequestProcessor();
final InetAddress inetAdress = clientSocket.getInetAddress();
logger.log(Level.FINER, "handle connection from " + inetAdress);
Object inob;
while ((inob = instream.readObject()) != null) {
logger.log(Level.FINER, "received Object from " + inetAdress);
final ObjectOutputStream finalOutputStream = outstream;
final Object finalInob = inob;
new Thread() {
public void run() {
setPriority(MAX_PRIORITY);
Object outob;
try {
outob = processor.processObject(finalInob);
logger.log(Level.FINER, "send Respond to: " + inetAdress + " Error: " + (outob instanceof ErrorMessage));
finalOutputStream.writeObject(outob);
finalOutputStream.flush();
} catch (IOException e) {
logger.log(Level.SEVERE, "Connection closed to " + inetAdress);
}
}
}.start();
}
closeConnection(clientSocket, instream, outstream);
} catch (IOException e) {
logger.log(Level.SEVERE, "Connection closed to " + clientSocket.getInetAddress());
} catch (ClassNotFoundException e) {
logger.log(Level.SEVERE, "Connection closed to " + clientSocket.getInetAddress());
} finally {
closeConnection(clientSocket, instream, outstream);
}
}
/**
* closes InputStream, OutputStream and socket
*
* #param socket
* #param instream
* #param outstream
*/
private void closeConnection(Socket socket, InputStream instream, OutputStream outstream) {
this.isRunning = false;
if (instream != null) {
try {
instream.close();
} catch (IOException e) {
}
}
if (outstream != null) {
try {
outstream.close();
} catch (IOException e) {
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
logger.log(Level.FINER, "Connection was closed to client " + socket.getInetAddress());
}
/**
* closes all connections and ends the server
*/
public void endAllConnections() {
this.isRunning = false;
if (this.serverSocket != null)
try {
this.serverSocket.close();
} catch (IOException e) {
// do nothing
}
}
}
and here is the client code which I am using to connect to this server:
public class SocketConnector implements IConnector {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private Socket s;
private ObjectOutputStream oos;
private ObjectInputStream ois;
/**
* creates a new connection
*
* #param host
* given host
* #param port
* given port
*
* #throws UnknownHostException
* #throws IOException
*/
public SocketConnector(String host, int port) throws UnknownHostException, IOException {
logger.log(Level.FINER, "Establish connection to " + host + ":" + port);
s = new Socket(host, port);
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
}
// some methos which use oos and ois.
Does someone maybe know why the server does not accept any more connections when 2 clients connected and disconnected from it? I googled alot arround but didn't find an adequate answer :/
The server log says it doesn't even accept the new connection.
Thanks in advance :)
The situation is:
when calling final Socket clientsocket = serverSocket.accept(); the first time, it's waiting for the first client. when the first client connected, you pass this client to a thread then continue the loop that calls final Socket clientsocket = serverSocket.accept(); the second time. Since starting a thread take more time than going to the next loop, isRunning still is true. In handleConnection(Socket clientSocket), you call closeConnection(clientSocket, instream, outstream); which set isRunning to false. That is the point. When the second client connected, you also pass this client to another thread, then continue the loop where isRunning is false, so the loop is terminated. Hence, you can't get to the third client.
I have this client class "T_Client" in a client-server implementation
T_Client:
public class T_Client{
private static final String TAG = "T_Client";
private static String serverIP = "192.168.2.5";
private static int port = 4444;
private InetAddress serverAddr = null;
private Socket sock = null;
private boolean running = false;
private ObjectInputStream in;
private ObjectOutputStream out;
Object objIn;
public void send(MessageCustom _msg) {
if (out != null) {
try {
out.writeObject(_msg);
out.flush();
// out.close();
Log.i("Send Method", "Outgoing : " + _msg.toString());
} catch (IOException ex) {
Log.e("Send Method", ex.toString());
}
}
}
public void stopClient() {
running = false;
}
public void run() {
running = true;
try {
// here you must put your computer's IP address.
serverAddr = InetAddress.getByName(serverIP);
Log.i("TCP Client", "C: Connecting...");
// create a socket to make the connection with the server
sock = new Socket(serverAddr, port);
try {
// send the message to the server
out = new ObjectOutputStream(sock.getOutputStream());
// receive the message which the server sends back
in = new ObjectInputStream(sock.getInputStream());
Log.i("TCP Client", "C: Connected.");
// in this while the client listens for the messages sent by the
// server
while (running) {
objIn = in.readObject();
Log.i("Object Read", objIn.toString());
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + objIn
+ "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
// the socket must be closed. It is not possible to reconnect to
// this socket
// after it is closed, which means a new socket instance has to
// be created.
out.close();
in.close();
sock.close();
Log.i(TAG, "Closing socket: " + sock);
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
}
And I want to get the Object from the server(objIn) and pass it to the UI thread so I can do some UI updates there. From searching around a bit, I think that I have to use a Handler, but can't really wrap my head around the implementation.
Could someone give me a simple example of how to implement a handler in my case, and make the call in a Main Activity? Or point me to a simple tutorial to get me started, cause I've tried to follow the one over at the Android Developers site but it's too complicated.
My program works fine and many users can connect and send commands to the server.
But when a user spams the server with commands the server blocks out all other clients and the server doesn't receive messages from clients other than the one that spammed.
Why is this?
TCPAccept Connections
package game.server;
import java.io.IOException;
import java.net.Socket;
public class TCPAcceptConnections implements Runnable
{
public static Socket clientSocket = null;;
int clientID = -1;
public void run()
{
while(Main.TCP)
{
try
{
clientSocket = TCPServer.serverSocket.accept();
System.out.println("Client Connected.");
clientID++;
new TCPClientManager(clientSocket, clientID).run();
}
catch (IOException e)
{
System.out.println("Couldn't create client socket.");
System.exit(-1);
}
}
}
}
TCPClientManager:
package game.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TCPClientManager implements Runnable
{
Socket client;
int clientID;
static PrintWriter out;
static BufferedReader in;
String inputLine, outputLine;
boolean destroy = false;
public TCPClientManager(Socket cs, int id)
{
try
{
client = cs;
clientID = id;
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch(IOException e)
{
e.printStackTrace();
}
}
public void run()
{
System.out.println("Created TCPManager for client.");
String command;
while(!destroy)
{
try
{
if((command = in.readLine()) != null) //If received something
{
System.out.println("Commad received: " + command);
System.out.println(" " + Commands.proccessCommand(command));
System.out.println("Command proccessed");
}
else
{
client.close();
destroy = true;
}
} catch (IOException e)
{
try
{
client.close();
} catch (IOException e1)
{
e1.printStackTrace();
destroy = true;
}
System.out.println("Client lost connection.");
destroy = true;
}
}
System.out.println("TCPManager for client destroyed.");
}
}
Commands:
package game.server;
public class Commands
{
public static String proccessCommand(String command)
{
if(command.equalsIgnoreCase("cp"))
{
System.out.println("Creating player...");
System.out.println(" Retrieved client");
return "Player Created";
}
else
{
return "Unkown command: " + command;
}
}
}
If you get an unknown command, you should log it and close the connection.
But you have a more severe problem. You aren't stopping the client handler when it reads null. So once a client disconnects the read will spin futilely forever. If readLine() returns null you must close the socket and exit the loop. If you get any IOException you must also close the socket.