Following Jetty documentation and answer to this question creation of websocket client is as simple as
WebSocketClient client = new WebSocketClient();
SimpleEchoSocket socket = new SimpleEchoSocket();
try {
client.start();
URI echoUri = new URI(destUri);
ClientUpgradeRequest request = new ClientUpgradeRequest();
client.connect(socket, echoUri, request);
System.out.printf("Connecting to : %s%n", echoUri);
socket.awaitClose(5, TimeUnit.SECONDS);
}
But I can't find SimpleEchoSocket! I try several versions of org.eclipse.jetty.websocket:websocket-client but had no success. Looks like documentation is outdated, but maybe I am doing something wrong? How can I use this example from Jetty doc?
SimpleEchoSocket is your socket implementation.
In other words, its your code, your class.
Something that implements the on open, on close, on message logic in the ways that the same documentation explains.
You have a few choices here, it can be jetty api specific, or jsr-356 (aka javax.websocket) specific.
Then you choose between a traditional class that implements an interface, or one that is marked up with annotations.
Related
I've been trying to connect to the XTB API and I can't seem to make it work.
I have zero experience with sockets and I'm learning on the go. I'm trying to send the JSON object and I'm expecting some kind of response either a success message or an error but I don't get anything. I don't even know if I'm doing it right.
public static void main(String[] args) {
String host = "xapi.xtb.com";
int port = 5112;
Socket s;
try {
JSONObject main = new JSONObject();
JSONObject user = new JSONObject();
main.put("command", "login");
user.put("userId", "MY_ID");
user.put("password", "MY_PSSWD");
main.put("arguments", user);
s = new Socket(host, port);
SocketAddress a;
a = new InetSocketAddress("xapi.xtb.com", 5112);
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
out.write(main.toString());
String response = in.readLine();
System.out.println(response);
in.close();
out.close();
} catch (IOException ex) {
ex.printStackTrace(System.out);
}
}
I only managed to get their WebSocket endpoints to work. That, in addition to the fact that their entire API documentation contains WebSocket commands only, makes me think they expect users to connect that way.
I can't help you with Java, but the algorithm is as follows:
1. Define connection
Get a WebSocket client library / package. Usually first thing you do is to instantiate an object using the wss://... address as parameter. Don't issue the connect command at this stage.
2. Define event handlers
Most WebSocket clients dispatch events which you need to handle in your code.
First event will typically be 'open' and it will be fired once the connection is established. Every message coming from server will fire a 'message' event. You need to write handlers for the 'onOpen' and 'onMessage' events (however the naming convention may be) which will execute your code's logic.
Typically there will be a 'send' command in your WebSocket package that you can use to send messages to the server. Use the command described in the documentation as payload of the send command:
// pseudocode
ws.send({
"command":"login",
"arguments": {
"userId":"1000",
"password":"PASSWORD"
}
})
3. Connect
Once the event handlers are defined, you can issue the 'connect' command.
Good luck with your trading. Hope it helps.
maybe im very, very, very too late but... I have been playing with your example.
You are getting null, because the connection is plain http.
To fix it, you need to change:
import java.net.Socket;
to
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
And then, when creating the socket...
instead of
Socket s
s = new Socket(host, port);
You must put this:
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket s = (SSLSocket) factory.createSocket(host, port);
Also, after out.write.... add
out.flush();
And you are done
Why? in the xtb api docs they said this:
All servers use SSL connection.
And after messing a bit with wireshark, I found that the JSON was sent in plain text...
You may have already found it before, because this question is old, but it remains here in case someone else has the problem
Currently I'm replacing existing org.apache.http.* http client library with JDK-11's new Http library. There are many exciting new features, however I've not found anything on "how to set RetryRequestHandler in new HTTPClient". Code snippet of previous Apache HttpClient builder:
...
...
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setConnectionManager(connectionManager)
if(retryCount > 0) {
httpClientBuilder.setRetryHandler(new RetryRequestHandler(retryCount, url));
}
if (proxyHost) {
HttpHost proxy = new HttpHost(proxyHost, proxyPort, "http");
httpClientBuilder.setProxy(proxy);
}
...
...
Here RetryRequestHandler is an extension of DefaultHttpRequestRetryHandler
public class RetryRequestHandler extends DefaultHttpRequestRetryHandler{...}
There is no option to set retry in java-11's new HttpClient. Is there any workaround to do so?
Spring has broken retry out of Spring Batch into a separate, standalone library that you can use (albeit inside a Spring project). It will allow you to add a retry policy to a method calling the new HTTP client. See docs below:
https://github.com/spring-projects/spring-retry
That's the closest thing I know for this situation. If you want to roll your own, you could also accomplish the same thing with aspects. I think the Spring library is cleaner because you can let the library handle the details of retry. They also have a powerful set of APIs for different retry policies, including exponential backoff, etc.
The java.net.http HttpClient will retry idempotent requests (GET/HEAD) once by default. This is typically useful on HTTP/1.1 long live connections where the server side might arbitrarily decide that the connection has remained idle for too long, and closes it at the same time that the client takes it out of the pool and starts sending a new request.
I've learned how to send and handle Rest API requests, so am reasonably comfortable with how an outside user would submit requests to an API through methods such as opening a connection to the API, setting a request method and processing returned messages.
However the time has come to create my own Rest Web Service, and I'm a bit stuck as I'm not entirely familiar with just how the server will handle the communication.
I can set up a connection just fine to allow for communication, but I'm not particularly comfortable with the specifics of a connection.
Below is the method where I initialise the server, which will then wait until something connects and have a brief conversation until the client disconnects.
public void Initialise(){
try {
ServerSocket s = new ServerSocket(21); //TODO: Change port?
while(true){
Socket incoming = s.accept();
Runnable r = new ConnectionManager(incoming);
Thread t = new Thread(r);
t.start();
}
}
catch(IOException e){
e.printStackTrace();
}
}
And the class handling the connection.
public class ConnectionManager implements Runnable{
private Socket incoming;
public ConnectionManager(Socket i){
this.incoming = i;
}
#Override
public void run() {
try{
try{
//Initialise IOStreams
InputStream inStream = incoming.getInputStream();
OutputStream outStream = incoming.getOutputStream();
Scanner in = new Scanner(inStream);
PrintWriter out = new PrintWriter(outStream, true);
out.println("TODO: Change this message. Press Q to quit.");
boolean done = false;
while (!done && in.hasNextLine()){
String line = in.nextLine();
out.println("Echo: " +line);
if (line.trim().equals("Q")){
done = true;
}
}
}
finally{
incoming.close();
}
}
catch (IOException e){
e.printStackTrace();
}
}
}
What I'm not sure of how to do, is how I start building an application that listens for Rest requests, and then processes them accordingly. I feel confident that upon examining the connection, I'd be able to engineer functionality to process the API request, however I do not know how to view the specifics of a Rest request sent by a user.
For example, if a user were to send a request, such as
GET exampleAPI/endpoint?params
How do I examine the request, and then subsequently process it accordingly?
For example, on the client side when you initiate the request, an approach such as the use of HttpURLConnection would allow you to follow the process of
HttpURLConnection c = (HttpURLConnection) targetURL.openConnection();
c.setRequestMethod("GET");
Which would allow you to submit a Get request to the target URI.
Looking through the Java Documentation for Socket, I don't quite know how I can view incoming requests and active connections.
Am I missing something, or just doing things completely wrong?
As I mentioned in my comments, you can use Jersey/Spring/etc.. for this rather than you rewriting the logic for the whole server and handling multiple threads, etc..
Also, you should know that there is a JDK API called JAX-RS (specification plus implementation) for the same. you can look here
You can look here for Spring REST Controller or here for Jersey.
I recommend you go through JDK JAX-RS API first, then you may have a look at Spring and Jersey.
There are other vendors implementing JAX-RS, which you may be interested in, you can look here for comparison for JAX-RS implementations.
P.S.: You should also know that Spring does not compliant to JAX-RS API, rather they have got their own API.
I have a Jersey client up and running, using the Apache Client 4 library, like this:
private Client createClient() {
ApacheHttpClient4Config cc = new DefaultApacheHttpClient4Config();
// boring stuff here
return ApacheHttpClient4.create(cc);
}
But this by default uses a BasicClientConnManager, which doesn't allow multi-threaded connections.
The ApacheHttpClient4Config Javadoc says that I need to set the PROPERTY_CONNECTION_MANAGER to a ThreadSafeClientConnManager instance if I want multi-threaded operation. I can do this, and it works OK:
private Client createClient() {
ApacheHttpClient4Config cc = new DefaultApacheHttpClient4Config();
cc.getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER,
new ThreadSafeClientConnManager());
// boring stuff here
return ApacheHttpClient4.create(cc);
}
But ThreadSafeClientConnManager is deprecated. This is annoying.
The more modern version is PoolingHttpClientConnectionManager. Unfortunately, though, the ApacheHttpClient4.create() method requires the connection manager to be an implementation of ClientConnectionManager (itself deprecated), and PoolingHttpClientConnectionManager doesn't implement that interface. So if I try to use it, my connection manager gets ignored and we're back to a BasicClientConnManager.
How can I end up with a thread-safe client without using anything that's deprecated?
You can create the client as follows (see https://github.com/phillbarber/connection-leak-test/blob/master/src/test/java/com/github/phillbarber/connectionleak/IntegrationTestThatExaminesConnectionPoolBeforeAndAfterRun.java#L30-L33):
client = new ApacheHttpClient4(new ApacheHttpClient4Handler(HttpClients.custom()
.setConnectionManager(new PoolingHttpClientConnectionManager())
.build(), null, false));
I'm pretty puzzled with this issue. I have an Apache Thrift 0.9.0 client and server. The client code goes like this:
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(this.transport);
this.client = new ZKProtoService.Client(protocol);
This works fine. However, if I try to wrap the transport in a TFramedTransport
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(new TFramedTransport(this.transport));
this.client = new ZKProtoService.Client(protocol);
I get the following obscure (no explanation message whatsoever) exception in the client side. Server side shows no error.
org.apache.thrift.transport.TTransportException
at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.transport.TFramedTransport.readFrame(TFramedTransport.java:129)
at org.apache.thrift.transport.TFramedTransport.read(TFramedTransport.java:101)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:378)
at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:297)
at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:204)
at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:69)
at com.blablabla.android.core.device.proto.ProtoService$Client.recv_open(ProtoService.java:108)
at com.blablabla.android.core.device.proto.ProtoService$Client.open(ProtoService.java:95)
at com.blablabla.simpleprotoclient.proto.ProtoClient.initializeCommunication(ProtoClient.java:411)
at com.blablabla.simpleprotoclient.proto.ProtoClient.doWork(ProtoClient.java:269)
at com.blablabla.simpleprotoclient.proto.ProtoClient.run(ProtoClient.java:499)
at java.lang.Thread.run(Thread.java:724)
It also fails if I use TCompactProtocol instead of TBinaryProtocol.
In the server side I have extended TProcessor with my own class since I need to reuse existing service handler (the service server-side IFace implementation) for this client:
#Override
public boolean process(final TProtocol in, final TProtocol out)
throws TException {
final TTransport t = in.getTransport();
final TSocket socket = (TSocket) t;
socket.setTimeout(ProtoServer.SOCKET_TIMEOUT);
final String clientAddress = socket.getSocket().getInetAddress()
.getHostAddress();
final int clientPort = socket.getSocket().getPort();
final String clientRemote = clientAddress + ":" + clientPort;
ProtoService.Processor<ProtoServiceHandler> processor = PROCESSORS
.get(clientRemote);
if (processor == null) {
final ProtoServiceHandler handler = new ProtoServiceHandler(
clientRemote);
processor = new ProtoService.Processor<ProtoServiceHandler>(
handler);
PROCESSORS.put(clientRemote, processor);
HANDLERS.put(clientRemote, handler);
ProtoClientConnectionChecker.addNewConnection(clientRemote,
socket);
}
return processor.process(in, out);
}
And this is how I start the server side:
TServerTransport serverTransport = new TServerSocket(DEFAULT_CONTROL_PORT);
TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
serverTransport).processor(new ControlProcessor()));
Thread thControlServer = new Thread(new StartServer("Control", server));
thControlServer.start();
I have some questions:
Is it correct to reuse service handler instances or I shouldn't be doing this?
Why does it fail when I use TFramedTransport or TCompactProtocol? How to fix this?
Any help on this issue is welcome. Thanks in advance!
I was having the same problem and finally found the answer. It is possible to set the transport type on the server, though this is not clear from most tutorials and examples I've found on the web. Have a look at all of the methods of the TServer.Args class (or the args classes for other servers, which extend TServer.Args). There are methods inputTransportFactory and outputTransportFactory. You can use new TFramedTransport.Factory() as inputs to each of these methods to declare which transport the server should use. In scala:
val handler = new ServiceStatusHandler
val processor = new ServiceStatus.Processor(handler)
val serverTransport = new TServerSocket(9090)
val args = new TServer.Args(serverTransport)
.processor(processor)
.inputTransportFactory(new TFramedTransport.Factory)
.outputTransportFactory(new TFramedTransport.Factory)
val server = new TSimpleServer(args)
println("Starting the simple server...")
server.serve()
Note that if you are using a TAsyncClient, you have no choice about the transport that you use. You must use TNonblockingTransport, which has only one standard implementation, TNonblockingSocket, which internally wraps whatever protocol you are using in a framed transport. It doesn't actually wrap your chosen protocol in a TFramedTransport, but it does prepend the length of the frame to the content that it writes, and expects the server to prepend the length of the response as well. This wasn't documented anywhere I found, but if you look at the source code and experiment with different combinations, you will find that with TSimpleServer you must use TFramedTransport to get it to work with an async client.
By the way, it's also worth noting that the docs say that a TNonblockingServer must use TFramedTransport in the outermost later of the transport. However, the examples don't show this being set in TNonblockingServer.Args, yet you still find that you must use TFramedTransport on the client side to successfully execute an rpc on the server. This is because TNonblockingServer.Args has its input and output protocols set to TFramedTransport by default (you can see this using reflection to inspect the fields of the superclass hierarchy or in the source code for the constructor of AbstractNonblockingServerArgs -- you can override the input and output transports, but the server will likely fail for the reasons discussed in the documentation).
When the issue happens with framed, but it works without framed, then you have an incompatible protocol stack on both ends. Choose one of the following:
either modify the server code to use framed as well
or do not use framed on the client
A good rule of thumb is, to always use the exact same protocol/transport stack on both ends. In the particular case it blows up, because framed adds a four-byte header holding the size of the message that follows. If the server does not use framed, these additional four bytes sent by the client will be interpreted (wrongly) as part of the message.
Altough the sample code in that answer
TNonblockingServer in thrift crashes when TFramedTransport opens is for C++, adding framed on the server should be very similar with Java.
PS: Yes, it is perfectly ok to re-use your handler. A typical handler is a stateless thing.