I am required to make a client-server application as my project submission for university finals.
I have figured out how I would be writing the server but I am kinda confused with this situation I am facing.
So the server is said to support only one defined protocol (represented by a Protocol interface) and would serve to the clients that speaks using that rule only. To test the functionality of the server, I have wrote an implementation that supports the HTTP Protocol so that I can quickly test the server from browser, but there is one thing that is really confusing me.
I have defined the server as:
public interface Server {
// Methods...
public void start() throws Exception;
public Protocol getProtocol();
}
The base implementation of server does this:
public class StandardServer implements Server {
/* Implementations */
public synchronized final void start() throws Exception {
try {
while (true) {
Socket socket = serverSocket.accept();
// Use the protocol to handle the request
getProtocol().handshake(socket);
}
} catch (IOException ex) {
logger.error(ex);
}
}
}
I am confused that is it really required to do this, as I am certain that there are better ways to do this.
What I have considered so far is:
Synchronize the getProtocol() method.
Make the implementation of Protocol a thread and then use it to handle requests.
Spawn a thread when the client connects and pass-in the protocol object to that thread.
What would be the good ways to do this, considering that the server would be getting a decent amount of requests per second?
Any source code help/reference would be highly appreciated.
P.S:
I am not implementing an HTTP Server.
There would be multiple implementations of Server
Related
I'm building a TCP Server using Netty.
Is there any way to persist the connected client's session data while its channel exists?
for example, when a client connect to the server, I need to create its class instance and reuse in different ways when he send messages.
something like the code below:
// this is called when the client connect to the server
public void channelActive(final ChannelHandlerContext ctx) {
ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
new GenericFutureListener<Future<Channel>>() {
public void operationComplete(Future<Channel> future) throws Exception {
// I need to create the class instance when the
// client connects to the server
ClientData clientData = new ClientData(ctx.channel());
channels.add(ctx.channel());
}
}
);
}
// this is called when the server receives a message from the connected client
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
if("update".equals(msg)){
// then I need the retrieve the data created
// in the ChannelActive method.
clientData().update();
}
}
While browsing for solutions, I found a few examples where the developer used a cache service (like memcache or redis) to store and retrieve the data related to the connected client.
But I wish to solve this without depending on a external process.
Is there any way to achieve this? Any advice on the subject would be appreciated.
Thank you
You should use AttributeMap.attr(AttributeKey key), which is inherited by ChannelHandlerContext:
Storing stateful information
AttributeMap.attr(AttributeKey) allow you to store and access stateful information that is related with a handler and its context. Please refer to ChannelHandler to learn various recommended ways to manage stateful information. [1]
[1][http://netty.io/4.0/api/io/netty/channel/ChannelHandlerContext.html]
I am using dynamodb from amazon web services as my database. The client providd by AWS uses http to make the requests to the database. This code will be on a server which will accept requests from users and send it over to dynamodb. I had a few questions how to design this then.
Since this is a server accepting many requests I am using the async client http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/AmazonDynamoDBAsyncClient.html instead of the sync because I don't want for every request to block and instead I will wait for a future to return (better performance). Is it best to make this client static?
public class Connection {
AmazonDynamoDBAsyncClient client;
static DynamoDB dynamoDB;
public Connection(){
client = new AmazonDynamoDBAsyncClient(new ProfileCredentialsProvider());
dynamoDB = null;
}
public void setConnection(String endpoint){
client.setEndpoint(endpoint);
dynamoDB = new DynamoDB(client);
}
public DynamoDB getConnection(){
return dynamoDB;
}
}
Then to call this static variable from main:
public class Main{
Connection c;
DynamoDB con;
public Main() throws Exception {
try {
c = new Connection();
c.setConnection("http://dynamodbserver:8000");
con = c.getConnection();
//Do stuff with the connection now
} catch (Exception e) {
System.err.println("Program failed:");
System.err.println(e.getMessage());
}
Is this a good approach? What will happen if two users are requesting to use the static variable at the same time (I am using a framework called vertx so this program will run on a single thread, but there will be multiple instances of this program)?
You should not set the connection as static member, Also the way you are setting endpoints of your connection is:
not thread safe
may lead to race condition
Endpoints should be setup at the time of AmazonDynamoDBAsyncClient
construction and then this Async client should be used in the DynamoDB
construction. Please also refer to the documentation.
Why don't you use the SDK provided with AWS for dynamoDb? It will take care of connection management for you in a thread safe manner.
On a side note, If you still want to roll out your own solution for connection management, I would recommend that you use a Dependecy Injection framework. I would highly recommend google-guice.
Here is the sample code of DI through guice.
public class DynamoDBProvider implements Provider<DynamoDB> {
// Notice that endpoint is set at the time of client construction and the
// get() method provides an instance of DynamoDb.
// In another configuration class, we define that DynamoDb will be
// served under singleton scope, so you will have a single instance.
private final AmazonDynamoDBAsyncClient asyncClient;
#Inject
public DatabaseTransactionLogProvider(
ProfileCredentialsProvider creds,
#Named("Endpoint") String endpoint) {
this.asyncClient = new AmazonDynamoDBAsyncClient(creds);
// endpoint is a configuration so it must also be injected to the provider.
this.setEndpoint(endPoint);
}
public DynamoDb get() {
return new DynamoDB(asyncClient);
}
}
This is how you ensure your connection instance is served as singleton.
public class DynamoDBModule extends AbstractModule {
protected void configure() {
bind(Dynamodb.class).toProvider(DynamoDbProvider.class).in(Singleton.class);
}
}
Learning DI through guice or any other framework will require some
effort but it will go a a long way in making your code maintainable
and unit testable. Please be aware to utilize the benefits of DI, you
will have to refactor your project so that all depedencies are
injected.
static would be good since it is shared by all connection instance. but you can further improve the code by introducing singleton design pattern for connection class so that only one connection instance will be created and used for serve all the requests.
I'm developing a server based on the Netty libraby and I'm having a problem with how to structure the application with regards to business Logic.
currenty I have the business logic in the last handler and that's where I access the database. The thing I can't wrap my head around is the latency of accessing the database(blocking code). Is it advisable to do it in the handler or is there an alternative? code below:
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
super.channelRead(ctx, msg);
Msg message = (Msg)msg;
switch(message.messageType){
case MType.SIGN_UP:
userReg.signUp(message.user);// blocking database access
break;
}
}
you should execute the blocking calls in DefaultEventExecutorGroup or your custom threadpool that can be added to when the handler is added
pipeline.addLast(new DefaultEventExecutorGroup(50),"BUSSINESS_LOGIC_HANDLER", new BHandler());
ctx.executor().execute(new Runnable() {
#Override
public void run() {
//Blocking call
}});
Your custom handler is initialized by Netty everytime the Server receives a request, hence one instance of the handler is responsible for handling one Client.
So, it is perfectly fine for issuing blocking calls in your handler. It will not affect other Client's, as long as you don't block it indefinitely (or atleast not for very long time), thereby not blocking Netty's Thread for long and you do not get too much load on your server instance.
However, if you want to go for asynchronous design, then there can be more than a few design patterns that you can use.
For eg. with Netty, if you can implement WebSockets, then perhaps you can make the blocking calls in a separate Thread, and when the results are available, you can push them to the client through the WebSocket already established.
The question might seem stupid/trivial and might be, but I simply cannot understand how to achieve my goal. (Sorry if the title is misguiding, couldn't think of a better one)
I have a webpage on a App Engine server which uses GWT. I got client code and server code. The client code can call RPC methods without any problem (my problem has nothing to do with the "gwt-client" at all).
I got the following classes:
//MyClassService.java - client package
#RemoteServiceRelativePath("myService")
public interface MyClassService extends RemoteService{
public doSomething();
}
//MyClassServiceAsync.java - client package
public interface MyClassServiceAsync{
public void doSomething(AsyncCallback<Void> callback);
}
//MyClassServiceImpl.java - server package
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
#Override
public void doSomething()
{
//does something
}
}
A scenario and what I want to do:
I've got a remote client, in other words, a client who's not connecting through the page via the "GWT-interface", it's a client who's simply making GET, POST requests to a path on the server (from elsewhere). This remote client is not "using" GWT at all. The client is connecting through an HttpServlet, inside this servlet I want to reuse the RPC mechanics so that i don't have to rewrite the interfaces, who are on the client side and using client-dependent code (the implementation is already server-side).
To reuse the existing methods on the server-side I could create an instance of MyClassServiceImpl.java and just use those. BUT as you can see above, they are implemented as synchronous methods, since GWT-RPC automatically makes the calls asyncronous when using the GWT-RPC.
How would i go about to reuse the MyClassServiceImpl on the server-side and also get them as asynchronous?
Also if I'm wrong with the approach I'm taking, please suggest some other solution. For example, one solution might be for the remote client to directly communicate with the RemoteServiceServlet instead of creating a HttpServlet which the client connects through, but I don't know if that's possible (and if it is, please tell me how)!
Thank you!
EDIT (thanks to some answers below I got some insight and will try to improve my question):
The server-side implementation of the methods is SYNCHRONOUS. Meaning they will block until results a returned. When invoking these method from the gwt-client code, they are 'automatically' made ASYNCHRONOUS one can call them by doing the following:
MyClassServiceAsync = (MyClassServiceAsync) GWT.create(MyClassService.class);
ServiceDefTarget serviceDef = (ServiceDefTarget) service;
serviceDef.setServiceEntryPoint(GWT.getModuleBaseURL() + "myService");
service.doSomething(new AsyncCallback<Void>() {
#Override
public void onSuccess(Void result) {
//do something when we know server has finished doing stuff
}
#Override
public void onFailure(Throwable caught) {
}
});
As you can see from the above code, there is support for the doSomething method to take an AsyncCallback, without even having the implementation for it. This is what I wanted on the server-side so i didn't have to use threads or create a new implementation for "async-usage". Sorry if I was unclear!
1) Any client can call MyClassServiceImpl.doSomething() with the current configuration. MyClassServiceImpl is a servlet and properly exposed. In order to achieve communication this way, the client must be able to "speak" the GWT dialect for data transportation. Google may provide you with libraries implementing this. I haven't used any, so I cannot make suggestions.
An example, proof-of-concept setup: Check the network communications with Firebug to get an idea of what is going on. Then try calling the service with curl.
2) If you do not want to use the GWT dialect, you can easily expose the same service as REST (JSON) or web services (SOAP). There are plenty of libraries, e.g. for the REST case RestEasy and Jersey. You do not mention any server-side frameworks (Spring? Guice? CDI?), so the example will be simplistic.
I'd suggest implementing your business method in a class independent of transportation method:
public class MyBusinessLogic {
public void doSomething() {
...
}
}
Then, the transport implementations use this business logic class, adding only transport-specific stuff (e.g. annotations):
GWT:
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
#Override
public void doSomething() {
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
JAX-RS:
#Path("myService")
public class MyResource {
#GET
public void doSomething() {
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
So the transport endpoints are just shells for the real functionality, implemented in one place, the class MyBusinessLogic.
Is this a real example? Your method takes no arguments and returns no data.
Anyhow you can create a new servlet and invoke it via normal HTTP request. The servlet then just invokes the target method:
public class MyNewServlet extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response){
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
I would like to make a kind of logging proxy in netty. The goal is to be able to have a web browser make HTTP requests to a netty server, have them be passed on to a back-end web server, but also be able to take certain actions based on HTTP specific things.
There's a couple of useful netty exmaples, HexDumpProxy (which does the proxying part, agnostic to the protocol), and I've taken just a bit of code from HttpSnoopServerHandler.
My code looks like this right now:
HexDumpProxyInboundHandler can be found at http://docs.jboss.org/netty/3.2/xref/org/jboss/netty/example/proxy/HexDumpProxyInboundHandler.html
//in HexDumpProxyPipelineFactory
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline p = pipeline(); // Note the static import.
p.addLast("handler", new HexDumpProxyInboundHandler(cf, remoteHost, remotePort));
p.addLast("decoder", new HttpRequestDecoder());
p.addLast("handler2", new HttpSnoopServerHandler());
return p;
}
//HttpSnoopServerHandler
public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
HttpRequest request = (HttpRequest) e.getMessage();
System.out.println(request.getUri());
//going to do things based on the URI
}
}
Unfortunately messageReceived in HttpSnoopServerHandler never gets called - it seems like HexDumpProxyInboundHandler consumes all the events.
How can I have two handlers, where one of them requires a decoder but the other doesn't (I'd rather have HexDumpProxy as it is, where it doesn't need to understand HTTP, it just proxies all connections, but my HttpSnoopHandler needs to have HttpRequestDecoder in front of it)?
I've not tried it but you could extend HexDumpProxyInboundHandler and override messageReceived with something like
super.messageReceived(ctx, e);
ctx.sendUpstream(e);
Alternatively you could modify HexDumpProxyInboundHandler directly to that the last thing messageReceived does is call super.messageReceived(ctx,e).
This would only work for inbound data from the client. Data from the service you're proxy-ing would still be passed through without you code seeing it.