I'm new to java and especially to java networking, but what I'm trying to do is set up a server (for a game). When TWO clients are connected to the server, I want to refuse any other connection. Am I able to close the ServerSocket? And if the ServerSocked is closed, those two connections which has been ran as threads and stored in a collection are still alive and able to cummunicate with the server? I hope you've got my point.
Here's the source code:
//Server
public synchronized List<ClientThread> getClients(){
return clients;
}
public void run() {
try {
while(true){
Socket clsock = srvsock.accept();
if(getClients().size() == 2){
System.out.println("Too many connections!");
clsock.close();
continue;
}
ClientThread clt = new ClientThread(clsock);
clients.add(clt);
clt.start();
System.out.println("Connection accepted.");
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
And with this code, I'm not able to detect on the Client if the connection is still alive, or the server has closed the connection. Thanks in advance.
Code for test client:
Socket s = new Socket("localhost", 8932);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
for (int i=0; i<20; i++) {
bw.write(String.valueOf(i));
bw.newLine();
bw.flush();
Thread.sleep(1000);
}
bw.close();
And for the ClientThread:
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
while (true) {
String misc = in.readLine();
System.out.println(misc);
if (misc==null || misc.length()==0)
break;
}
in.close();
Output:
Connection accepted.
0
Connection accepted.
0
1
Too many connections!
1
2
2
3
So it works as you intended. By the way, it is usually better to implement Runnable rather than extend Thread - see "implements Runnable" vs. "extends Thread"
Every time a connection is established, the server returns a new socket ( when you use srvsock.accept() ) for the next connection. So you can close "srvsock" without affecting "clsock". To test if they are alive, check this post How do I check if a Socket is currently connected in Java?.
Hope you can solve your problem.
Related
I've created a client-server connection, something like a chat system. Previously I was using a while loop on the client side, and it was waiting to read a message from the console every time (of course server has a while loop as well to serve forever). But now, I'm trying to first create a connection at the beginning of the session, and then occasionally send a message during the session, so to maintain a permanent and persistent connection.
Currently, without the while loop, the client closes the connection and I don't know how to find a workaround.
Here is the client code:
import java.net.*;
import java.io.*;
public class ControlClientTest {
private Socket socket = null;
// private BufferedReader console = null;
private DataOutputStream streamOut = null;
public static void main(String args[]) throws InterruptedException {
ControlClientTest client = null;
String IP="127.0.0.1";
client = new ControlClientTest(IP, 5555);
}
public ControlClientTest(String serverName, int serverPort) throws InterruptedException {
System.out.println("Establishing connection. Please wait ...");
try {
socket = new Socket(serverName, serverPort);
System.out.println("Connected: " + socket);
start();
} catch (UnknownHostException uhe) {
System.out.println("Host unknown: " + uhe.getMessage());
} catch (IOException ioe) {
System.out.println("Unexpected exception: " + ioe.getMessage());
}
String line = "";
// while (!line.equals(".bye")) {
try {
Thread.sleep(1000);
//TODO get data from input
// line = console.readLine();
line="1";
if(line.equals("1"))
line="1,123";
streamOut.writeUTF(line);
streamOut.flush();
} catch (IOException ioe) {
System.out.println("Sending error: " + ioe.getMessage());
}
// }
}
public void start() throws IOException {
// console = new BufferedReader(new InputStreamReader(System.in));
streamOut = new DataOutputStream(socket.getOutputStream());
}
}
And here is the Server code:
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ControlServer {
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream streamIn = null;
public static void main(String args[]) {
ControlServer server = null;
server = new ControlServer(5555);
}
public ControlServer(int port) {
try {
System.out
.println("Binding to port " + port + ", please wait ...");
server = new ServerSocket(port);
System.out.println("Server started: " + server);
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted: " + socket);
open();
boolean done = false;
while (!done) {
try {
String line = streamIn.readUTF();
// TODO get the data and do something
System.out.println(line);
done = line.equals(".bye");
} catch (IOException ioe) {
done = true;
}
}
close();
} catch (IOException ioe) {
System.out.println(ioe);
}
}
public void open() throws IOException {
streamIn = new DataInputStream(new BufferedInputStream(
socket.getInputStream()));
}
public void close() throws IOException {
if (socket != null)
socket.close();
if (streamIn != null)
streamIn.close();
}
}
I would like to summarize some good practices regarding the stability of TCP/IP connections which I apply on a daily basis.
Good practice 1 : Built-in Keep-Alive
socket.setKeepAlive(true);
It automatically sends a signal after a period of inactivity and checks for a reply. The keep-alive interval is operating system dependent though, and has some shortcomings. But all by all, it could improve the stability of your connection.
Good practice 2 : SoTimeout
Whenver you perform a read (or readUTF in your case), your thread will actually block forever. In my experience this is bad practice for the following reasons: It's difficult to close your application. Just calling socket.close() is dirty.
A clean solution, is a simple read time-out (e.g. 200ms). You can do this with the setSoTimeoutmethod. When the read() method timeouts it will throw a SocketTimeoutException. (which is a subclass of IOException).
socket.setSoTimeout(timeoutInterval);
Here is an example to implement the loop. Please note the shutdown condition. Just set it to true, and your thread will die peacefully.
while (!shutdown)
{
try
{
// some method that calls your read and parses the message.
code = readData();
if (code == null) continue;
}
catch (SocketTimeoutException ste)
{
// A SocketTimeoutExc. is a simple read timeout, just ignore it.
// other IOExceptions will not be stopped here.
}
}
Good practice 3 : Tcp No-Delay
Use the following setting when you are often interfacing small commands that need to be handled quickly.
try
{
socket.setTcpNoDelay(true);
}
catch (SocketException e)
{
}
Good practice 4 : A heartbeat
Actually there are a lot of side scenario's that are not covered yet.
One of them for example are server applications that are designed to only communicate with 1 client at a time. Sometimes they accept connections and even accept messages, but never reply to them.
Another one: sometimes when you lose your connection it actually can take a long time before your OS notices this. Possibly due to the shortcomings described in good practice 3, but also in more complex network situations (e.g. using RS232-To-Ethernet converters, VMware servers, etc) this happens often.
The solution here is to create a thread that sends a message every x seconds and then waits for a reply. (e.g. every 15 seconds). For this you need to create a second thread that just sends a message every 15 seconds. Secondly, you need to expand the code of good practice 2 a little bit.
try
{
code = readData();
if (code == null) continue;
lastRead = System.currentTimeMillis();
// whenever you receive the heart beat reply, just ignore it.
if (MSG_HEARTBEAT.equals(code)) continue;
// todo: handle other messages
}
catch (SocketTimeoutException ste)
{
// in a typical situation the soTimeout is about 200ms
// the heartbeat interval is usually a couple of seconds.
// and the heartbeat timeout interval a couple of seconds more.
if ((heartbeatTimeoutInterval > 0) &&
((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
{
// no reply to heartbeat received.
// end the loop and perform a reconnect.
break;
}
}
You need to decide if your client or server should send the message. That decision is not so important. But e.g. if your client sends the message, then your client will need an additional thread to send the message. Your server should send a reply when it receives the message. When your client receives the answer, it should just continue (i.e. see code above). And both parties should check: "how long has it been?" in a very similar way.
You could wrap a thread around the connection and have it periodically send a status to keep the line open, say every 30 seconds or whatever. Then, when it actually has data to send it would reset the keep alive to be 30 seconds after the last transmission. The status could be helpful to see if the client is still alive anyway, so at least it can be a useful ping.
Also, you should change your server code, you appear to only handle one connection at the moment. You should loop and when a socket connection comes in spawn a thread to handle the client request and go back to listening. I may be reading to much into what may just be your test code, though.
Make the client socket connection wrapped around a thread. Use a blocking queue to wait for messages. There should only be a single sender queue throughout your application, so use a singleton pattern.
e.g.
QueueSingleton queue = QueueSingleton.getSenderQueue();
Message message = queue.take() // blocks thread
send(message); //send message to server
When you need to send a message to the server, you can use the blocking queue to send the message.
QueueSingleton queue = QueueSingleton.getSenderQueue();
queue.put(message)
The client thread will wake up and process the message.
For maintaining the connection, use a timer task. This is special type of thread that calls a run method repetitively at specified periods. You can use this to post a message, a ping message, every so often.
For processing the received message, you could have another thread, waiting for messages on another blocking queue (receiver queue). The client thread will put the received message on this queue.
I have a 2 nodes that should always communicate with each other, but they don't seem to talk for more than 1 interaction. After successfully sending and receiving 1 message, they stop.
My code looks like this:
The initiator:
try {
Socket client = new Socket(ip, port);
OutputStream toNode = client.getOutputStream();
DataOutputStream out = new DataOutputStream(toNode);
out.writeUTF("Start:Message");
System.out.println("Sent data");
InputStream fromNode = client.getInputStream();
DataInputStream in = new DataInputStream(fromNode);
if(in.readUTF().equals("Return Message")) {
System.out.println("Received data");
out.writeUTF("Main:Message");
System.out.println("Sent data again");
}
else
System.out.println("Error");
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The responder:
while(true) {
Socket server;
try {
server = s.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
String msg = in.readUTF();
String[] broken_msg = msg.split(":");
if(broken_msg.length > 0)
System.out.println("Looping");
String ret;
if (broken[0].equalsIgnoreCase("Start")) {
ret = "Return Message";
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF(ret);
}
else if (broken[0].equalsIgnoreCase("Main")) {
//Do Useful work
}
} catch (IOException e) {
e.printStackTrace();
}
}
My output looks like this:
Looping
and:
Sent data
Received data
Sent data again
You are looping around the accept() call, accepting new connections, but your actual I/O code only reads one message per connection. You need an inner loop around the readUTF() calls, handling the entire connection until EOFException is thrown. Normally all the I/O for a connection is handled in a separate thread.
In order for programs to do repetitive actions, you would generally use looping of some sort, including for loops, while loops and do-while loops. For something like this where you don't know how many times you'd need to communicate in advance, then you would need to use a while loop, not a for loop.
Having said that, you have no while loops whatsoever inside of your connection code... so without code that would allow continued communication, your program will stop, exactly as you've programmed it to do.
Solution: fix this. Put in while loops where continued communication is needed.
I am building a client/server application, for some socket programming exercise.
Below is construction + run method of my server class. The server awaits a respond from the client, which in this case is just a string.
The problem is that it seems to make two connections when the client respond. From my print statements i can see that all the code in the run method is run twice, and then the first line once again.
Why would dateServer.accept(); accept a connection for only one client request?
public Server() throws Exception {
dateServer = new ServerSocket(3001);
System.out.println("Server lytter på port 3000.");
this.start();
}
public void run() {
while (true) {
try {
System.out.println("waiting for client to request");
Socket client = dateServer.accept();
System.out.println("connection established");
Connect c = new Connect(client);
clients.add(c);
this.sleep(5000);
} catch (Exception e) {
}
}
}
--EDIT--
Client code that talks to server (Message is a simple "wrapper" class"):
System.out.println("Write to server:");
String name = scanner.nextLine();
Message message = new Message(name, null);
oos.writeObject(message);
oos.flush();
If all the prints happen twice there must have been two connections. The first line prints again after that because you're in a loop.
NB:
Never ignore exceptions: especially IOExceptions.
The sleep is completely pointless. accept() will block while there are no incoming connections. You are literally wasting time here.
I am trying to create a MapleStory type game for my computer science final. It's basically a 2D RPG played over LAN. My question is how would I get the connection between two computers to be simultaneous?
class MagicServer extends Thread
{
private ServerSocket serverSocket;
public MagicServer(int port) throws IOException
{
serverSocket = new ServerSocket(port);
//serverSocket.setSoTimeout(10000);
}
public void run()
{
Scanner kb = new Scanner(System.in);
while(true)
{
try
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
System.out.println(in.readUTF());
for(int i=0; i<5; i++)
{
System.out.println(in.readUTF());
out.writeUTF(kb.nextLine());
}
server.close();
}
catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}
catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = 2001;
try
{
Thread t = new MagicServer(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
I was experimenting with this and I can only send/recieve messages between two computers in order (i.e. server sends to client then client sends to server) and I cannot go out of order. How would I do this?
You have to de-couple your reads/writes by using multiple threads or through interlocked queues to manage your work.
In you loop, you force the serialization by doing a read then a write in the code.
There's no reason you couldn't spawn a reader thread that feeds into a queue to perform work by worker threads and writes happen on another thread. You just need to have synchronization on the work queues.
You can also poll the socket to see if there's any data available to read and if not, send any data waiting to be written.
There's more exotic ways to do it, and plenty of examples, search around and see what your comfortable with.
There's a similar thread here
You could use multiple threads to have a connection one way in one thread on one port and a connection the other way on a different port in the other thread. This could introduce some synchronization issues though, so I would recommend rethinking your design so that communication only needs to occur in one direction at a time (you can switch back and forth as often as you like if need be).
I had earlier posted a query on Java threads. ( link text)
And based on the answers i received, i decided to implement them. So ive done this bit of coding on a machine with 2 cpu cores. The code is as follows
import java.net.*;
import java.io.*;
public class thready implements Runnable{
private Socket num;
public thready(Socket a) {
this.num=a;
}
public void run() {
try {
BufferedInputStream is = new BufferedInputStream(num.getInputStream());
System.out.println("Connected to port"+num);
} catch (IOException ex) {
//Logger.getLogger(thready.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String [] args)
{
int port = 80;
int port1= 81;
//int count = 0;
try{
ServerSocket socket1 = new ServerSocket(port);
ServerSocket socket2 = new ServerSocket(port1);
while (true) {
Socket connection = socket1.accept();
Socket connection1 = socket2.accept();
Runnable runnable =new thready(connection);
Runnable run= new thready(connection1);
Thread t1=new Thread(runnable);
Thread t2=new Thread(run);
t1.start();
t2.start();
}
}
catch(Exception e)
{
} }}
Now Im testing this piece of code using Hyperterminal and am connecting to both port 890 and port 81(am using 2 instances of the hyperterminal) and as i understand it the expected behavior should be that "Connected to port 'port number'" should be printed as soon as a connection to any port( 80 or 81) is made. But the output that im getting here from this piece of code is that if i connect to only 1 port then the required output is not getting printed and if i connect to both ports, one after the other, the output is printed only after both ports are connected. So this again leads me to the initial confusion as to whether both these threads are executing concurrently or the execution is alternating between these 2 threads.
Any suggestions would be of great help.
Cheers
You're calling accept before starting the threads. accept will block until a connection is made, so that's why you're seeing the behavior you do. If you want to listen on multiple ports, you will need to[1] create a thread for each ServerSocket and then either start a communication thread when the accept returns or process the connections one by one in the thread doing the listening.
[1] This applies only if you are using ServerSocket directly, which you probably should be using while learning. The java.nio package and its subpackages contain classes for use with multiplexing non-blocking I/O that can be used to, e.g., listen on multiple sockets in the same thread.
You're doing a lot of initialisation before kicking off your threads and blocking there.
I would move all that code into the runnable. Then you would also avoid these duplicated variables names such as connection and connection1, have those objects owned by Thready.
The code
Socket connection = socket1.t();
Socket connection1 = socket2.accept();
uses Socket.accept which is a blocking method. See the javadoc:
Listens for a connection to be made to
this socket and accepts it. The method
blocks until a connection is made.
You have these 2 lines
Socket connection = socket1.accept();
Socket connection1 = socket2.accept();
Now, .accept() blocks until a connection is made.
So that means when your code waits on the 2. line above. You'll never get around to start the thread for 'connection' until the 2. connection is made.
I tweaked the code a bit as per the suggestions and got it running, I guess.
Here is the modified constructor and run method
public thready(int a) {
this.num=a;
}
public void run() {
try {
ServerSocket socket1 = new ServerSocket(num);
while(true){
Socket connection = socket1.accept();
BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
System.out.println("Connected to port"+num);
}
} catch (IOException ex) {
//Logger.getLogger(thready.class.getName()).log(Level.SEVERE, null, ex);
}
}
This does(I guess) implement concurrent threads. Thank you all for your suggestions.