I write some client-server communication.
My server:
public class Server {
public synchronized static void sendPacket(Packet packet,
ObjectOutputStream server) {
try {
server.writeObject(packet);
server.flush();
} catch (IOException e) {
Log.d(TAG, "Error while sending a packet. Output stream is unaviable.");
}
}
public synchronized static Packet readPacket(ObjectInputStream sourceStream) {
Packet recivedPacket = null;
try {
recivedPacket = (Packet) sourceStream.readObject();
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return recivedPacket;
}
/** Register user on the server */
private User registerUser(Socket socket) {
ClientUserLoginPacket newUserPacket = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
Log.i(TAG, "Opening output stream...");
oos = new ObjectOutputStream(socket.getOutputStream());
if (oos != null)
Log.d(TAG, "Output stream opened");
Log.i(TAG, "Opening input stream...");
ois = new ObjectInputStream(socket.getInputStream());
if (ois != null)
Log.d(TAG, "Input stream opened");
} catch (StreamCorruptedException e1) {
Log.e(TAG, "Error while opening stream");
} catch (IOException e1) {
e1.printStackTrace();
}
// First packet MUST be register request
try {
Log.d(TAG, "Waiting for login packet from client...");
newUserPacket = (ClientUserLoginPacket) readPacket(ois);
Log.d(TAG, "Login packet from recived...");
} catch (Exception e) {
Log.e(TAG, "Can't recive login packet.");
}
User newUserInstance = null;
// TODO check if exists. or to map in the future
if (newUserPacket != null) {
newUserInstance = new User(socket, ois, oos, newUserPacket.nick);
users.add(newUserInstance);
Log.d(TAG, "User " + newUserPacket.nick + " registered.");
Server.sendPacket(new ServerLoginAcceptedPacket(), oos);
Log.d(TAG, "User accept confirmation sent.");
}
return newUserInstance;
}
#Override
public void run() {
Log.i(TAG, "Starting server...");
ServerSocket server;
try {
server = new ServerSocket(PORT);
Log.i(TAG, "Server started.");
server.setSoTimeout(0);
while (true) {
Log.i(TAG, "Waiting for players...");
final Socket socket = server.accept();
Log.i(TAG, "New player connected.");
new Thread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "Try to register new player.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
User user = registerUser(socket);
while (true) {
Log.i(TAG, "Waiting for packets from " + user.nick+"...");
Packet packet = readPacket(user.ois);
Log.i(TAG, "Packet from " + user.nick + " recived.");
if (packet instanceof ...) {
...
}
}
}
}).start();
}
} catch (IOException e) {
Log.i(TAG, "Port is busy.");
}
}
private class User {
public Socket connection;
public ObjectInputStream ois;
public ObjectOutputStream oos;
public String nick;
public boolean inGame;
public User(Socket socket, ObjectInputStream ois,
ObjectOutputStream oos, String nick) {
this.connection = socket;
this.ois = ois;
this.oos = oos;
this.nick = nick;
}
// ...
}
My client:
public class Client {
callbackHandler = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
Log.e(TAG, "Waiting for incomeing packets...");
Packet packet = (Packet) Server.readPacket(serverInput);
Log.e(TAG, "Packet recived.");
if (packet instanceof ServerLoginAcceptedPacket) {
Log.e(TAG, "Recived packet is "
+ packet.getClass().toString());
Intent intent = new Intent(MyActivity.this,
MainMenuActivity.class);
MyActivity.this.startActivity(intent);
}
}
}
});
public void connectToServer() {
SocketAddress sockaddr = new InetSocketAddress(mEditTextIp.getText()
.toString(), Server.PORT);
server = new Socket();
try {
server.setSoTimeout(1000);
Log.d(TAG, "Connecting to server.");
server.connect(sockaddr, Server.PORT);
Log.d(TAG, "Connected to server.");
} catch (IOException e) {
Log.e(TAG, "Can't connect to server.");
server = null;
}
if (server != null)
try {
server.setSoTimeout(0);
Log.d(TAG, "Opening output stream...");
serverOutput = new ObjectOutputStream(server.getOutputStream());
if (serverOutput != null)
Log.d(TAG, "Output stream opened");
else
Log.e(TAG, "Error while opening output stream");
} catch (IOException e) {
Log.e(TAG, "Server socket probably closed");
}
}
public void requestLogin() {
new Thread(new Runnable() {
#Override
public void run() {
Log.e(TAG, "Sending login packet...");
Server.sendPacket(new ClientUserLoginPacket(mEditTextLogin
.getText().toString(), ""), serverOutput); // TODO send
// pass and
// email
Log.e(TAG, "Login packet send");
}
}).start();
}
public void authenticate(View v) {
if (server == null)
connectToServer();
if (server != null) {
requestLogin();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
serverInput = new ObjectInputStream(server.getInputStream());
} catch (StreamCorruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (serverInput != null) {
Log.e(TAG, "Start reciving callbacks...");
callbackHandler.start();
} else {
Log.d(TAG, "Can't open input stream to server.");
}
}
}
public void runServer(View v) {
new Thread(new Server()).start();
Toast.makeText(this, "Server running...", 1000).show();
}
}
Where runServer() and authenticate() functions are triggered with button.
Problem is that after server recive ClientLoginPacket, all subsequent sentPacket functions hangs on oos.writeObject().
I think the order of reading/writing from/to streams may be wrong.
What should be correct order of opening streams and writing objects to them?
Do I have to write something to ObjectOutputStream before opening ObjectInputStream?
After few hours I found that keywords synchronized before my methods readPacket() and sendPacket() were problem. ;)
Related
I am trying to connect an Android device to a java server. It works perfectly when I use the emulator but when I port it onto my phone there is no connection.
The aim of the code is to send a value from client to server, perform a calculation on it and return it back to the client to be displayed.
This is my server code:
public class ServerTest {
public static final int PORT_NUMBER = 8000;
protected Socket socket;
private ServerTest(Socket socket) {
this.socket = socket;
System.out.println("New client connected from " + socket.getInetAddress().getHostAddress());
connect();
}
public void connect() {
InputStream in = null;
OutputStream out = null;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String request = br.readLine();
if (request.equals("end")) {
System.out.println("Message received: " + request + ". Ending connection.");
request = "End Connection";
out.write(request.getBytes());
in.close();
out.close();
socket.close();
System.exit(0);
} else {
System.out.println("Message received: " + request);
request = calculatePi(request);
System.out.println("Output: " + request);
out.write(request.getBytes());
}
} catch (IOException ex) {
System.out.println("Unable to get streams from client");
} finally {
try {
in.close();
out.close();
socket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) {
System.out.println("Welcome. IP address is: " + getIP());
ServerSocket server = null;
try {
server = new ServerSocket(PORT_NUMBER);
while (true) {
new ServerTest(server.accept());
}
} catch (IOException ex) {
System.out.println("Unable to start server.");
} finally {
try {
if (server != null)
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private static String getIP() {
String ip = "";
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
// filters out 127.0.0.1 and inactive interfaces
if (iface.isLoopback() || !iface.isUp())
continue;
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while(addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
// *EDIT*
if (addr instanceof Inet6Address) continue;
ip = addr.getHostAddress();
}
}
} catch (SocketException e) {
throw new RuntimeException(e);
}
return ip;
}
and this is my client side code on device:
public class MainActivity extends AppCompatActivity {
TextView piResultTextView;
EditText addressEditText, messageEditText;
Button connectButton;
Handler handler = new Handler();
Results results;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
results = new Results();
addressEditText = findViewById(R.id.AddressEditText);
messageEditText = findViewById(R.id.MessageEditText);
connectButton = findViewById(R.id.ConnectButton);
connectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
connect();
}
});
piResultTextView = findViewById(R.id.PiResultTextView);
}
public void connect() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
String hostAddress = addressEditText.getText().toString();
int port = 8000;
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket(hostAddress, port);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e) {
Toast.makeText(getApplicationContext(), "Unknown host: " + hostAddress, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Unable to get streams from server", Toast.LENGTH_SHORT).show();
}
String input = messageEditText.getText().toString();
try {
out.println(input);
results.pi = in.readLine();
handler.post(new Runnable() {
#Override
public void run() {
piResultTextView.setText(results.pi);
}
});
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Unable to read input stream from server", Toast.LENGTH_SHORT).show();
}
try {
out.close();
in.close();
echoSocket.close();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Error closing streams", Toast.LENGTH_SHORT).show();
}
}
});
thread.start();
}
}
This question already has an answer here:
java.net.SocketException socket is closed
(1 answer)
Closed 5 years ago.
I have a application to connect 2 device using socket. In Client, i try send and receive data. When i send data from Client, the Server can receive data and reply a other message. But when i open InputStream to catch receive from server, it show notify (IOException: java.net.SocketException: Socket is closed).
Please help me. ##
CODE IN CLIENT:
Socket socket = null;
String mes = message;
try {
socket = new Socket(dstAddress, dstPort);
/*Example send data to server*/
ops = socket.getOutputStream();
ps = new PrintStream(ops);
ps.print(mes);
ps.close();
/*End of example*/
/*Receive data from server*/
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(
1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
/*End of Receive data from server*/
Log.e("Receive From Server:", response);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
AND THIS CODE OF SERVER
private class SocketServerThread extends Thread {
int count = 0;
#Override
public void run() {
try {
serverSocket = new ServerSocket(socketServerPORT);
while (true) {
Socket socket = serverSocket.accept();
count++;
/*example get input String*/
try {
isr = new InputStreamReader(socket.getInputStream());
br = new BufferedReader(isr);
request = br.readLine();
Log.e("Mess-H.a", request);
}catch (Exception e){
Log.e("Can't receive data:", e.getMessage() );
}
message += "#" + count + " from "
+ socket.getInetAddress() + ":"
+ socket.getPort() + request + "\n";
/*End of example*/
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread(
socket, count);
socketServerReplyThread.run();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class SocketServerReplyThread extends Thread {
private Socket hostThreadSocket;
int cnt;
SocketServerReplyThread(Socket socket, int c) {
hostThreadSocket = socket;
cnt = c;
}
#Override
public void run() {
OutputStream outputStream;
String msgReply = "Hello from Server, you are #" + cnt;
try {
outputStream = hostThreadSocket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.print(msgReply);
printStream.close();
message += "replayed: " + msgReply + "\n";
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
message += "Something wrong! " + e.toString() + "\n";
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.msg.setText(message);
}
});
}
}
You closed the socket and then continued to use it.
ps.close();
Here. Remove.
I am trying to connect my App to the bluetooth device and after that i am doing the functionality Read and Write. I am able to do connectivity and Write command to device. But i am not able to do Read functionality.
The "Read" functionality is like, as soon as device socket will get connect to the App, it should send the device information continuously. But i my case, read() method is calling but every time i am getting the length on InputStream in 0.
Below is the code what i am writing. Please check it where i am going wrong and please help me.
public class ConnectionThread implements Runnable {
private static final String CLASSTAG = ConnectionThread.class.getSimpleName();
public static BluetoothSocket mSocket;
private InputStream inStream;
private OutputStream outStream;
private boolean canceled = false;
private Context mContext;
public ConnectionThread(Context context, BluetoothDevice device) {
this.mContext = context;
try {
mSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(Constants.mUUID));
} catch (IOException e) {
Log.e(CLASSTAG, "createRfcommSocketToServiceRecord", e);
}
}
#SuppressLint("NewApi")
#Override
public void run() {
// Cancel discovery because it will slow down the connection
if(BluetoothAdapter.getDefaultAdapter().isDiscovering()) {
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
}
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mSocket.connect();
} catch (IOException e) {
Log.e(CLASSTAG, "connect failed", e);
// Unable to connect; close the socket and get out
disconnect();
return;
}
// Get the input and output streams, using temp objects because
// member streams are final
try {
inStream = mSocket.getInputStream();
outStream = mSocket.getOutputStream();
} catch (IOException e) {
Log.e(CLASSTAG, "IO streams init failed", e);
disconnect();
return;
}
while (!canceled) {
read();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Log.e(CLASSTAG, "sleep failed", e);
}
}
}
#SuppressLint("NewApi")
public void applyCommand(String configCommand) throws IOException {
byte[] bytes = null;
bytes = new BigInteger(configCommand,16).toByteArray();
if (mSocket.isConnected()) {
//write(bytes);
outStream.write(bytes);
Log.d(CLASSTAG, "Command apply: " + bytes + " (" + configCommand + ")");
}
Toast.makeText(mContext, mContext.getString(R.string.cmd_updated), Toast.LENGTH_LONG).show();
}
private void read() {
byte[] buffer = new byte[128];
// Keep listening to the InputStream while connected
try {
// Read from the InputStream
if (inStream.available() > 0) {
int bytes = inStream.read(buffer);
if (bytes > 0) {
Log.d(CLASSTAG, "Response: " + new String(buffer, 0, bytes));
}
}
// Send the obtained bytes to the UI Activity
// mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(CLASSTAG, "reading from input stream failed", e);
disconnect();
}
}
public void disconnect() {
try {
if (outStream != null) {
outStream.close();
}
if (inStream != null) {
inStream.close();
}
mSocket.close();
canceled = true;
} catch (IOException e) {
Log.e(CLASSTAG, "close socket", e);
}
}
}
I'm making a app which can send a character ("B") to activate microcontroller then accept the result data from it. The data will be numbers 0-100. However I'm stuck in converting stream data to string.
I've tried the codes in comment but the process ended up being looping forever.
Here is my codes :
public Bluetooth(startover so, Handler handler, ProgressDialog pd) {
// TODO Auto-generated constructor stub
this.handler=handler;
activity=so;
this.pd=pd;
}
#Override
public void run() {
// TODO Auto-generated method stub
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
try
{
btSocket =device.createRfcommSocketToServiceRecord(MY_UUID);
//Toast.makeText(this, "Bluetooth_socket is created", Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
Log.e(TAG, "ON RESUME: Socket creation failed.", e);
}
try
{
btSocket.connect();
Log.e(TAG, "ON RESUME: BT connection established, datatransfer link open.");
//Toast.makeText(this, "Bluetooth_socket is connected", Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
try
{
btSocket.close();
}
catch (IOException e2)
{
Log.e(TAG, "ON RESUME: Unable to close socket during connection failure", e2);
}
}
message = "B";
sendMessage(message);
InputStream mInput=null;
try {
mInput = btSocket.getInputStream();
System.out.println("Input Open");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(!Thread.currentThread().isInterrupted() && mBluetoothAdapter.isEnabled()) {
try {
int bytesAvailable = mInput.available();
if(bytesAvailable > 0) {
System.out.println("Pesan Diterima");
BufferedReader r = new BufferedReader(new InputStreamReader(mInput));
StringBuilder total = new StringBuilder(bytesAvailable);
String line;
//BACA LEBIH DARI 1 KARAKTER
//while ((line = r.readLine()) != null) {
// total.append(line);
//}
final String message=total.toString();
handler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
pd.dismiss();
System.out.println("Turn "+message);
activity.startActivity(new Intent(activity.getApplicationContext(),result.class).putExtra("data", message));
}
});
break;
}
}
catch (IOException ex) {
}
}
super.run();
}
private void sendMessage (String message) {
byte[] send = message.getBytes();
try {
OutputStream OutStream = btSocket.getOutputStream();
OutStream.write(send);
System.out.println("Send "+message);
}
catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
}
I'm using an AsyncTask to establish a TCP Connection and sending/receiving data through it.
My current Code looks like this at the moment:
public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {
Socket nsocket; //Network Socket
InputStream nis; //Network Input Stream
OutputStream nos; //Network Output Stream
boolean bSocketStarted = false;
byte[] buffer = new byte[4096];
#Override
protected void onPreExecute() {
Log.i(TAG, "onPreExecute");
}
#Override
protected Boolean doInBackground(Void... params) { //This runs on a different thread
boolean result = false;
try {
// Connect to address
Log.i(TAG, "doInBackground: Creating socket");
SocketAddress sockaddr = new InetSocketAddress("google.de", 80);
nsocket = new Socket();
nsocket.connect(sockaddr, 5000); //10 second connection timeout
if (nsocket.isConnected()) {
bSocketStarted = true;
nis = nsocket.getInputStream();
nos = nsocket.getOutputStream();
Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
int read = nis.read(buffer, 0, 4096); //This is blocking
while(bSocketStarted) {
if (read > 0){
byte[] tempdata = new byte[read];
System.arraycopy(buffer, 0, tempdata, 0, read);
publishProgress(tempdata);
Log.i(TAG, "doInBackground: Got some data");
}
}
}
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "doInBackground: IOException");
result = true;
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "doInBackground: Exception");
result = true;
} finally {
try {
nis.close();
nos.close();
nsocket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.i(TAG, "doInBackground: Finished");
}
return result;
}
public boolean SendDataToNetwork(final byte[] cmd) { //You run this from the main thread.
// Wait until socket is open and ready to use
waitForSocketToConnect();
if (nsocket.isConnected()) {
Log.i(TAG, "SendDataToNetwork: Writing received message to socket");
new Thread(new Runnable() {
public void run() {
try {
nos.write(cmd);
}
catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "SendDataToNetwork: Message send failed. Caught an exception");
}
}
}
).start();
return true;
}
else
Log.i(TAG, "SendDataToNetwork: Cannot send message. Socket is closed");
return false;
}
public boolean waitForSocketToConnect() {
// immediately return if socket is already open
if (bSocketStarted)
return true;
// Wait until socket is open and ready to use
int count = 0;
while (!bSocketStarted && count < 10000) {
try {
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
count += 500;
}
return bSocketStarted;
}
#Override
protected void onProgressUpdate(byte[]... values) {
try {
if (values.length > 0) {
Log.i(TAG, "onProgressUpdate: " + values[0].length + " bytes received.");
String str = new String(buffer, "UTF8");
Log.i(TAG,str);
tv.setText(str);
tv.setMovementMethod(new ScrollingMovementMethod());
}
} catch (Exception e) {
e.printStackTrace();
}
finally {}
}
#Override
protected void onCancelled() {
Log.i(TAG, "Cancelled.");
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
Log.i(TAG, "onPostExecute: Completed with an Error.");
} else {
Log.i(TAG, "onPostExecute: Completed.");
}
}
}
I can instantiate the Task and call SendDataToNetwork from my activity. However, all the text I pass to SendDataToNetwork, for example, 'GET / HTTP/1.1' is continously sent to the server.
How can I modify my Code to maintain the connection in doInBackground and do nothing until I call SendDataToNetwork and after sending bytes to the server just wait until new data is ready to be sent? Basically I want to run the AsyncTask until I explicitly cancel (= close the connection) it.
nsocket.connect(sockaddr, 5000); //10 second connection timeout
if (nsocket.isConnected()) {
The test is pointless. If the socket wasn't connected, connect() would have thrown an exception.
Your read loop is also fundamentally flawed, in that it doesn't keep reading. There are standard solutions as to how to read a stream, e.g.:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Your waitForSocketToConnect() method doesn't really do anything useful either.
You need to rethink all this.