I'm trying to write simple server-client chat solution. For test purposes, I'm creating an array of 2 serverThreads, which are responsible for sending and receiving messages from the clients connected.
I'd like a server to reject a connections after the number of connected clients reach a maximum value. However, even though the server do not accept the connection, the socket on client side is created. Methods socket.isBound and isConnected both return true value.
So back to the main question. Do you have any ideas how could I reject the client from connecting when the ServerSocket will not be able to .accept() additional connection?
Here's the code of the Server class.
public class Server {
private ServerSocket serverSocket = null;
private ServerThread serverThread[] = new ServerThread[2];
protected volatile int clientCount = 0;
public Server (int port){
try {
System.out.println("Binding to port " + port + " ...");
serverSocket = new ServerSocket (port);
System.out.println("Binded to port " + port + ".");
} catch (IOException e) {
System.out.println("Failed binding to the port: " + e.getMessage());
}
}
public void addThread (Socket socket){
System.out.println ("Client connected at socket: " + socket);
serverThread[clientCount] = new ServerThread (this, socket);
try {
serverThread[clientCount].open();
serverThread[clientCount].start();
} catch (IOException e) {e.getMessage();}
}
public void waitForClient () {
boolean isLogPrinted = false;
while (true){
try {
if (clientCount < serverThread.length){
System.out.println ("Waiting for connection...");
isLogPrinted = false;
addThread (serverSocket.accept());
clientCount++;
System.out.println("Client count: " + clientCount);
}
else {
if (!isLogPrinted){
System.out.println("MAXIMUM NUMBER OF CLIENTS REACHED! (" + clientCount + ").");
isLogPrinted = true;
}
}
} catch (IOException e) {
System.out.println("Error while waiting for new clients to connect: " + e.getMessage());
}
}
}
public synchronized void broadcastMessages (String msg){
for (int i = 0; i < clientCount; i++)
serverThread[i].sendMessage(msg);
}
public static void main (String args[]){
Server server = new Server (4200);
server.waitForClient();
}
}
I'd like a server to reject a connections after the number of connected clients reach a maximum value.
Close the server socket.
However, even though the server do not accept the connection, the socket on client side is created. Methods socket.isBound and isConnected both return true value.
Correct. That's because TCP maintains a 'backlog queue' of incoming connections which have been completed but not yet accepted by the server application.
So back to the main question. Do you have any ideas how could I reject the client from connecting when the ServerSocket will not be able to .accept() additional connection?
Close the server socket while the number of connections is at its maximum.
However due to the backlog this technique can never be perfect. There is no perfect solution. You could have the server immediately close excess connections, but the excess clients won't detect that until they try to send something. If you need perfection you will probably have to introduce an application protocol whereby the server sends something like 'ACCEPTED' or 'REJECTED' accordingly.
Instead of while true in you waitForClient method try this
private final int allowedClients = 10;
private int connectedClients = 0;
public void waitForClient () {
boolean isLogPrinted = false;
while (connectedClients <= allowedClients){
try {
if (clientCount < serverThread.length){
System.out.println ("Waiting for connection...");
isLogPrinted = false;
addThread (serverSocket.accept());
connectedClients++;
System.out.println("Client count: " + clientCount);
}
else {
if (!isLogPrinted){
System.out.println("MAXIMUM NUMBER OF CLIENTS REACHED! (" + clientCount + ").");
isLogPrinted = true;
}
}
} catch (IOException e) {
System.out.println("Error while waiting for new clients to connect: " + e.getMessage());
}
}
}
I know this is very late to answer, but I think it will help many.
You can check for the existing socket if any by below code.
SocketAddress socketAddress = new InetSocketAddress("localhost", 8091);
Socket socket = new Socket();
ServerSocket serverSocket = null;
try {
socket.connect(socketAddress);
} catch (IOException e) {
e.printStackTrace();
}
if(socket == null) {
try {
serverSocket = new ServerSocket(8091);
} catch (IOException e) {
e.printStackTrace();
}
}
if not found a active socket on the same port and IP then it will start a new server socket or you can change it start socket only else you can connect to the existing socket.
Related
I am trying to get into IoT and want to make an app send a string from an android phone to a Linux pc. The app does this by implementing an asynctask:
//From the java docs, slightly modified
private Void sendThroughSocket(String s, String host, int port) {
Log.d("E", "In send through socket");
final String hostName = host;//Host is the address of the receiver, can be IP or domain
int portNumber = port;
//Check if device is connected to internet
try {
Socket clientsocket = new Socket(hostName, portNumber); //one of 2-way point communication
Log.d("E", "Created Socket: ");
DataOutputStream DOS = new DataOutputStream(clientsocket.getOutputStream());
if (clientsocket.isConnected())
Log.d("E", "Socket connected");
DOS.writeUTF(s);
clientsocket.close();
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + hostName);
new Runnable() {
public void run() {
Toast.makeText(context, "Don't know about host " + hostName, Toast.LENGTH_SHORT).show();
}
};
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to " + hostName);
//Toast can not be run using asynctask since it acesses UI
new Runnable() {
public void run() {
Toast.makeText(context, "Couldn't get I/O for the connection to " + hostName + " , check the port", Toast.LENGTH_SHORT).show();
}
};
} catch (Exception e) {
Log.d("E", "#fares" + e.getClass().getName().toString());
}
return null;
}
On 3 occasions do I try to send the string, all triggered from my seekbar (I send the seek bar progress value as my string):
public void onProgressChanged(SeekBar seekBar, int i, boolean b)
public void onStartTrackingTouch(SeekBar seekBar)
public void onStopTrackingTouch(SeekBar seekBar)
The implementation for all 3 is the same:
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
progressvalue = i;
textView.setText("Brightness = " + progressvalue + " %");
if (((RecieverPort.equals("Please enter port Number")) || (RecieverIP.equals("Please enter receiver IP")))) {
//Make sure toast isn't persistent
if (IPPortToastcount++ == 0)
Toast.makeText(MainActivity.this, "Please set both IP and Port ", Toast.LENGTH_SHORT).show();
} else {
//Check if connected to internet
if (!isConnectedtoInternet(MainActivity.this)) {
if (ConnectivityToastCount++ < 1)
Toast.makeText(MainActivity.this, "You are not connected to the Internet", Toast.LENGTH_SHORT).show();
} else {
//Send text over wifi
SendText ST = new SendText(getApplicationContext());
ST.execute(String.valueOf(progressvalue), RecieverIP, RecieverPort);
ST.cancel(false);
}
}
}
Mainly
//Send text over wifi
SendText ST = new SendText(getApplicationContext());
ST.execute(String.valueOf(progressvalue), RecieverIP, RecieverPort);
ST.cancel(false);
The server side (my pc) is pretty simple:
int portNumber = 44339; // Choose unused port on router
//Open a socket
try {
//System.out.println("in try statement");
try (ServerSocket serverSocket1 = new ServerSocket(portNumber)) {
portNumber = serverSocket1.getLocalPort();
System.out.println("Created socket at port " + portNumber);
Socket clientSocket = serverSocket1.accept();
System.out.println("Accepted");
DataInputStream DIS = new DataInputStream(clientSocket.getInputStream()); //get input from socket
//System.out.println("Created reader");
String inputLine;
// System.out.println("About to read");
while (DIS.available() > 0) {
inputLine = DIS.readUTF();
System.out.println(inputLine);
}
}
} catch (Exception e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getClass().getSimpleName());
}
This kind of works, except it takes a very long time(seconds) before the server socket is accepted. It also only works in onprogresschanged , which leads me to believe that multiple attempts of
//Send text over wifi
SendText ST = new SendText(getApplicationContext());
ST.execute(String.valueOf(progressvalue), RecieverIP, RecieverPort);
ST.cancel(false);
are needed before one succeeds at creating the socket and connecting to the pc. How can I make sure that one tap, or one call of the function will be enough to send the string?
Sorry for the long post but it's my first time asking :)
Edit: my new server code:
try {
//System.out.println("in try statement");
try ( ServerSocket serverSocket1 = new ServerSocket(portNumber))
{
portNumber = serverSocket1.getLocalPort();
System.out.println("Created socket at port " + portNumber);
while(true){
Socket clientSocket = serverSocket1.accept();
// System.out.println("Accepted");
DataInputStream DIS = new DataInputStream(clientSocket.getInputStream()); //get input from socket
//System.out.println("Created reader");
//String inputLine;
//System.out.println("About to read");
System.out.println(DIS.readUTF());
}
}
} catch (Exception e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getClass().getSimpleName());
}
Worth noting that even in the while true loop, the server will always display 4 numbers then stop.
Edit: here is an example log:
10-06 20:08:09.145 26372-26372/com.example.fares.ledslider D/E: #fares in test method value = 50
10-06 20:08:26.475 26372-26372/com.example.fares.ledslider D/E: #Fares in start tracking
10-06 20:08:26.722 26372-27004/com.example.fares.ledslider D/E: #fares Socket connected
10-06 20:08:26.810 26372-26764/com.example.fares.ledslider D/E: #fares Socket connected
10-06 20:08:27.241 26372-27003/com.example.fares.ledslider D/E: #fares Socket connected
10-06 20:08:27.304 26372-26372/com.example.fares.ledslider D/E: #fares in stop tracking
ST.cancel() can be removed. Also not waiting for availability looks not good.
I will post my code below, a little background.
I am trying to connect to a gameserver on port 9339. my local port changes each time. The aim is to pass the packets through the proxy and display the info in the command line.
The client connects to the remote host using bluestacks which is running the game.
Code:
import java.io.*;
import java.net.*;
public class proxy {
public static void main(String[] args) throws IOException {
try {
String host = "gamea.clashofclans.com";
int remoteport = 9339;
ServerSocket ss = new ServerSocket(0);
int localport = ss.getLocalPort();
ss.setReuseAddress(true);
// Print a start-up message
System.out.println("Starting proxy for " + host + ":" + remoteport
+ " on port " + localport);
// And start running the server
runServer(host, remoteport, localport,ss); // never returns
System.out.println("Started proxy!");
} catch (Exception e) {
System.err.println(e);
}
}
/**
* runs a single-threaded proxy server on
* the specified local port. It never returns.
*/
public static void runServer(String host, int remoteport, int localport, ServerSocket ss)
throws IOException {
final byte[] request = new byte[2048];
byte[] reply = new byte[4096];
while (true) {
Socket client = null, server = null;
try {
// Wait for a connection on the local port
client = ss.accept();
System.out.println("Client Accepted!");
final InputStream streamFromClient = client.getInputStream();
final OutputStream streamToClient = client.getOutputStream();
// Make a connection to the real server.
// If we cannot connect to the server, send an error to the
// client, disconnect, and continue waiting for connections.
try {
server = new Socket(host, remoteport);
System.out.println("Client connected to server.");
} catch (IOException e) {
PrintWriter out = new PrintWriter(streamToClient);
out.print("Proxy server cannot connect to " + host + ":"
+ remoteport + ":\n" + e + "\n");
out.flush();
client.close();
System.out.println("Client disconnected");
continue;
}
// Get server streams.
final InputStream streamFromServer = server.getInputStream();
final OutputStream streamToServer = server.getOutputStream();
// a thread to read the client's requests and pass them
// to the server. A separate thread for asynchronous.
Thread t = new Thread() {
public void run() {
int bytesRead;
try {
while ((bytesRead = streamFromClient.read(request)) != -1) {
streamToServer.write(request, 0, bytesRead);
streamToServer.flush();
}
} catch (IOException e) {
}
// the client closed the connection to us, so close our
// connection to the server.
try {
streamToServer.close();
} catch (IOException e) {
}
}
};
// Start the client-to-server request thread running
t.start();
// Read the server's responses
// and pass them back to the client.
int bytesRead;
try {
while ((bytesRead = streamFromServer.read(reply)) != -1) {
streamToClient.write(reply, 0, bytesRead);
streamToClient.flush();
}
} catch (IOException e) {
}
// The server closed its connection to us, so we close our
// connection to our client.
streamToClient.close();
} catch (IOException e) {
System.err.println(e);
} finally {
try {
if (server != null)
server.close();
if (client != null)
client.close();
} catch (IOException e) {
}
}
}
}
}
Basically the last thing that is printed out is "Starting proxy for gamea.clashofclans.com:9339 on port (whatever it chose).
Hopefully someone can help me.
I have this problem too, I don`t have enough time to correct this but i think using thread is that is why all mistake.
check your proxy for working on browser setting( May be proxy had problem)
If not,
I suggest to don`t use thread. maybe mutual exclusion occurs.
Your code is correct.It is working fine so you don't need any fix. What is happening is , your serverSocket in your proxy class is waiting for client to connect. that's why it is not going forward. What you need to do is, create a client and connect to it.
follow the step :
run your proxy.
then run your client
for the client, you can use this code,
public static void main(String[] args) throws IOException {
try {
int remoteport = 9339;
String host="127.0.0.1";
makeConnection(host, remoteport);
System.out.println("connection successful!");
} catch (Exception e) {
System.err.println(e);
}
}
public static void makeConnection(String host, int remoteport) throws IOException {
while (true) {
Socket client = null;
try {
client = new Socket(host, remoteport);
System.out.println("Client connected to server.");
break;
} catch (IOException e) {
System.err.println(e);
} finally {
if (client != null)
client.close();
if (client != null)
client.close();
}
}
}
Why IOException after thousands of socket creation calls?
I did a simple Server code (Java) which accepts connections then creates a thread reads the socket and sends back another character to the Client
The Client code starts to do a cycling (long enough to reproduce the issue) and in each cycle creates 50 threads in each thread creating a client socket to server machine and sends a character then reads from socket the character that the Server sends back.
Then both the Client and the Server closes the socket.
After a while I notice that on Client side I get exception in client socket creation.
Are there some limitations which I should take in consideration to work this properly or this should work in an infinite loop?
I'm thinking here to situations that maybe after a long enough cycling time the client side tries to bind the new socket to a port on client machine which is still binded to a socket which is in CLOSED state but that time period which needs to be elapsed to be freed by kernel not passed yet. (sorry don't know official name of this time period)
The client and server machines are two Linux systems in VMware.
Sounds like maybe your connection was dropped.
You forgot rule #1 in the Fallacies of Distributed Computing: The network is always reliable.
Have you set the setReuseAddress parameter to true on your ServerSocket? If not, you have to wait a quite long time before the kernel release network resources.
Thank you !
Actually this is my Server side code
public class TestServer {
public void createThread() {
System.out.println("createThread");
ServerThread servThread = new ServerThread();
servThread.start();
}
public static final void main(String[] args) {
ServerSocket server = null;
try {
System.out.println("Started");
server = new ServerSocket(12345);
}
catch(IOException ex) {
System.out.println("Server: Exception at socket creation: " + ex.getMessage());
}
try {
while(true) {
Socket clientSock = server.accept();
System.out.println("Connection Accepted: server: "+clientSock.getLocalPort()+", Client: "+clientSock.getPort());
ServerThread servThread = new ServerThread(clientSock);
servThread.start();
}
}
catch(IOException ex) {
System.out.println("Server: Exception at socket accept: " + ex.getMessage());
}
}
}
class ServerThread extends Thread {
private Socket sock;
public ServerThread() {}
public ServerThread(Socket sock) {
this.sock = sock;
}
public void run() {
InputStream is = null;
OutputStream os = null;
try {
is = sock.getInputStream();
os = sock.getOutputStream();
}
catch(IOException ex) {}
try {
int b = is.read();
System.out.println("server: received = " + (char)b);
}
catch(IOException ex) {
System.out.println("Server: IOException at read = " + ex.getMessage());
}
try {
os.write('R');
os.flush();
}
catch(IOException ex) {
System.out.println("Server: IOException at write = " + ex.getMessage());
}
try {
sock.close();
}
catch(IOException ex) {
System.out.println("Server: IOException at close = " + ex.getMessage());
}
}
}
and this is the Client part:
public class TestClient {
public static void main(String[] args) {
if (args.length != 4) {
System.out.println("Usage: java TestClient <ServerIP> <nbThreads> <cycle> <delay>");
System.exit(1);
}
String host = args[0];
int nbThreads = Integer.parseInt(args[1]);
int cycle = Integer.parseInt(args[2]);
int delay = Integer.parseInt(args[3]);
for (int i = 0; i<cycle; i++) {
for (int j = 0; j<nbThreads; j++) {
ClientThread clThread = new ClientThread(host);
clThread.start();
}
/* try {
Thread.sleep(delay);
}
catch (Exception ex) {} */
}
}
}
class ClientThread extends Thread {
private String host;
public ClientThread(String host) {
this.host = host;
}
public void run(){
for (int i=0; i<3; i++) {
Socket clientSock = null;
try {
clientSock = new Socket(host, 12345);
}
catch(IOException ex) {
System.out.println("Client: IOException at socket creation = " + ex.getMessage());
}
OutputStream os = null;
InputStream is = null;
try {
os = clientSock.getOutputStream();
is = clientSock.getInputStream();
}
catch (IOException ex) { }
try {
os.write('B');
os.flush();
}
catch (IOException ex) {
System.out.println("Client: IOException at write = " + ex.getMessage());
}
try {
int reply = is.read();
System.out.println("Client: reply = " + (char)reply);
}
catch(IOException ex) {
System.out.println("Client: IOException at read = " + ex.getMessage());
}
try {
clientSock.close();
}
catch(IOException ex) {
System.out.println("Client: IOException at close = " + ex.getMessage());
}
}
}
}
I'm testing with 60 threads and 1000 cycle and no delay.
I was wrong in my first question, the exception comes from the is.read() call after a while and it is 'Connection reset' exception.
I did this sample code to simulate the problem I'm getting in my application code where I'm getting the exception during the client socket creation ... but it seems I need to find further what is the difference netween this and my application code.
However I think would help me also to understand why after a while I'm getting the 'Connection reset' exception on the client side after a while.
Is that possible that on the server side once os.write('R') happened the sock.close() happens so fast that on the client side the is.read() call hasn't reached yet. Sound strange :)
Also not sure on which socket I should use the setReuseAddress function. Isn't on the client side, because there I'm creating again and again the sockets... although now I'm not getting the exception at client socket creation.
Thanks !
Given this:
. . .
ServerSocket serverSocket = new ServerSocket(1111);
while (helperSockets.size() < Common.NUM_HELPERS) {
Socket helperSocket = serverSocket.accept();
. . .
This throws the exception:
new Socket("localhost", 1111, InetAddress.getLocalHost(), localPort);
Exception:
java.net.ConnectException: connect: Address is invalid on local machine, or port is not valid on remote machine
I'm trying to use this constructor to set the local port, so what am I doing wrong? Source below.
The constructor creates a thread that listens for clients via ServerSockets, while trying to connect to other clients. This client tries to connect with itself for testing. The problem is encountered upon first iteration of the for loop.
public class DisSemHelper extends Thread {
private int id;
private int semaphore;
private Clock clock;
private Vector<Socket> helperSockets;
private int localPort;
private int receivedSender;
private String receivedOperation;
private int receivedTimestamp;
/**
*/
public DisSemHelper(int id) {
this.id = id;
this.semaphore = 0;
this.clock = new Clock();
this.helperSockets = new Vector<Socket>();
this.receivedSender = -1;
this.receivedOperation = null;
this.receivedTimestamp = -1;
this.localPort = Common.portMap.get(id);
new ConnectionListener().start();
/* Create and store connections to all helpers */
for (int i=0; helperSockets.size() < Common.NUM_HELPERS; i++) {
Socket helperSocket = null;
// String portKey = "STREET_" + i;
/* Wait until target street socket is ready. Retry every second. */
Exception e = new ConnectException();
while (helperSocket == null) {
try {
Thread.sleep(1000);
helperSocket = new Socket("localhost", 2222, InetAddress.getLocalHost(), localPort);
} catch (ConnectException ce) {
e = ce;
e.printStackTrace();
} catch (UnknownHostException uhe) {
uhe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
e.printStackTrace();
}
}
int remotePort = helperSocket.getPort();
int connectedHelperID = Common.portMap.indexOf(remotePort);
if (this.helperSockets.size() <= connectedHelperID) {
this.helperSockets.add(helperSocket);
System.out.println("Helper " + id + " added socket from outgoing: local port: " + helperSocket.getLocalPort() + " remote port: " + helperSocket.getPort());
}
}
System.out.println(this.helperSockets);
}
private class ConnectionListener extends Thread {
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(2222);
/* Listen for connections from other helpers */
while (helperSockets.size() < Common.NUM_HELPERS) {
Socket helperSocket = serverSocket.accept();
// TODO Will indexof int in list of Integers work?
int remotePort = helperSocket.getPort();
int connectedHelperID = Common.portMap.indexOf(remotePort);
// TODO Does this really work?
if (connectedHelperID == -1) {
helperSockets.add(helperSocket);
System.out.println("Helper " + id + " added socket from incoming: local port: " + helperSocket.getLocalPort() + " remote port: " + helperSocket.getPort());
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This is a WAG, but I'd try the other constructors in Socket.
Try new Socket(INetAddress.getLocalHost(), "111");
See:
http://ashishmyles.com/tutorials/tcpchat/index.html
Can you make a simple test-case and post the source? That'll help us troubleshoot this better.
new Socket("localhost", 1111, InetAddress.getLocalHost(), localPort);
What exactly are you trying to do here? Why do you need to define what local host/port pair to use locally? A client should normally just specify the remote host/port and let the OS pick the local port. This is perhaps the problem.
Not a true solution, but I ended up working around setting the local port (because nobody seems to like that idea).
i want to connect morethan one client at a time to the server and also communicate server to all the clients.
how server recognize each client. and how to send data to a particular client?
consider , there are 3 clients A,B,C. all the clients are connected to the server. the server wants to send message to B. how its done ?
If i understand you right - all you need is not bind socket for one connection.
Your client code will looks like that:
Client class:
public class TCPClient {
public TCPClient(String host, int port) {
try {
clientSocket = new Socket(host, port);
} catch (IOException e) {
System.out.println(" Could not connect on port: " + port + " to " + host);
}
}
Server(host) class:
public class TCPListener {
public TCPListener(int portNumber) {
try {
serverSocket = new ServerSocket(portNumber);
} catch (IOException e) {
System.out.println("Could not listen on port: " + portNumber);
}
System.out.println("TCPListener created!");
System.out.println("Connection accepted");
try {
while (true) {
Socket clientConnection = serverSocket.accept();
//every time client's class constructor called - line above will be executed and new connection saved into Socket class.
}
} catch (Exception e) {
e.printStackTrace();
}
}
That is simplest example. More can be found here:
http://www.oracle.com/technetwork/java/socket-140484.html