I am trying out a basic RMI example .But whenever I run the service I get the following error
java.rmi.ConnectException: Connection refused to host: 116.203.202.217; nested exception is:
java.net.ConnectException: Connection timed out: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:601)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
at java.rmi.Naming.bind(Naming.java:111)
at rmi.remote.RemteImpl.main(RemteImpl.java:29)
Here is the code
package rmi.remote;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class RemteImpl extends UnicastRemoteObject implements RemoteIntf{
protected RemteImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public String sayHello() throws RemoteException {
// TODO Auto-generated method stub
return "hi";
}
public static void main(String a[])
{
try {
RemoteIntf service=new RemteImpl();
Naming.bind("Remote",service);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I am using windows 7 OS
Your bind string is incorrect. It should be "rmi://localhost/Remote". And you should also check your 'hosts' file to make sure it maps "localhost" to 127.0.0.1, and your real hostname to your real host address.
It looks like your RMI registry is not running, which is causing the bind call to fail. You are also not binding to a URL but just to a name.
Usually you'd call bind like so:
Naming.bind("//registryHost:port/remote", service);
where registryHost points at the machine that is running your RMI registry.
For a simple local test you'd make the URL "//localhost:port/remote" and run the rmiregistry service on your local machine.
How to do this is explained for example here:
http://www.javacoffeebreak.com/articles/javarmi/javarmi.html
Excerpt:
To start the registry, Windows users should do the following (assuming that your java\bin directory is in the current path):-
start rmiregistry
To start the registry, Unix users should do the following:-
rmiregistry &
public class RemteImpl extends UnicastRemoteObject implements RemoteIntf{
from RemoteInf is a interface which implements Remote, so, in your main code
RemoteIntf service=new RemteImpl(); //avoid this
//priort to adding this also consider to make sure you have initialized security Manager for allowing connection from or all given IP address.
RemoteImpl service = new RemoteImpl();
should be changed to
RemoteInt service = new RemoteImpl();
where a server object is needed. After that , create a server registry in your code if don't want to use rmiregistry.
LocateRegistry.createRegistry(*port*);
finally, bind the service to a url where a rmi service is provided, using
String url = "rmi://127.0.0.1/RemoteObjectRegisteration" ; //or (your remote ip
address on place of 127.0.0.1)
Naming.bind(url, service);
and the server side should be okay. and You should take some time learning how to ask questions in stack overflow.........
Related
I am having trouble finding the source of this error. I implemented a simple service using protobuf:
syntax = "proto3";
package tourism;
service RemoteService {
rpc Login(LoginUserDTO) returns (Response) {}
}
message AgencyDTO{
int32 id=1;
string name=2;
string email=3;
string password=4;
}
message LoginUserDTO{
string password=1;
string email=2;
}
message SearchAttractionsDTO{
string name=1;
int32 start_hour=2;
int32 start_minute=3;
int32 stop_hour=4;
int32 stop_minute=5;
AgencyDTO loggedUser=6;
}
message AttractionDTO{
int32 id=1;
string name=2;
string agency=3;
int32 hour=4;
int32 minute=5;
int32 seats=6;
int32 price=7;
}
message ReservationDTO{
int32 id=1;
string first_name=2;
string last_name=3;
string phone=4;
int32 seats=5;
AttractionDTO attraction=6;
AgencyDTO agency=7;
}
message Response{
enum ResponseType{
OK=0;
NOT_LOGGED_ID=1;
SERVER_ERROR=2;
VALIDATOR_ERROR=3;
}
ResponseType type=1;
AgencyDTO user=2;
string message=3;
}
When using a java client everything works fine, the server receives the request and responds appropriately. When using C# with the same .proto file for generating sources at the client.Login() I get the following errror: Grpc.Core.RpcException Status(StatusCode=Unimplemented, Detail="Method tourism.RemoteService/Login is unimplemented"). The server receives the request but does not have time to respond and throws:
INFO: Request from ex#ex.com
May 22, 2017 12:28:58 AM io.grpc.internal.SerializingExecutor run
SEVERE: Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2#4be43082
java.lang.IllegalStateException: call is closed
at com.google.common.base.Preconditions.checkState(Preconditions.java:174)
at io.grpc.internal.ServerCallImpl.sendHeaders(ServerCallImpl.java:103)
at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:282)
at ServiceImp.login(ServiceImp.java:20)
at tourism.RemoteServiceGrpc$MethodHandlers.invoke(RemoteServiceGrpc.java:187)
at io.grpc.stub.ServerCalls$1$1.onHalfClose(ServerCalls.java:148)
at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:262)
at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2.runInContext(ServerImpl.java:572)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:52)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:117)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Java server:
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import tourism.RemoteServiceGrpc;
import tourism.Service;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Created by Andu on 21/05/2017.
*/
public class ServerGrpc {
Logger logger= Logger.getLogger(ServerGrpc.class.getName());
private final Server server;
private final int port;
public ServerGrpc(int p){
port=p;
server= ServerBuilder.forPort(port).addService(new ServiceImp()).build();
}
public void start() throws IOException {
server.start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
// Use stderr here since the logger may has been reset by its JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
ServerGrpc.this.stop();
System.err.println("*** server shut down");
}
});
}
public void stop() {
if (server != null) {
server.shutdown();
}
}
void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
private class ServiceImp extends RemoteServiceGrpc.RemoteServiceImplBase {
Logger log=Logger.getLogger(ServiceImp.class.getName());
#Override
public void login(Service.LoginUserDTO request, StreamObserver<Service.Response> responseStreamObserver){
super.login(request,responseStreamObserver);
log.log(Level.INFO,"Request from "+request.getEmail());
Service.Response response= Service.Response.newBuilder().setMessage("Hello "+request.getEmail()+", I know your password: "+request.getPassword()).build();
responseStreamObserver.onNext(response);
responseStreamObserver.onCompleted();
}
}
}
C# Client:
namespace testGrpc2
{
class MainClass
{
public static void Main(string[] args)
{
var channel = new Channel("127.0.0.1:61666",ChannelCredentials.Insecure);
var client = new RemoteService.RemoteServiceClient(channel);
Response response=client.Login(new LoginUserDTO{Email="ex#ex.com",Password="notmypassword"});
Console.WriteLine(response);
Console.ReadKey();
}
}
}
I managed to find the source of the problem. For anyone else having this problem:
Make sure your .proto file is identical for both client and server and it has the same package. When the client calls a method on the remote server, it uses the full name of the remote class and the package.
However this was not the reason why the method appeared as unimplemented to the client. It was this:
super.login(request,responseStreamObserver);
Calling the super method login sends an async UNIMPLEMENTED error code back to the client. This is the login() method in the generated class:
public void login(LoginUserDTO request,StreamObserver<Response> responseObserver) {
asyncUnimplementedUnaryCall(METHOD_LOGIN, responseObserver);
}
So make sure in the implementation of your service methods you don't call the super method as it will appear to the client as UNIMPLEMENTED. If you generate #Override methods using IntelliJ IDEA it will add the super method call. Make sure to delete it.
For me it was that I forget adding endpoint of gRpc service in startup class.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
//Add your endpoint here like this
endpoints.MapGrpcService<YourProtoService>();
});
For me, using the C# client, the problem was that I wasn't overriding the generated service method.
Thanks to Alexandru - this helped solve my problem with Akka gRPC client and Python grPC server. In my case, I had same packages and preamble in .proto file but had eliminated message classes and gRPC functions not needed for this specific use case in the Python gRPC server. When I made the .proto files identical, everything worked and I no longer received UNIMPLEMENTED errors. This is needed for languages beyond the C#/Java example cited. Thanks again.
My server and client were both java, and the problem was removed after closing and opening the project in IntelliJ!!
I am trying to write a class which would print the actual hostname of the IP address supplied as an argument to the InetAddress.getByName(). But everytime I run the program the IP address gets printed on the console rather than the hostname.
This is my output:=
208.73.211.249
What would I have to do to print it correctly?
import java.net.*;
public class Inet1 {
public static void main(String[] args) throws UnknownHostException {
InetAddress ia=null;
ia=InetAddress.getByName("74.125.236.50");
System.out.print(ia.getHostName());
}
}
InetAddress inetAddr = InetAddress.getByName("74.125.236.50");
String hostname = inetAddr.getHostName(); // Get the host name
The underlying system configuration might not allow you to access the host name. Then there's nothing you can do on Java level.
Have you tried
System.out.println(ia.getCanonicalHostName());
?
I'm trying to return a normal class via a RMI call. My server holds a instance of a class called GameState that i want to perform actions on via it's methods, from a client application. So the RMI works fine if a just return a int or something, but when a try to return GameState, which is a class defined inside the GameServer java file, the following error occurs (game state is declared neither public, protected or private):
Exception in thread "main" java.lang.IllegalAccessError: tried to access class GameState from class $Proxy0
at $Proxy0.getGameState(Unknown Source)
at GameClient.login(GameClient.java:204)
at GameClient.main(GameClient.java:168)
So, i guess the client application knows how GameState looks, but dont have any access to it?
I have tried to make GameState a public class in it's own file, but then the different connecting client applications get each their own GameState, so it's seems like that dont get it from the server.
Here are some code that i think is relevant:
The remote interface:
import java.rmi.*;
public interface ServerInterface extends Remote
{
public GameState getGameState() throws RemoteException;
}
Some if the server code:
public class GameServer extends UnicastRemoteObject implements ServerInterface {
/**
*
*/
private static final long serialVersionUID = -6633456258968168102L;
private final static int DEFAULT_NAMING_PORT = 9955; // TODO: IMPORTANT - change this to a group-specific number,
// e.g., 2000 + group number. The number should be the same
// as in GameClient.java.
private final GameState m_state;
public static void main(String[] args) {
//the variables: port and host etc it configurated here, but has nothing to do with the RMI problem.
try {
GameServer instance = new GameServer(players);
System.out.print("Setting up registry on "+host+":"+port+" ... ");
//Set up an unrestricted security manager.
if (System.getSecurityManager() == null) {
// Set security manager to an instance of a dynamically created
// subclass of RMISecurityManager with the checkPermission() method overloaded
System.setSecurityManager(
new RMISecurityManager() {
#Override
public void checkPermission(Permission permission) {
}
}
);
}
// Create a registry for binding names (name server)
Registry naming = LocateRegistry.createRegistry(port);
System.out.println("done.");
String rmiObjectName = "GeschenktServer";
System.out.print("Binding name "+rmiObjectName+" ... ");
naming.rebind(rmiObjectName, instance);
System.out.println("done.");
} catch(RemoteException e) {
System.err.println("Could not start server: "+e);
System.exit(-1);
}
}
//the rest of the server code....
//the GameState declared in the same file
class GameState implements java.io.Serializable {
private static final long serialVersionUID = 545671487061859760L;
//the rest of the Game state code.
Here is some of the client code:
private void login() {
try {
System.out.println("Connecting to server on host "+m_host+".");
// Set up an unrestricted security manager. In the server we trust.
// See GameServer.java for code explanation.
if (System.getSecurityManager() == null) {
System.setSecurityManager(
new RMISecurityManager() {
#Override
public void checkPermission(Permission permission) {
}
}
);
}
System.out.print("Locating registry on "+m_host+":"+m_port+" ... ");
Registry naming = LocateRegistry.getRegistry(m_host, m_port);
System.out.println("done.");
String name = "GeschenktServer";
System.out.print("Looking up name "+name+" ... ");
m_server = (ServerInterface) naming.lookup(name);
System.out.println("done.");
// TODO: Connect the player, i.e., register the player with the server.
// Make sure that the player cannot register if there are already enough players.
m_Id = m_server.getGameState().loginPlayer(m_name); //this line is causing the error...
if(m_Id < 0)
System.exit(0);
System.out.println("Server connection successful.");
m_window = new GameWindow(m_server, m_name, m_Id);
m_window.run();
} catch (Exception e) {
System.out.println("Connection failed - "+e);
System.exit(1);
}
}
}
I am using eclipse to do all this, and based on what i have red about RMI in eclipse, rmic and that stuff is not needed anymore, i'm i right?
So anyone with any idea?
Thanks in advance!
I don't think this is a permission problem. I cannot tell for sure from the code above, but I would assume it is a codebase problem. Did you configure the codebase also on client-side?
To deserialize the GameState class, the client needs to be able to load the class definition. This definition is located in the Server implementation and not the interface. Normally, the Server implementation should not be compiled to the client's classpath, only the interface should. I am not entirely sure, as in your solution the interface seems to have a dependency on the implementation due to the GameState which is not a good idea btw. Anyways, try adding a codebase configuration to your VM-args. Assuming you execute everything on localhost, it should look like this:
-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/
Where ${workspace_loc} is the absolute path to your workspace and PROJECT-NAME is the name of the server project. Eclipse will resolve ${workspace_loc} automatically, so you only need to set your PROJECT-NAME
As a side note: If you implement it that way, the GameState object is transmitted to the client-side and is executed on the client, having no effect whatsoever on the execution of the server. Is this really what you want? If you want the GameState instance to execute on the server-side, GameState also needs to implement Remote, not Serializable, and you need to export it when transmitting its stub to the client.
Finally, as you correctly stated, you do not need to use rmic since Java 1.5
try to return GameState, which is a class defined inside the
GameServer java file, the following error occurs (game state is
declared neither public, protected or private)
This is the problem. Only the GameServer class and classes in the same package can create instances of GameState. Your RMI proxy object (stub) Make it a public class in its own file.
I have tried to make GameState a public class in it's own file, but
then the different connecting client applications get each their own
GameState, so it's seems like that dont get it from the server
That's correct. It is serialized to each client. If you want to share a single GameState and have it remain at the server, it has to be an exported remote object itself, with a remote interface called GameState.
The IllegalAccessError reason is simple: GameState is NOT public
However, there is a larger issue:
you do understand that loginPlayer will not do what you like it to... The GameState is a copy of the original state. You want GameState to be Remote not serializable, so you can execute the operation on the server, not each client to get a useless copy of.
I'm doing my first steps with RMI, and I have a simple question.
I have a .jar file which has the implementation of several methods from a library.
I want to call this methods in the .jar file using RMI.
What I'm trying is to create a kind of a wrapper to do it.
So, I'm working on something like this:
Interface class: This interface has the methods to be implemented by the remote object.
Implementation class: This class, has the implementation of the interface methods, each implementation calls the corresponding method in the .jar file. E.g., the jar file has a method called getDetails(), and it returns a "ResponseDetail" object. ResponseDetail is a response class I have in the .jar.
Server class: it binds the methods to the rmiregistry
Client class: it will consume the methods implemented in implementation.
So far so good? :)
Now, I have a lib folder where resides the .jar file.
In the server machine I have deployed the Interface, Implementation and Server classes. I've generated the stub, and I ran the rmiregistry successfully, but, with these details:
To start the rmiregistry, I had to set the classpath in the command line to reference the .jar files, otherwise I get the java.lang.NoClassDefFoundError. I did it with this .sh file:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
rmiregistry -J-classpath -J".:${THE_CLASSPATH}"
To start the server, I had to set the classpath as well to reference the .jar files, otherwise, I get the java.lang.NoClassDefFoundError. I've used something like this:
THE_CLASSPATH=
for i in `ls ./lib/*.jar` do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" Server
Client machine:
To run the Client.class file from the client machine, I had to copy the .jar files to it, and make reference to them in the classpath, because otherwise, it does not run and I get the java.lang.NoClassDefFoundError. I had to use this on the client machine:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" HelloClient
Is this ok? I mean, do I have to copy the .jar files to the client machine to execute methods through RMI?
Prior to JDK v5 one had to generate the RMI stubc using the rmic (RMI Compiler). This is done automatically from JDK v5 on. Moreover, you can start the RMI Registry from within the Java code as well. To start with a simple RMI application you may want to follow the following steps:
Create the interface:
import java.rmi.*;
public interface SomeInterface extends Remote {
public String someMethod1() throws RemoteException;
public int someMethod2(float someParameter) throws RemoteException;
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException;
}
Implement the interface:
import java.rmi.*;
import java.rmi.server.*;
public class SomeImpl extends UnicastRemoteObject implements SomeInterface {
public SomeImpl() throws RemoteException {
super();
}
public String someMethod1() throws RemoteException {
return "Hello World!";
}
public int someMethod2( float f ) throws RemoteException {
return (int)f + 1;
}
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException {
int i = someStruct.getInt();
float f = someStruct.getFloat();
someStruct.setInt(i + 1);
someStruct.setFloat(f + 1.0F);
return someStruct;
}
}
Implement a non-primitive serializable object that is to be passed between a client and the server:
import java.io.*;
public class SomeStruct implements Serializable {
private int i = 0;
private float f = 0.0F;
public SomeStruct(int i, float f) {
this.i = i;
this.f = f;
}
public int getInt() {
return i;
}
public float getFloat() {
return f;
}
public void setInt(int i) {
this.i = i;
}
public void setFloat(float f) {
this.f = f;
}
}
Implement the server:
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.net.*;
import java.io.*;
public class SomeServer {
public static void main(String args[]) {
String portNum = "1234", registryURL;
try{
SomeImpl exportedObj = new SomeImpl();
startRegistry( Integer.parseInt(portNum) );
// register the object under the name "some"
registryURL = "rmi://localhost:" + portNum + "/some";
Naming.rebind(registryURL, exportedObj);
System.out.println("Some Server ready.");
} catch (Exception re) {
System.out.println("Exception in SomeServer.main: " + re);
}
}
// This method starts a RMI registry on the local host, if it
// does not already exist at the specified port number.
private static void startRegistry(int rmiPortNum) throws RemoteException{
try {
Registry registry = LocateRegistry.getRegistry(rmiPortNum);
registry.list( );
// The above call will throw an exception
// if the registry does not already exist
} catch (RemoteException ex) {
// No valid registry at that port.
System.out.println("RMI registry is not located at port " + rmiPortNum);
Registry registry = LocateRegistry.createRegistry(rmiPortNum);
System.out.println("RMI registry created at port " + rmiPortNum);
}
}
}
Implement the client:
import java.io.*;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class SomeClient {
public static void main(String args[]) {
try {
String hostName;
String portNum = "1234";
String registryURL = "rmi://localhost:" + portNum + "/some";
SomeInterface h = (SomeInterface)Naming.lookup(registryURL);
// invoke the remote method(s)
String message = h.someMethod1();
System.out.println(message);
int i = h.someMethod2(12344);
System.out.println(i);
SomeStruct someStructOut = new SomeStruct(10, 100.0F);
SomeStruct someStructIn = new SomeStruct(0, 0.0F);
someStructIn = h.someStructTest(someStructOut);
System.out.println( someStructIn.getInt() );
System.out.println( someStructIn.getFloat() );
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
A larger client-server application should be divided into three modules:client, server, and common (for classes shared between the server and client code, i.e. the remote interface and the non-primitive object in this example). The client application will then be created from client + common modules on the classpath and the server from server + common modules on the classpath.
I used this example many years ago to learn basics of RMI and it still works. However it is far from being perfect (default Java package used, incorrect exception handling, hostname and port parameters are hard-coded and not configurable, etc.)
Nevertheless, it is good for starters. All the files can be placed in one directory and compiled using the simple javac *.java command. The server application can then be started using the java SomeServer and the client one by launching the java SomeClient command.
I hope this helps to understand the Java RMI which is, in fact, far more complicated than just this.
You shouldn't be generating stubs (if you are following a tutorial, it is way old). you can run the client without necessarily having the jars locally (using remote classloading), but it's way easier to do it this with the jars available locally (i've personally done a fair bit of RMI and never actually deployed a system with remote classloading). typically, you want 2 jars, a "client" jar with just the remote interfaces (and any Serializable classes used by those interfaces) and a "server" jar which includes the implementation classes. you would then run the server with the server jar, and the rmiregistry/client with the client jars.
This is a pretty good (up to date and simple) getting started guide.
To say it in short what the other answers elaborated:
The client needs only the common interfaces (and the client classes), not the server implementation.
The server needs interfaces and implementation (and your server main class).
The rmiregistry needs only the interfaces.
(Actually, you can start your own registry inside the server process - then you don't need the rmiregistry at all. Have a look at the createRegistry methods in the java.rmi.registry.LocateRegistry class.)
"Interfaces" here means both the remote interfaces and any (serializable) classes used by these as parameter or argument types.
How you distribute these classes to jar files is independent of this.
EDIT: removed reference to C# as the only accepted answer is about Java. If someone needs information about websocket server implementation in C#, ask a new question.
Do you know "production ready" framework for creating WebSockets Server in Java? I found one library http://nugget.codeplex.com/ but i did not know how it is stable and fast.
The accepted answer is 3 years old, with the recent release of JEE7, now every Web Containers that implement servert 3.1 will support websocket via standard API (javax.websocket) package.
The following code show example how to implement websocket using JEE7:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/chat")
public class ChatServer {
private static final Logger LOGGER =
Logger.getLogger(ChatServer.class.getName());
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
}
#OnMessage
public String onMessage(String message, Session session) {
LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
new Object[] {session.getId(), message});
return "Server received [" + message + "]";
}
#OnClose
public void onClose(Session session) {
LOGGER.log(Level.INFO, "Close connection for client: {0}",
session.getId());
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
}
Example in details here.
Web Container that support Websocket:
Tomcat 8
WildFly (Previously Jboss AS)
Glassfish 4.0
and much more
For Java, check out this informative post. Copy-paste from there:
Jetty WebSocket Server – Jetty has supported WebSockets since last September. This seems to be a good option.
Caucho Resin
jWebSocket
GlassFish/Grizzly (see a DZone posting on it here)
JBoss Netty (see patch here)
Webbit
Out of these options, I guess Jetty and Resin are the most mature and stable. However, always good to do your own testing.
The Vert.x option is also worth considering.
Creating a ws server can be as simple as
vertx.websocketHandler(new Handler<ServerWebSocket>() {
public void handle(ServerWebSocket ws) {
// A WebSocket has connected!
}
}).listen(8080);
or
vertx.createHttpServer().websocketHandler(new Handler<ServerWebSocket>() {
#Override
public void handle(final ServerWebSocket ws) {
logger.info("ws connection established with " + ws.remoteAddress());
ws.dataHandler(new Handler<Buffer>() {
#Override
public void handle(Buffer data) {
JsonObject item = new JsonObject(data.toString());
logger.info("data in -> " + item.encodePrettily());
// if you want to write something back in response to the client
//ws.writeTextFrame(...);
}
});
}
}).listen(port, new Handler<AsyncResult<HttpServer>>() {
#Override
public void handle(AsyncResult<HttpServer> event) {
logger.info("ws server is up and listening on port " + port);
}
});
For more details look here http://vertx.io/docs/vertx-core/java/#_websockets
So one can write his own WebSocket server with Vert.x, package it as FatJar, and run it on its own.
Or you can embed Vert.x env. in your app, and deploy your verticle (that implements the ws server) programmatically.
Another alternative is JBoss's web server Undertow. Which is easily embeddable in applications.
Add these dependencies:
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${version.io.undertow}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>${version.io.undertow}</version>
</dependency>
And here's a sample ws server:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(path()
.addPrefixPath("/myapp", websocket(new WebSocketConnectionCallback() {
#Override
public void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) {
channel.getReceiveSetter().set(new AbstractReceiveListener() {
#Override
protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
final String messageData = message.getData();
for (WebSocketChannel session : channel.getPeerConnections()) {
WebSockets.sendText(messageData, session, null);
}
}
});
channel.resumeReceives();
}
}))
.build();
server.start();
Take a look at the Bristleback Framework. It is a high level overlay for commonly used Java Websocket Servers, like Jetty, Netty or Tomcat. If you like Spring Framework, you must definitely try Bristleback!
Disclaimer: I'm a contributor in Bristleback Framework project.
Apache Tomcat 8.0 implements WebSockets 1.1 API (JSR-356). You can even play with examples after installing by navigating to examples folder: there are echo chat and snake game.
JETTY
I've spent the past week mauling over how to make a WebSocket server. Finally got something to work hope this helps. It uses libraries from Jetty (jars).
File WebRTC_IceServer.java
package com.evanstools;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.websocket.server.*;
public class WebRTC_IceServer{
public static void main(String[] args){
try{
////////////////////////
if(args.length == 0){
System.out.printf("%s%n","WebRTC_IceServer [port]");
return;
}
Server server = new Server(Integer.parseInt(args[0]));
WebSocketHandler.Simple webSocketHandlerSimple = new WebSocketHandler.Simple(WebsocketPOJO.class);
server.setHandler(webSocketHandlerSimple);
server.start();
server.join();
////////////////////////
}catch(Exception w){w.printStackTrace();}
}
}
File WebsocketPOJO.java
package com.evanstools;
import org.eclipse.jetty.websocket.api.annotations.*;
import org.eclipse.jetty.websocket.api.Session;
//The class must be not abstract and public.
#WebSocket
public class WebsocketPOJO{
//Flags one method in the class as receiving the On Connect event.
//Method must be public, not abstract, return void, and have a single Session parameter.
#OnWebSocketConnect
public void onWebSocketConnect(Session session){
System.out.printf("%s%n","test client connected");
}
//Flags one method in the class as receiving the On Close event.
//Method signature must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
////int closeCode (required)
////String closeReason (required)
#OnWebSocketClose
public void OnWebSocketClose(Session session,int closeCode,String closeReason){}
//Flags up to 2 methods in the class as receiving On Message events.
//You can have 1 method for TEXT messages, and 1 method for BINARY messages.
//Method signature must be public, not abstract, and return void.
//The method parameters for Text messages:
////Session (optional)
////String text (required)
//The method parameters for Binary messages:
////Session (optional)
////byte buf[] (required)
////int offset (required)
////int length (required)
#OnWebSocketMessage
public void onWebSocketMessageString(Session session, String text){}
//Flags one method in the class as receiving Error events from the WebSocket implementation.
//Method signatures must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
////Throwable cause (required)
//#OnWebSocketError
//Flags one method in the class as receiving Frame events from the WebSocket implementation after they have been processed by any extensions declared during the Upgrade handshake.
//Method signatures must be public, not abstract, and return void.
//The method parameters:
////Session (optional)
///Frame (required)
//The Frame received will be notified on this method, then be processed by Jetty, possibly resulting in another event, such as On Close, or On Message. Changes to the Frame will not be seen by Jetty.
//#OnWebSocketFrame
}