This question already has answers here:
Java Socket why server can not reply client
(4 answers)
Closed 3 years ago.
My android app is supposed to send data to the server through socket but also occasionally receive data from that server. To do that I am using service and.
Sending data to the server works ok, I'm using service method that i'm calling from activity. But while sending works just fine my app doesnt receive any data back. While I send string "pp" I should get another sring back from server but that just doesn't happen. What am I doing wrong?
My service:
public class MyService extends Service {
private Socket socket;
public static PrintWriter out;
private BufferedReader in;
private String line;
private final IBinder binder = new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MyBinder extends Binder {
MyService getMyService() {
return MyService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName("10.0.2.2");
socket = new Socket(serverAddr,8998);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket
.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Thread thread = new Thread(new Listener());
thread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
return START_STICKY;
}
private class Listener implements Runnable{
#Override
public void run() {
while(true){
try {
line = in.readLine();
if(line!=null) Log.d(line,line); //never shows up in logcat
line=null;
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void send(String line){
out.println(line);
}
}
And my server:
public class Server {
private static final int SERVER_PORT = 8998;
private static ServerSocket server = null;
private static Socket client = null;
private static BufferedReader in = null;
private static boolean isConnected = true;
private static String line;
public static void main(String[] args){
while(isConnected){
if(server==null || server.isClosed()){
try{
server = new ServerSocket(SERVER_PORT);
client = server.accept();
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("Connected");
}catch (IOException e){
System.out.println("Error in opening Socket"+e);
System.exit(-1);
}
}
else{
try{
line = in.readLine();
if(line != null)
{
if(line.equals("pp")){
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(client.getOutputStream())),
true);
String toSend = "String to send";
out.write(toSend);
System.out.println("sent");
}
System.out.println(line);
}else if(in.read()==-1){
client.close();
server.close();
}
}catch (IOException e){
System.out.println("Read from client failed");
System.exit(-1);
}
}
}
}
}
Usual problems.
You are reading lines but you aren't writing lives. Add a line terminator.
You should stop reading when readLine() returns null, and close the socket.
Once readLine() has returned null, the extra read test is pointless. It will always return -1.
Related
I'm writing a TCP multi Client/Server app that works in an infinite loop.
What happens:
Client types "COMMANDS" and expects to get available commands from server.
Server sends lines to client.
Client reads server input line-by-line and is stuck after the last one is written.
Expected result:
Client is prompted for keyboard input.
Input is written to server.
Server sends back text.
Client reads server input line-by-line.
End of loop.
user types commands > server responds > user gets to type commands again
I know that BufferedReader would stop reading lines once I close the socket. However, that's not what we want since it has to work infinitely.
How do I exit the loop?
Client method:
public class Client {
private final Socket clientSocket;
private final BufferedReader clientInput;
private final PrintWriter clientOutput;
private final BufferedReader keyboardInput;
public Client() throws IOException {
this.clientSocket = new Socket(InetAddress.getLocalHost(), 13370);
this.clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
this.clientOutput = new PrintWriter(clientSocket.getOutputStream(), true);
this.keyboardInput = new BufferedReader(new InputStreamReader(System.in));
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.init();
}
private void init() {
try {
while (true) {
System.out.print("> ");
String args = keyboardInput.readLine().trim().replaceAll("\\s+", " ");
clientOutput.println(args.toUpperCase());
// the loops doesn't seem to stop after reading all input lines
String line;
while ((line = clientInput.readLine()) != null) {
System.out.println(line);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ClientHandler implements Runnable {
private final int id;
private final Socket clientSocket;
private final PrintWriter serverOutput;
private final BufferedReader serverInput;
// private final ClientFiles clientFiles;
public int getId() {
return id;
}
public ClientHandler(int id, Socket clientSocket) throws IOException {
this.id = id;
this.clientSocket = clientSocket;
this.serverInput = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
this.serverOutput = new PrintWriter(this.clientSocket.getOutputStream(), true);
// this.clientFiles = new ClientFiles(id, clientSocket);
}
#Override
public void run() {
try {
String command;
while ((command = serverInput.readLine()) != null) {
executeCommand(command.split(" "));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeConnection();
removeFromHosts();
}
}
private void executeCommand(String[] input) throws IOException {
String command = input[0];
// String option = input[1];
switch (command) {
case "COMMANDS": {
getCommands();
break;
}
// case "LIST_LOCAL": {
// listFiles();
// break;
// }
// case "LIST_FILES": {
// listFiles(option);
// }
// case "PULL": {
// pull(clientSocket, option);
// }
// case "PUSH": {
// push(clientSocket, option);
// }
case "DISCONNECT": {
closeConnection();
break;
}
default: {
write("Invalid command.");
getCommands();
break;
}
}
}
private String read() throws IOException {
return serverInput.readLine();
}
private void write(String message) {
serverOutput.println(message);
}
private void getCommands() {
write("AVAILABLE COMMANDS:");
write("\tCOMMANDS");
write("\t\tlists available commands");
write("\tLIST_HOSTS");
write("\t\tlists hosts connected to server");
write("\tLIST_FILES");
write("\t\tlists files from all hosts connected server");
write("\tLIST_LOCAL");
write("\t\tlists local files");
write("\tLIST_FILES [HOSTS]...");
write("\t\tlists files from provided hosts connected server");
write("\tPULL [HOST] [FILE]");
write("\t\tdownloads file from host");
write("\tPUSH [HOST] [FILE]");
write("\t\tuploads file to host");
write("\tDISCONNECT");
write("\t\tdisconnects client from server");
}
private void closeConnection() {
try {
serverInput.close();
serverOutput.close();
clientSocket.close();
removeFromHosts();
} catch (IOException e) {
e.printStackTrace();
}
}
private void removeFromHosts() {
Server.getClients().remove(this);
}
}
Server just accepts new clients and starts new threads.
public class Server {
private static final AtomicInteger count = new AtomicInteger(1);
private static final ArrayList<ClientHandler> clients = new ArrayList<>();
public static void main(String[] args) {
Server.init();
}
public static void init() {
System.out.println("Opening server socket...");
try (
ServerSocket serverSocket = new ServerSocket(13370)
) {
System.out.println("Server socket opened at port: " + serverSocket.getLocalPort());
while (true) {
System.out.println("Waiting for client connection...");
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected.");
ClientHandler client = new ClientHandler(count.getAndIncrement(), clientSocket);
clients.add(client);
System.out.println(clients);
new Thread(client, "client-" + client.getId()).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static ArrayList<ClientHandler> getClients() {
return clients;
}
}
your client is waiting for more lines.
In your code
while ((line = clientInput.readLine()) != null) {
System.out.println(line);
}
clientInput.readLine() will never return null if server does not close the connection. The execution stops waiting more data.
I suggest to implements a solution like insert an empty line or a special char to signal the client that the response to the command is finished.
I have a JavaFX app which reads the input of a number and then sends it to a server. The server calculates the sum of its digits and then gives the result back to the app. Im using the Task class in order to not alter the main thread of the application.
Part of the code of the app
calculate.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Task<String> task = new Task<String>() {
String result_from_server;
#Override
protected String call() throws Exception {
try(Socket socket = new Socket("localhost",PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))){
warning.setText("");
result.setText("");
if(!input.getText().equalsIgnoreCase("")){
out.print(input.getText());
result_from_server = in.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
return result_from_server;
}
};
task.setOnSucceeded(event1 -> {
result.setText(task.getValue());
});
new Thread(task).start();
}
});
The server
public class QuersummeServer{
static final int PORT = 4444;
public static void main(String[] args){
try(ServerSocket ss = new ServerSocket(PORT);
Socket cs = ss.accept();
PrintWriter out = new PrintWriter(cs.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(cs.getInputStream()))){
String number = in.readLine();
int result = calculate(number);
out.print(result);
}catch (IOException e){
e.printStackTrace();
}
}
private static int calculate(String number) {
int result = 0;
for(int i = 0;i<number.length();i++){
result+= Integer.valueOf(number.substring(i,i+1));
}
return result;
}}
At the end nothing happens, what is wrong?
Thanks in advance
Edit: I figured out that the server blocks after in.readLine() but I dont know why
Try in the client class after out.print(input.getText()); to call out.flush()
Try to do some concurrent messaging between the server and the client. When they first connect to eachother and the Server sends the test string, the client gets it perfectly fine the first time. And the client can SEND messages just fine to the Server. But my Client class cant constantly check for messages like my Server can and idk what's wrong. Any suggestions?
Server class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
String testMessage = "You are now connected and can begin chatting!";
boolean connected = false;
int port;
public Server(int port) {
this.port = port;
}
public void Open() {
//creates Threadpool for multiple instances of chatting
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
System.out.println("Opening...");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (Exception e) {
try {
System.out.println(e);
System.out.print("You're opening too many servers in the same location, fool!\n");
ServerSocket srvr = new ServerSocket(port);
while (true) {
Socket skt = srvr.accept();
clientProcessingPool.submit(new ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
//for sending messages
if (connected == false) {
System.out.println("======================");
System.out.println("Server has connected!");
processMessage(testMessage);
}
//for receiving messages
while (true) {
try {
// Read one line and output it
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//br.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println("Server had error receiving message.");
System.out.println("Error: " + e);
}
}
}
//for processing a message once it is received
public void processMessage(String message) {
PrintWriter out = null;
try {
out = new PrintWriter(skt.getOutputStream(), true);
} catch (IOException ex) {
System.out.println(ex);
System.out.println("Server had error sending message.");
}
System.out.print("Server: Sending message: " + message + "\n");
out.print(message);
out.flush();
connected = true;
try {
skt.shutdownOutput();
//out.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Client class code:
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
class Client {
public String message;
Socket skt;
public int port;
public Client(int port) {
this.port = port;
}
//for receiving messages from Server
public void receiveMessage() {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
while (true) {
clientProcessingPool.submit(new Client.ClientTask(skt));
}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
//for sending messages to Server
public void sendMessage(String outgoingMessage) throws IOException {
try {
skt = new Socket(InetAddress.getLocalHost().getHostName(), port);
PrintWriter pw = new PrintWriter(skt.getOutputStream());
System.out.println("Client: Sending message: " + outgoingMessage);
pw.print(outgoingMessage);
pw.flush();
skt.shutdownOutput();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.println(e);
System.out.print("Client had error sending message.\n");
JOptionPane.showMessageDialog(null, "That User is not currently online.", "ERROR!!", JOptionPane.INFORMATION_MESSAGE);
}
}
private class ClientTask implements Runnable {
private final Socket skt;
private ClientTask(Socket skt) {
this.skt = skt;
}
#Override
public void run() {
while (true) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(skt.getInputStream()));
//while (!in.ready()) {}
String incomingMessage = in.readLine();
if (incomingMessage != null) {
System.out.println("Client: Received message: " + incomingMessage); // Read one line and output it
message = incomingMessage;
}
//skt.shutdownInput();
//in.close();
//skt.close(); //maybe delete
} catch (Exception e) {
System.out.print("Client had error receiving message.\n");
}
}
}
}
}
Streams cannot be re-wrapped. Once assigned to a wrapper, they must use that wrapper for the entire life-cycle of the stream. You also shouldn't close a stream until you are done using it, which in this case isn't until your client and server are done communicating.
In your current code, there are a few times where you re-initialize streams:
while (true) {
try {
//Each loop, this reader will attempt to re-wrap the input stream
BufferedReader br = new BufferedReader(new InputStreamReader(skt.getInputStream()));
String incomingMessage = br.readLine();
if (incomingMessage != null) {
System.out.println("Server: Received message: " + incomingMessage);
processMessage(incomingMessage);
}
//don't close your stream and socket so early!
br.close();
skt.close();
} catch (Exception e) {
//...
}
You get the idea; you can use this knowledge to find the stream problems in your client code as well.
With that said, servers are the middle-man between multiple clients. If you want to be able to type in the server's console to send a message to clients, it shouldn't go to only 1 client (unless you had a system that allowed you to specify a name). You need to store every connection in some kind of collection so when you type in the server's console, it goes to every client that's connected. This also helps when a client wants to send a message to every other client (global message). The server's main thread is primarily for accepting clients; I created another thread to allow you to type in the console.
As for your streams, you should create them whenever you start the ClientTask, both server side and client side:
public class Server {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private Set<User> users = new HashSet<>();
private boolean running;
private int port;
public Server(int port) {
this.port = port;
}
public void start() {
running = true;
Runnable acceptor = () -> {
try(ServerSocket ss = new ServerSocket(port)) {
while(running) {
User client = new User(ss.accept());
users.add(client);
executor.execute(client);
}
} catch(IOException e) {
//if a server is already running on this port;
//if the port is not open;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try(Scanner scanner = new Scanner(System.in)) {
while(running) {
String input = scanner.nextLine();
for(User user : users) {
user.send(input);
}
}
} catch(IOException e) {
//problem sending data;
e.printStackTrace();
}
};
Thread acceptorThread = new Thread(acceptor);
Thread userThread = new Thread(userInputReader);
acceptorThread.start();
userThread.start();
}
public void stop() {
running = false;
}
public static void main(String[] args) {
new Server(15180).start();
System.out.println("Server started!");
}
}
In the run() method is where the streams should be wrapped.
class User implements Runnable {
private Socket socket;
private boolean connected;
private DataOutputStream out; //so we can access from the #send(String) method
public User(Socket socket) {
this.socket = socket;
}
public void run() {
connected = true;
try(DataInputStream in = new DataInputStream(socket.getInputStream())) {
out = new DataOutputStream(socket.getOutputStream());
while(connected) {
String data = in.readUTF();
System.out.println("From client: "+data);
//send to all clients
}
} catch(IOException e) {
//if there's a problem initializing streams;
//if socket closes while attempting to read from it;
e.printStackTrace();
}
}
public void send(String message) throws IOException {
if(connected) {
out.writeUTF(message);
out.flush();
}
}
}
It's pretty much the same idea with the client:
1. Connect to Server
2. Create "communication" thread
3. Create "user input" thread (to receive input from console)
4. Start threads
public class Client {
private final String host;
private final int port;
private boolean connected;
private Socket socket;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws IOException {
connected = true;
socket = new Socket(host, port);
Runnable serverInputReader = () -> {
try (DataInputStream in = new DataInputStream(socket.getInputStream())) {
while (connected) {
String data = in.readUTF();
System.out.println(data);
}
} catch (IOException e) {
// problem connecting to server; problem wrapping stream; problem receiving data from server;
e.printStackTrace();
}
};
Runnable userInputReader = () -> {
try (DataOutputStream out = new DataOutputStream(socket.getOutputStream());
Scanner scanner = new Scanner(System.in)) {
while (connected) {
String input = scanner.nextLine();
out.writeUTF(input);
}
} catch (IOException e) {
//problem wrapping stream; problem sending data;
e.printStackTrace();
}
};
Thread communicateThread = new Thread(serverInputReader);
Thread userThread = new Thread(userInputReader);
communicateThread.start();
userThread.start();
}
public static void main(String[] args) throws IOException {
new Client("localhost", 15180).start();
}
}
There are a few things I used in the code above that you may not be familiar with. They help simplify the syntax for your code:
Lambda Expressions - Prevents the need to create an anonymous class (or subclass) to declare a method
Try-With-Resources - Closes the resources specified automatically once the try block as ended
EDIT
When a user connects, you should store their connection by name or id. That way, you can send data to specific users. Even if your client is running on the same machine as the server, it's still the same idea: client connects to server, server sends message to client based on name or id:
while(running) {
User client = new User(ss.accept());
users.add(client); //add to set
executor.execute(client);
}
Right now, you are simply adding users to a Set. There is currently no way to grab a specific value from this set. What you need to do is give it some kind of "key". To give you an idea, here's an old algorithm I used to use. I have an array full of empty slots. When someone connects, I look for the first empty slot. Once an empty slot is found, I pass the user the index of the array it's being stored at (that will be the user's id), then store the user in the array at the specified index. When you need to send a message to someone, you can use the id to access that specific array index, grab the user you want and send a message:
class Server {
private int maxConnections = 10;
private ExecutorService executor = Executors.newFixedThreadPool(maxConnections);
private User[] users = new User[maxConnections];
//...
while(running) {
Socket socket = ss.accept();
for(int i = 0; i < users.length; i++) {
if(users[i] == null) {
users[i] = new User(socket, i);
executor.execute(users[i]);
break;
}
}
}
//...
public static void sendGlobalMessage(String message) throws IOException {
for(User user : users)
if(user != null)
user.send(message);
}
public static void sendPrivateMessage(String message, int id) {
User user = users[id];
if(user != null) {
user.send(message);
}
}
}
class User {
private Socket socket;
private int id;
private DataOutputStream out;
public User(Socket socket, int id) {
this.socket = socket;
this.id = id;
}
public void send(String message) throws IOException {
out.writeUTF(message);
out.flush();
}
public void run() {
DataInputStream in;
//wrap in and out streams
while(connected) {
String data = in.readUTF();
//Server.sendGlobalMessage(data);
//Server.sendPrivateMessage(data, ...);
sendMessage(data); //sends message back to client
}
}
}
So I have network socket class that should be handling my socket connection that i want running when my app is running. Problem is I dont know how to reference the class other than just starting a new one.
To start a new one I would do:
Networker network = null;
try {
network = new Networker(SERVER_IP, SERVERPORT);
new Thread(network).start();
Then i could do:(from the same activity I just did the above in)
network.send("helloworld");
How can i do a network.send in any class without making a whole new socket connection?
Edit:
Here is my Networker Class:
public class Networker implements Runnable, Closeable {
private final Socket clientSocket;
private final PrintWriter out;
private final BufferedReader in;
private volatile boolean closed = false;
public Networker(String hostname, int port) throws IOException {
clientSocket = new Socket(hostname, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
public void run() {
try {
for(String fromServer; (fromServer = in.readLine()) != null;)
System.out.println("Server: " + fromServer);
} catch (IOException ex) {
if (!closed)
Log.i("logging", "error") ;
}
}
public void send(String line) {
out.println(line);
}
public void close() {
closed = true;
try { clientSocket.close(); } catch (IOException ignored) { }
}
}
Problem:
I have written one java socket server which send response when I send first message from the client to it. But I want to send one more message based on the first response. After the first response i am not getting any other response?
Here is the Server code:
public class SendSmsServerSocket {
private final static CxpsLogger logger = CxpsLogger.getLogger(SendSmsServerSocket.class);
SendSmsServerSocket(){
try {
new SeverSocketForSms(new ServerSocket(4330));
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static class SeverSocketForSms extends Thread {
private Socket socket;
private ServerSocket serversocket;
private volatile static boolean running = true;
public SeverSocketForSms(ServerSocket ssocket) throws IOException {
this.serversocket = ssocket;
start();
}
public void run() {
try{
while(running) {
this.socket = serversocket.accept();
InputStreamReader ir = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(ir);
String msg = br.readLine();
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("inside SeverSocketForSms: msg received is : "+msg);
}
}
catch(Exception e){
e.printStackTrace();
}
catch(Throwable t) {
System.out.println("Caught " + t + "xmlServerThread - closing thread");
}
}
public static void shutdown() {
System.out.println("Stopping socket connection and thread");
try{
socket.close();
}catch (Exception e) {
e.printStackTrace();
}
running = false;
}
public static void main (String [] args){
try {
System.out.println("Starting sms server ----- Please press Enter Key to stop the server after receiving one message");
SendSmsServerSocket s=new SendSmsServerSocket();
new Scanner(System.in).nextLine();
SeverSocketForSms.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Once you have an incoming connection, you should delgate the responsibility for handling that incoming connection to another Thread, otherwise you will block your "accept" thread until the current connection is closed...
while (running) {
this.socket = serversocket.accept();
Thread thread = new Thread(new Handler(socket));
thread.start();
}
And the Handler
public class Handler implements Runnable {
private Socket socket;
public Handler(Socket socket){
this.socket = socket;
}
public void run() {
// You may need to add a repeat and exit clause here...
InputStreamReader ir = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(ir);
String msg = br.readLine();
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("inside SeverSocketForSms: msg received is : " + msg);
}
}