I'm trying to teach myself Java programming. Currently I am working on some client-server code. My objective is to increment the client count before the thread is launched, and decrement the count when the thread completes. Right now, the thread just sleeps for a few seconds. You can see the full directions here:
http://archive.oreilly.com/oreillyschool/courses/java5/Homework/Projects/serverEssentials_proj.project.html
Here is the code I currently have:
RepositoryServer.java
package server;
import java.io.*;
import java.net.*;
public class RepositoryServer {
ServerSocket serverSocket = null;
int state = 0;
public void bind() throws IOException {
serverSocket = new ServerSocket(9172);
state=1;
}
public void process() throws IOException {
while (state ==1) {
Socket client = serverSocket.accept();
new RepositoryThread(client).start();
}
shutdown();
}
void shutdown() throws IOException {
if (serverSocket != null) {
serverSocket.close();
serverSocket=null;
state=0;
}
}
}
RepositoryClient.java
package client;
import java.io.*;
import java.net.*;
public class RepositoryClient {
public static void main(String[] args) throws Exception {
Socket server = new Socket("localhost", 9172);
PrintWriter toServer = new PrintWriter (server.getOutputStream(),true);
BufferedReader fromServer = new BufferedReader (new InputStreamReader(server.getInputStream()));
for (int num=0; num<3; num++) {
toServer.println("SIZE");
if (!toServer.checkError()) {
int response = Integer.valueOf(fromServer.readLine());
String value = fromServer.readLine();
if (response==0) {
System.out.println(num + ": Number of Images: "+ value);
} else if (response==-1) {
System.err.println(value);
} else {
System.err.println("Received unknown response: " +response);
}
}
}
server.close();
}
}
RepositoryThread.java
package server;
import java.io.*;
import java.net.*;
public class RepositoryThread extends Thread {
Socket client;
BufferedReader fromClient;
PrintWriter toClient;
RepositoryThread (Socket s) throws IOException {
fromClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
toClient=new PrintWriter(s.getOutputStream(), true);
client = s;
}
public void run() {
try {
while (true) {
String request = fromClient.readLine();
if (request == null) {
break;
}
if (request.equals("SIZE")) {
output("0");
} else {
//internal server error. Try to continue and keep processing
outputError("Unable to process request: "+ request);
continue;
}
}
} catch (IOException ioe) {
System.err.println("Thread processing terminated: " + ioe.getMessage());
}
try {
fromClient.close();
toClient.close();
client.close();
} catch (IOException ioe) {
System.err.println("Unable to close connection: " +ioe.getMessage());
}
}
void output(String result) {
toClient.println(0);
toClient.println(result);
}
void outputError(String error) {
toClient.println(-1);
toClient.println(error);
}
}
ServerLauncher.java
package server;
public class ServerLauncher {
public static RepositoryServer create() throws Exception {
RepositoryServer server = new RepositoryServer();
server.bind();
return server;
}
public static void main(String[] args) throws Exception {
RepositoryServer server = create();
System.out.println("Server awaiting client connections");
server.process();
System.out.println("Server shutting down.");
}
}
TestServer.java
package server;
import java.io.*;
import client.*;
import junit.framework.TestCase;
public class TestServer extends TestCase {
static int clientCount =0;
public void testMultipleClients() throws Exception {
RepositoryServer server = launchServer();
System.out.println(clientCount);
launchClient();
System.out.println(clientCount);
launchClient();
System.out.println(clientCount);
launchClient();
System.out.println(clientCount);
//wait until everything done.
//isClientCountZero();
Thread.sleep(10000);
server.shutdown();
assertEquals(0, server.state);
}
public static void launchClient() {
//incrementClientCount();
new Thread() {
public void run() {
try {
RepositoryClient.main(new String[]{});
} catch (Exception e) {
System.err.println("Unable to launch test client.");
}
}
}.start();
//decrementClientCount();
}
public static RepositoryServer launchServer() throws Exception {
final RepositoryServer server = ServerLauncher.create();
assertEquals(1, server.state);
new Thread() {
public void run() {
try {
server.process();
} catch (IOException ioe) {
System.err.println("Server completed");
}
}
}.start();
Thread.sleep(2000);
return server;
}
public static synchronized boolean isClientCountZero(){
if (clientCount==0) {
return true;
} else {
return false;
}
}
public static synchronized void decrementClientCount(){
clientCount--;
}
public static synchronized void incrementClientCount(){
clientCount++;
}
}
The code in question is in TestServer.java. When the Thread.sleep() methods are active, the server outputs text as expected. However, when the Thread.sleep() methods are commented out and replaced with the increment, decrement, and clientCount methods, it no longer outputs any text, just 'Server Completed'. What is my wrong with my solution to the posted link?
Thank you
Related
I'm making code for a Server that has multiple clients that joins in it. Here's what the server's looks like.
public class Server {
private final ServerSocket serverSocket;
private static final int PORT = 9000;
private WaitingRoom wroom = new WaitingRoom();
public Server(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
public void startServer() throws InterruptedException,Exception{
try {
int count = 0;
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
System.out.println("A new client has connected!");
ClientHandler clientHandler = new ClientHandler(new Player(count),socket);
Thread thread = new Thread(clientHandler);
thread.start();
count++;
System.out.println(clientHandler.getPlayer().getNickname());
wroom.join(clientHandler.getPlayer());
}
} catch (IOException e) {
closeServerSocket();
}
}
public void closeServerSocket() {
try {
if(serverSocket != null)
serverSocket.close();
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException,InterruptedException,Exception{
ServerSocket serverSocket = new ServerSocket(PORT);
Server server = new Server(serverSocket);
server.startServer();
}
}
I've a class named ClientHandler that manages these clients in a thread for each, and i pass it also in the Player class because i will use it for things like: Send msg, Receive msg. That's the ClientHandler class:
public class ClientHandler implements Runnable {
public static ArrayList<ClientHandler> clientHandlers = new ArrayList<>();
private Player player;
private String nickname;
private Socket socket;
private BufferedReader bufferedReader;
private BufferedWriter bufferedWriter;
public ClientHandler(Player player,Socket socket) throws InterruptedException,Exception{
try {
this.socket = socket;
this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.bufferedWriter= new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
nickname = this.bufferedReader.readLine();
player.init(nickname, this);
clientHandlers.add(this);
broadcastMessage("SERVER: " + nickname + " è entrato");
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
}
}
public Player getPlayer(){
return player;
}
public BufferedWriter getBufferedWriter(){
return bufferedWriter;
}
public BufferedReader getBufferedReader(){
return bufferedReader;
}
#Override
public void run() {
String messageFromClient;
while (socket.isConnected()) {
/* try {
// messageFromClient = bufferedReader.readLine();
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
break;
} */
}
}
public void broadcastMessage(String messageToSend) {
for (ClientHandler clientHandler : clientHandlers) {
try {
if (!clientHandler.nickname.equals(nickname)) {
clientHandler.bufferedWriter.write(messageToSend);
clientHandler.bufferedWriter.newLine();
clientHandler.bufferedWriter.flush();
}
} catch (IOException e) {
closeEverything(socket, bufferedReader, bufferedWriter);
}
}
}
private void writeToClient(String text) throws IOException{
bufferedWriter.write(text);
bufferedWriter.newLine();
bufferedWriter.flush();
}
public void removeClientHandler() {
clientHandlers.remove(this);
broadcastMessage("SERVER: " + nickname + " è uscito");
}
public void closeEverything(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter) {
removeClientHandler();
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (bufferedWriter != null) {
bufferedWriter.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now, the problem is: if I want to create a class named "WaitingRoom" for let players to waint until the wait's done. Where and how could I instantiate it? Before the linked code, i was instantiating it in the ClientHandler, but it worked only for a client a time. Here's what i wrote for the WaitingRoom class:
public class WaitingRoom {
private final int MAXPLAYERS = 2;
private ArrayList<Player> players = new ArrayList<Player>();
public ArrayList<Player> getPlayers(){
return players;
}
public void join(Player player) throws IOException,InterruptedException,Exception{
while(!addPlayer(player)){
player.sendMsg("waiting for join");
TimeUnit.SECONDS.sleep(1);
}
waitStart(player);
}
public boolean addPlayer(Player player){
if (players.size() >= MAXPLAYERS) return false;
players.add(player);
return true;
}
public boolean removePlayer(int idPlayer){
for(Player player : players){
if(player.getId() == idPlayer){
players.remove(player);
return true;
}
}
return false;
}
public void waitStart(Player player) throws IOException,InterruptedException,Exception{
if(players.size() < MAXPLAYERS)
player.sendMsg("sei entrato nella stanza d'attesa");
while(players.size() < MAXPLAYERS){
player.sendMsg("(" + players.size() + "/2) in attesa di giocatori...");
TimeUnit.SECONDS.sleep(1);
}
player.sendMsg("Inizio Gioco");
Player[] players2 = new Player[MAXPLAYERS];
for(int i=0;i<MAXPLAYERS;i++){
players2[0] = new Player(players.get(i).getId()).init(players.get(i).getNickname(),players.get(i).getClientHandler());
}
new Gioco(players2);
cleanRoom();
}
public void cleanRoom(){
players.clear();
}}
it's a really basic concept for waiting room and I only need a place where user must to wait before a gameloop. For example i don't really need multiple wainting rooms, one is ok for me, maybe.
I made a previous post a bit back working on getting a two-way server/client socket connection working. I've largely succeeded yet, but I still have one more step as a barrier. I'd like to make it so the client disconnects after they perform an operation, but the server remains up and can take in another client operation until the client makes a specific response. I'm attempting to do this through while loops in both the client and server. This is my server class:
import java.net.*;
import java.io.*;
public class ServerDemo {
private Socket mySocket = null;
private ServerSocket server = null;
private static ObjectInputStream in=null;
private static ObjectOutputStream out=null;
private static Payload myPayload=new Payload();
public ServerDemo(int port) throws ClassNotFoundException
{
double time=0;
int bytes=0;
try
{
server = new ServerSocket(port);
System.out.println("Server started");
System.out.println("Waiting for a client ...");
}
catch(IOException i)
{
System.out.println(i);
myPayload.setRepeat(false);
}
try {
while(myPayload.getRepeat()==true) {
mySocket = server.accept();
System.out.println("Client accepted");
in = new ObjectInputStream(
new BufferedInputStream(mySocket.getInputStream()));
out = new ObjectOutputStream(mySocket.getOutputStream());
myPayload.setDataPasses(10);
while (myPayload.getCurr()<myPayload.getDataPasses())
{
try
{
myPayload= (Payload) in.readObject();
myPayload.raisePasses();
out.writeObject(myPayload);
}
catch(IOException i)
{
System.out.println(i);
myPayload.setRepeat(false);
}
}
System.out.println("Closing connection");
mySocket.close();
in.close();
System.out.println("Operation Complete");
System.out.println("Client Address: "+myPayload.getClient());
System.out.println("Server Address: "+myPayload.getServer());
time=System.nanoTime()-(myPayload.getTime());
time=time/1000000000;
System.out.println("Total Time (in seconds): "+time);
bytes=(int) ( ((myPayload.getPacket().length)*myPayload.getDataPasses())/time);
System.out.println("Bytes per Second: "+bytes);
}
}
catch(IOException i)
{
System.out.println(i);
myPayload.setRepeat(false);
}
}
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
ServerDemo server=new ServerDemo(5000);
}
}
This is my client class:
import java.net.*;
import java.util.Scanner;
import java.io.*;
public class ClientDemo {
private Socket mySocket = null;
private ObjectInputStream in= null;
private ObjectOutputStream out = null;
private static long roundTrips=1;
private static Payload myPayload=new Payload();
public ClientDemo(String address, int port) throws ClassNotFoundException
{
int packageSize=1;
double time=0;
int bytes=0;
try
{
mySocket = new Socket(address, port);
System.out.println("Connected");
out = new ObjectOutputStream(mySocket.getOutputStream());
in = new ObjectInputStream(new BufferedInputStream(mySocket.getInputStream()));
}
catch(UnknownHostException u)
{
System.out.println(u);
}
catch(IOException i)
{
System.out.println(i);
}
while (myPayload.getCurr()<myPayload.getDataPasses())
{
try
{
if(myPayload.getCurr()==0) {
myPayload.setTime(System.nanoTime());
}
out.writeObject(myPayload);
myPayload= (Payload) in.readObject();
}
catch(IOException i)
{
System.out.println(i);
}
}
try
{
in.close();
out.close();
mySocket.close();
System.out.println("Operation Complete");
System.out.println("Client Address: "+myPayload.getClient());
System.out.println("Server Address: "+myPayload.getServer());
time=System.nanoTime()-(myPayload.getTime());
time=time/1000000000;
System.out.println("Total Time (in seconds): "+time);
bytes=(int) ( ((myPayload.getPacket().length)*myPayload.getDataPasses())/time);
System.out.println("Bytes per Second: "+bytes);
System.out.println("");
}
catch(IOException i)
{
System.out.println(i);
}
}
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
boolean isValid=false;
String response="";
int size=16384;
Scanner myScanner = new Scanner(System.in);
ClientDemo client=null;
String server="";
while (size>-1) {
System.out.println("Please enter a max data packet size. Enter -1 to end the program");
while(isValid==false) {
response=myScanner.next();
if(Long.parseLong(response)>=-1 && Long.parseLong(response)<=16384) {
isValid=true;
size=Integer.parseInt(response);
if(size>-1) {
myPayload.setPacket(fillPacket(size));
}
}
else {
System.out.println("Invalid Response. Please enter a value between 1 and 16384.");
}
}
if(size==-1) {
System.out.println("Closing server...");
myPayload.setRepeat(false);
client= new ClientDemo(server, 5000);
}
else {
isValid=false;
System.out.println("Please enter an amount of data passes.");
while(isValid==false) {
response=myScanner.next();
if(Long.parseLong(response)>=1) {
isValid=true;
roundTrips=Long.parseLong(response);
myPayload.setDataPasses(roundTrips);
}
else {
System.out.println("Invalid Response. Please enter a value of 1 or greater.");
}
}
isValid=false;
System.out.println("Please enter your client address.");
response=myScanner.next();
myPayload.setClient(response);
System.out.println("Please enter a server to connect to.");
response=myScanner.next();
server=response;
myPayload.setServer(server);
myPayload.reset();
client= new ClientDemo(server, 5000);
}
}
}
public static int[] fillPacket(int size) {
int[] thePacket= new int[size];
int current=0;
while(current<size) {
for(int counter=0;counter<100;counter++) {
if(current<size) {
thePacket[current]=counter;
current++;
}
}
}
return thePacket;
}
}
When I attempt to run both, the operation I have set up works completely fine, and entering -1 to close the program works but I run into errors when performing operations beyond that. Attempting to set size to -1 to end the program at this point causes an endless loop of
java.io.EOFException
inside ServerDemo, while entering what should be a valid packet size between 0 and 16384 instead produces an endless stream of
java.net.SocketException: Broken pipe (Write failed)
inside ClientDemo. Perhaps most strangely, the latter error only SOMETIMES occurs, not always. If anyone has any pointers on how to get this correctly working and remedying these errors, I would greatly appreciate it!
I would rather change approach. The usual one when doing this kind of stuff is create a thread to listen on your port, then, when a client connects, immediately dispatch the new task to a thread pool and continue listening.
This way not only your server will continue listening after the client disconnects, but also will be able to serve multiple clients in parallel (up to the thread pool size).
Also please use try-with-resources whenever possible to easily avoid resource leaking.
So your code could be changed to something like this:
Server class
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerDemo {
private int port;
private Thread listenThread;
private ExecutorService serverPool;
public ServerDemo(int port) {
this.port = port;
}
public synchronized void startServer() {
serverPool = Executors.newFixedThreadPool(4);
listenThread = new Thread(() -> {
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println(String.format("Listening on port %d", port));
System.out.println("1");
while (!Thread.interrupted()) {
System.out.println("2");
Socket clientSocket = serverSocket.accept();
System.out.println("3");
if(!Thread.currentThread().isInterrupted())
serverPool.submit(new ClientTask(clientSocket));
System.out.println("4");
}
} catch (IOException e) {
System.err.println("Error processing client connection");
e.printStackTrace();
}
System.out.println("ListenThread stopped");
}, "ListenThread");
listenThread.start();
}
public synchronized void stopServer() {
System.out.println("Stopping server...");
if (serverPool != null) {
serverPool.shutdown();
serverPool = null;
}
if(listenThread != null) {
listenThread.interrupt();
try (Socket voidSocket = new Socket("localhost", port)) {
// Void socket to unlock the accept() call
} catch (IOException e) {
}
listenThread = null;
}
}
private class ClientTask implements Runnable {
private final Socket clientSocket;
private ClientTask(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
System.out.println("Client accepted");
Payload myPayload = new Payload();
try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(clientSocket.getInputStream()));
ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream())) {
myPayload.setDataPasses(10);
while (myPayload.getCurr() < myPayload.getDataPasses()) {
try {
myPayload = (Payload) in.readObject();
myPayload.raisePasses();
out.writeObject(myPayload);
} catch (IOException i) {
System.out.println(i);
break;
} catch (ClassNotFoundException e) {
System.err.println("Error finding class to deserialize");
e.printStackTrace();
}
}
System.out.println("Operation Complete");
System.out.println("Client Address: " + myPayload.getClient());
System.out.println("Server Address: " + myPayload.getServer());
double time = System.nanoTime() - (myPayload.getTime());
time = time / 1000000000;
System.out.println("Total Time (in seconds): " + time);
int bytes = (int) (((myPayload.getPacket().length) * myPayload.getDataPasses()) / time);
System.out.println("Bytes per Second: " + bytes);
} catch (IOException e1) {
System.err.println("Error opening client I/O streams");
e1.printStackTrace();
}
try {
System.out.println("Closing connection");
clientSocket.close();
} catch (IOException e) {
System.err.println("Error closing client connection");
e.printStackTrace();
}
if(!myPayload.getRepeat())
stopServer();
}
}
public static void main(String[] args) throws ClassNotFoundException {
ServerDemo server = new ServerDemo(5000);
server.startServer();
// do other stuff including trapping for sigterm, then call server.stopServer() if needed
}
}
Client class
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class ClientDemo {
private static void executeClientJob(Payload myPayload, int port) {
double time = 0;
int bytes = 0;
try (Socket mySocket = new Socket(myPayload.getServer(), port);
ObjectOutputStream out = new ObjectOutputStream(mySocket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(mySocket.getInputStream()))) {
System.out.println("Connected");
while (myPayload.getCurr() < myPayload.getDataPasses()) {
if (myPayload.getCurr() == 0)
myPayload.setTime(System.nanoTime());
out.writeObject(myPayload);
myPayload = (Payload) in.readObject();
}
System.out.println("Operation Complete");
System.out.println("Client Address: " + myPayload.getClient());
System.out.println("Server Address: " + myPayload.getServer());
time = System.nanoTime() - (myPayload.getTime());
time = time / 1000000000;
System.out.println("Total Time (in seconds): " + time);
bytes = (int) (((myPayload.getPacket().length) * myPayload.getDataPasses()) / time);
System.out.println("Bytes per Second: " + bytes);
System.out.println("");
} catch (UnknownHostException u) {
u.printStackTrace();
} catch (IOException i) {
i.printStackTrace();
} catch (ClassNotFoundException c) {
c.printStackTrace();
}
}
private static void testAutomatic() {
for (int i = 0; i < 1; i++) {
Payload myPayload = new Payload();
myPayload.setPacket(fillPacket(40));
executeClientJob(myPayload, 5000);
}
Payload stopPayload = new Payload();
stopPayload.setRepeat(false);
executeClientJob(stopPayload, 5000);
}
private static void testInteractive() {
Payload myPayload;
boolean repeat;
do {
myPayload = readPayloadSettings();
repeat = myPayload.getRepeat();
executeClientJob(myPayload, 5000);
} while (repeat);
}
private static Payload readPayloadSettings() {
Payload ret = new Payload();
int size = 60;
#SuppressWarnings("resource")
Scanner myScanner = new Scanner(System.in);
System.out.println("Please enter a max data packet size. Enter -1 to end the program");
while (true) {
String response = myScanner.next();
if (Long.parseLong(response) >= -1 && Long.parseLong(response) <= 16384) {
size = Integer.parseInt(response);
break;
} else {
System.out.println("Invalid Response. Please enter a value between 1 and 16384.");
}
}
if (size == -1) {
System.out.println("Closing server...");
ret.setRepeat(false);
} else {
ret.setPacket(fillPacket(size));
System.out.println("Please enter an amount of data passes.");
while (true) {
String response = myScanner.next();
if (Long.parseLong(response) >= 1) {
ret.setDataPasses(Long.parseLong(response));
break;
} else {
System.out.println("Invalid Response. Please enter a value of 1 or greater.");
}
}
System.out.println("Please enter your client address.");
ret.setClient(myScanner.next());
System.out.println("Please enter a server to connect to.");
ret.setServer(myScanner.next());
}
return ret;
}
public static int[] fillPacket(int size) {
int[] thePacket = new int[size];
int current = 0;
while (current < size) {
for (int counter = 0; counter < 100; counter++) {
if (current < size) {
thePacket[current] = counter;
current++;
}
}
}
return thePacket;
}
public static void main(String[] args) throws ClassNotFoundException {
testInteractive();
//testAutomatic();
}
}
Payload class (with defaults to quick create an automatic test)
import java.io.Serializable;
public class Payload implements Serializable {
private int curr=0;
private long dataPasses=5;
private long time;
private String client="localhost";
private String server="localhost";
private int[] packet=new int[0];
private boolean repeat=true;
public Payload() {
}
public int getCurr() {
return curr;
}
public void setCurr(int curr) {
this.curr = curr;
}
public long getDataPasses() {
return dataPasses;
}
public void setDataPasses(long roundTrips) {
this.dataPasses = roundTrips;
}
public long getTime() {
return time;
}
public void setTime(long nanoTime) {
time = nanoTime;
}
public String getClient() {
return client;
}
public void setClient(String client) {
this.client = client;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public int[] getPacket() {
return packet;
}
public void setPacket(int[] packet) {
this.packet = packet;
}
public boolean getRepeat() {
return repeat;
}
public void setRepeat(boolean r) {
this.repeat = r;
}
public void reset() {
curr=0;
dataPasses=0;
}
public void raisePasses() {
curr++;
}
}
I've written minimal example, but it's still too long, so let me know I should post the link to Pastebin instead.
Server:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class Srv {
static final int PORT = 9001;
static final String HOST = "127.0.0.1";
public static void runInstance() {
try (AsynchronousServerSocketChannel asynchronousServerSocketChannel =
AsynchronousServerSocketChannel.open()) {
if (asynchronousServerSocketChannel.isOpen()) {
asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024);
asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
asynchronousServerSocketChannel.bind(new InetSocketAddress(HOST, PORT));
System.out.println(String.format("Launched master on %s:%d", HOST, PORT));
asynchronousServerSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
#Override
public void completed(AsynchronousSocketChannel result, Void attachment) {
asynchronousServerSocketChannel.accept(null, this);
try {
result.read(ByteBuffer.allocate(1024));
System.out.println("Conn from:" + result.getRemoteAddress());
} catch (Exception exn) {
exn.printStackTrace();
} finally {
try {
result.close();
} catch (IOException exn) {
exn.printStackTrace();
}
}
}
#Override
public void failed(Throwable exn, Void attachment) {
asynchronousServerSocketChannel.accept(null, this);
throw new UnsupportedOperationException("can't accept");
}
});
System.in.read();
} else {
System.out.println("The asynchronous server-socket channel cannot be opened");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import static java.lang.Thread.sleep;
public class Wrk {
static final int PORT = 9001;
static final String HOST = "127.0.0.1";
public static void runInstance() throws InterruptedException {
sleep(1000); //HERE
try(AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open()) {
if (asynchronousSocketChannel.isOpen()) {
asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024);
asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 1024);
asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
asynchronousSocketChannel.connect(new InetSocketAddress(HOST, PORT), null,
new CompletionHandler<Void, Void>() {
#Override
public void completed(Void result, Void attachment) {
try {
System.out.println("Connected to: " + HOST + PORT);
asynchronousSocketChannel.read(ByteBuffer.allocate(1024)).get();
} catch (Exception exn) {
exn.printStackTrace();
} finally {
try {
asynchronousSocketChannel.close();
} catch (IOException exn) {
exn.printStackTrace();
}
}
}
#Override
public void failed(Throwable throwable, Void o) {
System.out.println("Connection cannot be established");
}
});
sleep(1000); //AND HERE
} else {
System.out.println("The asynchronous socket channel cannot be opened");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Boilerplate to run:
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread srv = new Thread(new Runnable() {
#Override
public void run() {
Srv.runInstance();
}
});
srv.start();
Thread wrk1 = new Thread(new Runnable() {
#Override
public void run() {
try {
Wrk.runInstance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
wrk1.start();
}
}
So, if I have the code like this, it gives me the following output:
Launched master on 127.0.0.1:9001
Connected to: 127.0.0.1 9001
Conn from:/127.0.0.1:50415
But if I remove those sleep()s in Srv.runInstance(), I get:
Connection cannot be established
Launched master on 127.0.0.1:9001
Conn from:/127.0.0.1:50438
So, does that mean that client connects to server, but server refuses? I don't clearly understand what happens here and documentation is rather poor, so I don't know where to look for solutions.
The only sleep I see in the posted code is in Wrk.runInstance. However, the order of your output makes it pretty clear what is going on. Your working is trying to connect to the server before it has fully initialized. As you can see in your output, the "Connection message" is before the "Launched master".
The server takes a bit of time to start, so without the sleep, your client is trying to connect to something which is not yet there.
I'm trying to implement WebSockets with a Javascript-based client and a Java-based server. I think I've done all the correct steps, but for an unknown reason, I can't establish the connection with both.
When the server socket receives a connection, it handles to form a websocket-accept response, and it sends back to the client, but the connection in the client socket instantly close, weird that there's no handshake problem.
Does anyone have an idea what might be the problem?
Here's my server code implemented in java:
package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import server.message.Message;
import server.message.SpeakMessage;
public class Server implements ConnectionListener {
private static final int PORT = 1509;
private MessageDispatcher dispatcher = new MessageDispatcher();
private List<ConnectionManager> clients = new ArrayList<>();
public void listen() {
try (ServerSocket server = new ServerSocket(PORT)) {
System.out.printf("Listening on port %d...%n", PORT);
while (true) {
System.out.println("Waiting for connection...");
Socket client = server.accept();
System.out.println("Incoming connection - Attempting to establish connection...");
ConnectionManager manager = new ConnectionManager(client, dispatcher, this);
manager.start();
}
} catch (IOException e) {
System.out.println("Unable to start server");
e.printStackTrace();
}
System.exit(0);
}
public void execute() {
try {
while (true) {
if (dispatcher.isEmpty()) {
Thread.sleep(100);
continue;
}
Message msg = dispatcher.read();
if (msg instanceof SpeakMessage)
broadcast(MessageEncoder.spoke(((SpeakMessage) msg).getText()));
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
final Server server = new Server();
new Thread(new Runnable() {
#Override
public void run() {
server.listen();
}
}).start();
server.execute();
}
public synchronized void broadcast(byte[] message) {
for (ConnectionManager client : clients) {
client.send(message);
}
}
#Override
public synchronized void clientConnected(ConnectionManager who) {
clients.add(who);
System.out.println("Connected client " + clients.size());
}
#Override
public synchronized void clientDisconnected(ConnectionManager who) {
clients.remove(who);
}
}
Heres subclass ConnectionManager of server:
package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.security.MessageDigest;
import java.util.Properties;
import server.message.HandshakeMessage;
import server.message.Message;
public class ConnectionManager {
private static final int CLIENT_VERSION = 1;
private Socket socket;
private MessageDecoder decoder = new MessageDecoder();
private MessageDispatcher dispatcher;
private ConnectionListener listener;
public ConnectionManager(Socket connection, MessageDispatcher dispatcher, ConnectionListener listener) {
socket = connection;
this.dispatcher = dispatcher;
this.listener = listener;
}
public void start() {
Thread t = new Thread(new ChannelReader());
t.setName("Client thread");
t.setDaemon(true);
t.start();
}
public void send(byte[] data) {
if (socket == null)
return;
try {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.write(data);
dos.flush();
} catch (IOException e) {
disconnect("Client closed the connection");
}
}
private class ChannelReader implements Runnable {
private boolean accepted = false;
private String ret = null;
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
while (socket != null && socket.isConnected()) {
int len = in.readShort();
if (len < 0) {
disconnect("Invalid message length.");
}
String s;
readLine(in);
Properties props = new Properties();
while((s=readLine(in)) != null && !s.equals("")) {
String[] q = s.split(": ");
props.put(q[0], q[1]);
}
if(props.get("Upgrade").equals("websocket") && props.get("Sec-WebSocket-Version").equals("13")) { // check if is websocket 8
String key = (String) props.get("Sec-WebSocket-Key");
String r = key + "" + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // magic key
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.reset();
md.update(r.getBytes());
byte[] sha1hash = md.digest();
String returnBase = base64(sha1hash);
ret = "HTTP/1.1 101 Switching Protocols\r\n";
ret+="Upgrade: websocket\r\n";
ret+="Connection: Upgrade\r\n";
ret+="Sec-WebSocket-Accept: "+returnBase;
} else {
disconnect("Client got wrong version of websocket");
}
Message msg = decoder.decode((String) props.get("Sec-WebSocket-Protocol"));
if (!accepted) {
doHandshake(msg);
} else if (dispatcher != null) {
dispatcher.dispatch(msg);
}
}
} catch (Exception e) {
disconnect(e.getMessage());
e.printStackTrace();
}
}
private void doHandshake(Message msg) {
if (!(msg instanceof HandshakeMessage)) {
disconnect("Missing handshake message");
return;
}
HandshakeMessage handshake = (HandshakeMessage) msg;
if (handshake.getVersion() != CLIENT_VERSION) {
disconnect("Client failed in handshake.");
return;
}
send(ret.getBytes());
accepted = true;
listener.clientConnected(ConnectionManager.this);
}
private String base64(byte[] input) throws ClassNotFoundException,
SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("sun.misc.BASE64Encoder");
java.lang.reflect.Method m = c.getMethod("encode", new Class<?>[]{byte[].class});
String s = (String) m.invoke(c.newInstance(), input);
return s;
}
private String readLine(InputStream in) {
try{
String line = "";
int pread;
int read = 0;
while(true) {
pread = read;
read = in.read();
if(read!=13&&read!=10)
line += (char) read;
if(pread==13&&read==10) break;
}
return line;
}catch(IOException ex){
}
return null;
}
}
public synchronized void disconnect(String message) {
System.err.println(message);
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
socket = null;
listener.clientDisconnected(ConnectionManager.this);
}
}
And the MessageDispatcher:
package server;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque;
import server.message.Message;
public class MessageDispatcher {
Queue<Message> messageQueue = new LinkedBlockingDeque<>();
public void dispatch(Message message) {
messageQueue.offer(message);
}
public Message read() {
return messageQueue.poll();
}
public boolean isEmpty() {
return messageQueue.isEmpty();
}
}
And heres my client code implemented in javascript:
var canvas, // Canvas DOM element
ctx, // Canvas rendering context
socket; // Socket connection
function init() {
// Initialise the canvas
canvas = document.getElementById("gameCanvas");
ctx = canvas.getContext("2d");
// Maximise the canvas
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Initialise socket connection
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:1509/", ["1", "YURI"]);
socket.onopen = onSocketConnected();
socket.onclose = onSocketDisconnect();
socket.onmessage = onSocketMessage();
socket.onerror = onSocketError();
} else {
alert("The browser does not support websocket.");
}
};
// Socket message
function onSocketMessage(message) {
console.log('Message: ' + message.data);
};
// Socket error
function onSocketError(error) {
console.log('Error: ' + error.data);
};
// Socket connected
function onSocketConnected() {
console.log("Connected to socket server");
};
// Socket disconnected
function onSocketDisconnect() {
console.log("Disconnected from socket server");
};
I think, it is because you are using the Socket Package on the Java Server Side and the WebSocket API on the Client Side. Your idea is really good but the wrong technology.
Keep the WebSocket on the Client Side (Javascript) becaue you don't have lots of other possibilities, but try JWebSocket on the Server side (Java). In Fact WebSocket is using TCP/IP but its own communication protocol over TCP/IP. The Java Socket Package is purely TCP/IP. Re-write your server with JWebSocket, all details about JWebSocket can be found at:
http://jwebsocket.org/.
I hope my answer will help you.
you must specify end of return packet with "\r\n\r\n"
ret = "HTTP/1.1 101 Switching Protocols\r\n";
ret+="Upgrade: websocket\r\n";
ret+="Connection: Upgrade\r\n";
ret+="Sec-WebSocket-Accept: "+returnBase + "\r\n\r\n";
and for create accept key i use
public class WSKeyGenerator {
private final static String MAGIC_KEY =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
public static String getKey(String strWebSocketKey) throws
NoSuchAlgorithmException {
strWebSocketKey += MAGIC_KEY;
MessageDigest shaMD = MessageDigest.getInstance("SHA-1");
shaMD.reset();
shaMD.update(strWebSocketKey.getBytes());
byte messageDigest[] = shaMD.digest();
BASE64Encoder b64 = new BASE64Encoder();
return b64.encode(messageDigest);
}
}
I recommend that use the http://websocket.org/echo.html to check the server's websocket functionality
I have Vector of threads, and i wanna check all items in this vector. Everyone item is connection of user to server. I wanna "clean" all dead connections.
I can't find where I'm wrong.
Here is it my code :
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package server;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import server.ServerCore.Clients;
/**
*
* #author pisio
*/
public class GrimReaper extends Thread {
private int timeout = LoadSettings.Init().getConfigInt("grimreaper") * 1000; // 1000 ms = 1 sec
public GrimReaper() {
super();
}
public void cleanUserThreads() {
Vector users = ServerCore.users;
if (users.size() < 1) {
return;
}
Iterator iteratr = users.iterator();
while (iteratr.hasNext()) {
Clients user = (Clients) iteratr.next();
System.out.println(user.isAlive());
if (user.getClient().isClosed()) {
user.interrupt();
if (user.isInterrupted()) {
System.out.println("Beshe kiknat");
}
iteratr.remove();
// if (PublicVaribles.Init().systemLevelMesseging() == 2) {
System.out.println("+\t Kicked user ");
// }
}//if is dead
}//while
}//cleanUserThreads;
#Override
public void run() {
try {
while (ServerCore.getServerRunning()) {
cleanUserThreads();
sleep(timeout);
System.out.println("nani na shinigami");
}
} catch (InterruptedException ex) {
Logger.getLogger(GrimReaper.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
package server;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import server.DB.DataBase;
public class ServerCore extends Thread {
private static ServerCore sc = null;
private int port = LoadSettings.Init().getConfigInt("port");
private int max_connections = LoadSettings.Init().getConfigInt("max_connections");
private String ipServer = LoadSettings.Init().getConfig("ipServer");
private ServerSocket socket;
private static boolean serverRuning = false;
public static Vector users = new Vector();
public GrimReaper shinigami = new GrimReaper();// Shinigami from Japanice is Grim Reaper!
private ServerCore() {
}
#Override
public void run() {
shinigami.start();
try {
socket = new ServerSocket(port, max_connections);
System.out.println("+++\t Server was started at address:" + socket.getLocalSocketAddress() + " with posible max users " + max_connections);
serverRuning = true;
while (serverRuning) {
Socket client = socket.accept();
shinigami.cleanUserThreads();
if (users.size() < max_connections) {
Clients cls = new Clients(client);
cls.start();
users.add(cls);
System.out.println("++\tClient was connected:" + client.toString());
} else {
Clients cls = new Clients(client);
cls.start();
cls.getOutput().println("sorry_no_avable_slot");
cls.getOutput().flush();
cls.interrupt();
}
}
} catch (IOException ex) {
// Logger.getLogger(ServerCore.class.getName()).log(Level.SEVERE, null, ex);
}
}
//run method
public void sendUserMsg() {
Scanner input = PublicVaribles.Init().inputKeyBord();
System.out.print("Enter UserID/user connection port:");
int userID = input.nextInt();
Iterator iterator = users.iterator();
while (iterator.hasNext()) {
Clients cls = (Clients) iterator.next();
/// System.out.println("Passed user:" + cls.getUserId());
if (cls.getUserId() == userID) {
System.out.print("\nEnter msg:");
String str = input.next();
cls.getOutput().println(str);
System.out.println("+\t" + cls.getUserId() + " get msg :" + str);
}
}
}
//SendUserMsg
public void stopServer() {
statusServer();
serverRuning = false;
try {
socket.close();
} catch (IOException ex) {
Logger.getLogger(ServerCore.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("+++\t SERVER WAS STOPED !");
}
//Stop server
public void statusServer() {
if (serverRuning) {
System.out.println("+++\t Server running at port:" + port + " with connected users :" + users.size() + "/" + max_connections);
} else {
System.out.println("+++\t Server IS NOT RUNNING!");
}
}
//Status server
public static boolean getServerRunning() {
// function for GrimReaper .... R.I.P :D
return ServerCore.serverRuning;
}
public static ServerCore Init() {
if (ServerCore.sc == null) {
ServerCore.sc = new ServerCore();
}
return ServerCore.sc;
}
// SingleTon
public class Clients extends Thread {
private Socket client;
private int userID;
private Scanner input;
private PrintWriter output;
public Clients(Socket socket) {
client = socket;
userID = socket.getPort();
try {
input = new Scanner(client.getInputStream());
output = new PrintWriter(client.getOutputStream(), true);
} catch (IOException ioEx) {
System.out.println(ioEx.toString());
}
}
public int getUserId() {
return userID;
}
public Scanner getInput() {
return input;
}
public PrintWriter getOutput() {
return output;
}
public Socket getClient() {
return client;
}
}//Clients Class
}
Note: I'm assuming Clients extends Thread.
It looks like you might be using interrupt() incorrectly. After calling user.interrupt(), it's up to that thread to check that it has been interrupted by calling Thread.interrupted() and terminate itself if true. Here's an extremely basic example:
class Clients extends Thread {
#Override
public void run() {
while (!Thread.interrupted()) {
//do work
}
//thread has been interrupted and quits
}
}