I have a server app written in C# for Windows. I have a client app for android. I want to send data continuously from client to server in an infinite loop. The data is being sent but sometimes, there is a bad delay. I'm really stuck at it. Here's my client side code:
new Thread(new Runnable() {
public void run() {
Socket socket = null;
PrintWriter out = null;
while(true) {
try {
socket = new Socket(IP, PORT);
out = new PrintWriter(socket.getOutputStream(), true);
out.println(msg);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
Any idea why is there a delay?
Your problem is that you are initializing the socket every single iteration of your while loop.
new Thread(new Runnable() {
public void run() {
Socket socket = null;
PrintWriter out = null;
while(true) {
try {
socket = new Socket(IP, PORT);
out = new PrintWriter(socket.getOutputStream(), true);
out.println(msg);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
Refactor it out of the loop, like this:
new Thread(new Runnable() {
public void run() {
Socket socket = new Socket(IP, PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while(true) {
try {
out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}).start();
Unless that is by design, in which case, why?
It seems the code is correct. The lag may be caused not only by the application but also by the network status.
Try to ping to the router from both devices and see if you are having lag spikes due to the wireless conection. If you see high lag in pings the problem is in the connection, not in the application.
Related
Is it possible to write a client-server code that can connect 2-different computers to play a multi-player game using sockets in java? Do these computers need to be connected by a cable? Or can I send the data through some other source? (Like internet..) Or is it enough if I know just the ip addresses of both computers and put that in in the sockets? Please tell me how I can do it.
You can connect computers that are on the same Wifi network. You will need to open a server and then open clients that connect to it.
The following code may help:
Server.java
ArrayList<Socket> clientSockets = new ArrayList<>();
try {
ServerSocket serverSocket = new ServerSocket(port); // port same as client
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println("Server opened at: "+inetAddress.getHostAddress());
while (true) // this keeps the server listening
{
final Socket socket = serverSocket.accept(); // this accepts incomming connections
clientSockets.add(socket); // adds current connection to an arraylist
System.out.println(timestamp()+"Connection from "+socket.getInetAddress());
Thread t = new Thread(new Runnable() // Thread handles messages sent by client that just connected
{
#Override
public void run() {
try
{
while (socket.isConnected())
{
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String fromClient = br.readLine();
if (fromClient != null)
{
//use message from client
}
else // connection might have been reset by client
{
socket.close();
clientSockets.remove(socket);
}
}
} catch (SocketException e)
{
System.out.println("Disconnection from "+socket.getInetAddress());
} catch (IOException e) {}
}
});
t.start();
}
} catch (Exception e) {}
Client.java - add two buttons, one for connecting and one for sending
bConnect.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
InetAddress address = InetAddress.getByName(host); // host IPaddress
socket = new Socket(address, port); // port same as server
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
final Timer time = new Timer(); // to get new server txt if it changes
TimerTask t = new TimerTask() {
#Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String kry = br.readLine();
// use message from server
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, "The Server has just gone offline");
}
}
};
time.scheduleAtFixedRate(t, 0, 2000);
}
catch (Exception e1)
{e1.printStackTrace();
JOptionPane.showMessageDialog(null, "The Server is not online");}
}
});
bSend.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String textGekry = "what you are sending";
if (!textGekry.equals(""))
{
String sendMessage = textGekry + "\n";
try
{
bw.write(sendMessage);
bw.flush();
}
catch (Exception e1)
{
JOptionPane.showMessageDialog(null,"The Server is most likely offline");
}
}
}
});
This socket application works perfectly fine until I add support for multiple client connections to the server. Then I get a EOFException from the client, and a SocketException: Socket closed from the server.
Server.java:
public class Server {
static final int PORT = 8005;
static final int QUEUE = 50;
public Server() {
while (true) {
try (ServerSocket serverSocket = new ServerSocket(PORT, QUEUE);
Socket socket = serverSocket.accept();
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
output.writeUTF("Hey, this is the server!");
output.flush();
System.out.println(input.readUTF());
} catch (IOException e) {
System.out.println();
e.printStackTrace();
}
}
});
thread.start();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Server();
}
}
Client.java:
public class Client {
static final String HOST = "localhost";
static final int PORT = 8005;
public Client() {
try (Socket socket = new Socket(HOST, PORT);
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream())
) {
System.out.println(input.readUTF());
output.writeUTF("Hey, this is the client!");
output.flush();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
new Client();
}
}
A couple problems here:
You're creating a new ServerSocket for each pass through the loop. For a multi-client server you should instead be opening one ServerSocket and calling accept() on it for each client that connects.
Try-with-resources closes all resources it's provided with as soon as the try block is exited. You're creating a Thread that uses output but executes independently of the try block, so the execution flow is leaving the try block before thread finishes executing, resulting in socket (and output) being closed before the thread is able to use them. This is one of those situations where your resources need to be used outside the scope of the try block (in the thread you create to use them), so try-with-resources can't do all your resource handling for you.
I would rearrange your server code to something like:
public class Server {
static final int PORT = 8005;
static final int QUEUE = 50;
public Server() {
// create serverSocket once for all connections
try (ServerSocket serverSocket = new ServerSocket(PORT, QUEUE)) {
while (true) {
// accept a client connection, not in a try-with-resources so this will have to be explicitly closed
final Socket socket = serverSocket.accept();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// limit scope of input/output to where they're actually used
try (DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {
output.writeUTF("Hey, this is the server!");
output.flush();
System.out.println(input.readUTF());
} catch (IOException e) {
System.out.println();
e.printStackTrace();
}
// implicitly close socket when done with it
try {
socket.close();
} catch (IOException e) {
System.out.println();
e.printStackTrace();
}
}
});
thread.start();
}
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
public static void main(String[] args) {
new Server();
}
}
Code is commented somewhat to explain some of the moves. Also note that the socket.close() call is in its own try-catch block to ensure that it's called even if the I/O streams throw an exception. It could equivalently (or perhaps more correctly now that I think about it) been placed in a finally block on the I/O stream try-catch block.
Here's the problem. I'm attempting to set up a very simple app that will send messages to a Java server.
Here is my server code:
ServerSocket serverSocket = null;
Socket clientSocket =null;
try
{
serverSocket = new ServerSocket(4444);
System.out.println("Server Started...");
clientSocket = serverSocket.accept();
}catch(Exception e){};
Scanner in = new Scanner(clientSocket.getInputStream());
String inputLine;
while (true)
{
if(in.hasNext())
{
inputLine=in.nextLine();
System.out.println("Message from server: "+inputLine);
}
}
And here's the client code:
Socket client;
PrintWriter printwriter;
String serverIpAddress="192.168.173.1";
Button button;
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button =(Button) findViewById(R.id.button);
text=(TextView) findViewById(R.id.textView);
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
client = new Socket(serverIpAddress,4444);
printwriter = new PrintWriter(client.getOutputStream());
printwriter.write("Start");
printwriter.flush();
//printwriter.close();
//client.close();
}
catch(UnknownHostException e)
{
}
catch(IOException e)
{
e.printStackTrace();
}
}
}).start();
}
});
}
I have one button, when I press it a message is sent to the server and it displays fine, but when I press the button the socket does not reconnect so I can't send the massage again.
To be clear I intend to eventually add more buttons to send different messages. I looked into creating a global socket but that didn't seem to go anywhere.
Any help is greatly appreciated.
This is because you are not closing the socket in the client code. You should close the streams & sockets in both server and client when the connection is over. Saying this, you should keep the connection alive and send several messages instead of closing the connection after sending one message.
I would for example rewrite the server code as (please note that this handles only one client):
ServerSocket serverSocket = null;
Socket clientSocket =null;
Scanner in = null;
try
{
serverSocket = new ServerSocket(4444);
System.out.println("Server Started...");
clientSocket = serverSocket.accept();
in = new Scanner(clientSocket.getInputStream());
String inputLine;
while (true) {
if(in.hasNext()) {
inputLine=in.nextLine();
System.out.println("Message from server: "+inputLine);
}
}
} catch(IOException e) {
e.printStackTrace();
} finally {
if(in != null) {
in.close();
}
if(clientSocket != null) {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Just a note: I would use DataInputStream & DataOutputStream... in this way, you could use in.readUTF() in the server side which will block until receiving something new through network. In this way, you will not have to do while(true) which will be way much better for the CPU.
Thank you all for your responses. I did get it working.
Multithreader, thank you, you were completely correct about where my problem lay. I did it a bit differently though.
I set up another class to set up the socket and created a method to start listening on the given port. In the main I just put that in a loop to keep closing and recreating the socket till the end condition is met.
Thanks again all.
I am using a server socket in linux and I need to close it and reopen before the time_wait TCP status expires. I set the reuse address option of the server socket before the binding but it still throws a BindException.
I also tried this http://meteatamel.wordpress.com/2010/12/01/socket-reuseaddress-property-and-linux/ but it still doesn't work.
To open a server socket i use:
ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
and to close:
ss.close();
The "Address already in use" BindException is throwed at the bind call.
This code generates the exception:
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
#Override
public void run() {
try {
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
Socket s = ss.accept();
System.out.println((char) s.getInputStream().read());
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(500);
Socket s = new Socket("localhost", 12345);
s.getOutputStream().write('c');
}
You set reuse before binding not after you get an exception.
ServerSocket ss = new ServerSocket(); // don't bind just yet
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345)); // can bind with reuse= true
This runs without error on Windows 7 and RHEL 5.x
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(12345));
Socket s = ss.accept();
System.out.println((char) s.getInputStream().read());
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(50);
Socket s = new Socket("localhost", 12345);
s.getOutputStream().write('c');
t.join();
}
You have to do that: it means extract the code so that it does not recur constantly
public class....
private ServerSocket socServer;
onCreate
...
try {
socServer = new ServerSocket();
socServer.setReuseAddress(true);
socServer.bind(new InetSocketAddress(SERVER_PORT));
} catch (IOException e) {
e.printStackTrace();
}
// New thread to listen to incoming connections
new Thread(new Runnable() {
#Override
public void run() {
try
{
// Create server side client socket reference
Socket socClient = null;
// Infinite loop will listen for client requests to connect
while (true) {
// Accept the client connection and hand over communication
// to server side client socket
socClient = socServer.accept();
// For each client new instance of AsyncTask will be created
ServerAsyncTask serverAsyncTask = new ServerAsyncTask();
// Start the AsyncTask execution
// Accepted client socket object will pass as the parameter
serverAsyncTask.execute(new Socket[] {socClient});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
I am trying to write a small program, that opens a server, creates a client that connects to this server and receives a message from it.
This is the Code so far
public static void main(String[] args) {
final ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(12345);
Thread t = new Thread(){
public void run(){
try {
Socket server = serverSocket.accept();
PrintWriter writer = new PrintWriter(server.getOutputStream(), true);
writer.write("Hello World");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
Socket client = new Socket("localhost", 12345);
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String message = reader.readLine();
System.out.println("Received " + message);
} catch (IOException e1) {
e1.printStackTrace();
}
}
If i run program it keeps waiting in readLine() - so obviously the client does not receive the message from the server.
Has anyone got an idea why this isn' working?
Your reading thread is waiting for a newline in the data stream. Just change the server to use:
writer.write("Hello World\r\n");
and you'll get the result you were expecting. Alternatively, you can just close the server socket, and then readLine will return when it reaches the end of the data stream.
You should put the readline in a loop as follows:
public static void main(String[] args) {
final ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(12345);
Thread t = new Thread() {
public void run() {
try {
Socket server = serverSocket.accept();
PrintWriter writer = new PrintWriter(server.getOutputStream(), true);
writer.write("Hello World");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
Socket client = new Socket("localhost", 12345);
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
// Check this --------------------------------------------------->
String message = null;
while ((message = in.readLine()) != null) {
System.out.println("Received " + message);
break; //This break will exit the loop when the first message is sent by the server
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
You can read this documentation for further explanation: http://download.oracle.com/javase/tutorial/networking/sockets/