Java AIO concurrent blocking - aio

If the channel is not closed, there will be a blocking problem, but the link cannot be reused by closing
test
C:\Users\hxm>ab -k -c100 -n1000 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
apr_pollset_poll: The timeout specified has expired (70007)
Total of 100 requests completed

source
public class HSocket implements Runnable {
private Integer port = 8080;
private static final Logger LOGGER = Logger.getLogger(HSocket.class.getName());
private AsynchronousServerSocketChannel ssc;
private CountDownLatch countDownLatch = new CountDownLatch(1);
public void run() {
try {
AsynchronousChannelGroup cg = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(8));
ssc = AsynchronousServerSocketChannel.open(cg);
ssc.bind(new InetSocketAddress(port), 100);
ssc.accept(this, new CompletionHandler<AsynchronousSocketChannel, HSocket>() {
#Override
public void completed(AsynchronousSocketChannel channel, HSocket attachment) {
try {
ssc.accept(attachment, this);
} finally {
String body = generateErrorResponse("<h1>aaa</h1>");
channel.write(ByteBuffer.wrap(body.getBytes()));
}
}
#Override
public void failed(Throwable exc, HSocket attachment) {
ssc.accept(attachment, this);
}
});
LOGGER.log(Level.INFO, "server port " + port);
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
new Thread(new HSocket()).start();
}
private String generateErrorResponse(String message) {
return "HTTP/1.1 200 OK\r\n" +
"Content-type:text/html\r\n" +
"Connection:keep-alive\r\n" +
"Content-Length:" + message.length() + "\r\n" +
"\r\n" +
message;
}
}

Related

OKHttp DNS lookup asynchronously

public class OkHttpDns implements Dns {
#NotNull
#Override
public List<InetAddress> lookup(#NotNull String hostname) throws UnknownHostException {
MyLookUpUtility.getInstance.lookup(hostname, new MyLookUpUtility.lookupCallback()
{
#Override
public void onlookupResponseSuccess(JSONObject nslookupResponseJSON) {
Log.d("LookupResponse", nslookupResponseJSON.toString());
}
#Override
public void onlookupResponseFailure(String errCode) {
Log.d("LookupResponse", "Error Code : "+errCode);
}
});
}
}
In the above code, lookup method of DNS interface of OKHttp wants to return immediately. But my custom NSLookupUtility is an asynchronous call and I will have the ip address of the hostname only after a while. How to solve this problem? how to make the synchronous call to wait for the asynchronous call within it ?
Take a look at CompletableFuture. You’ll create an instance in lookup(), kickoff the async lookup, and then call future.get(). When your async call completes, call future.complete().
#Override
public List<InetAddress> lookup(#NotNull String hostName) throws UnknownHostException {
completableFuture = new CompletableFuture<>();
performLookUp(hostName);
try {
String ipAddress = completableFuture.get();
if (ipAddress != null) {
List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ipAddress));
return inetAddresses;
}
} catch (ExecutionException e) {
Log.d(TAG, "Error : ExecutionException : "+e );
e.printStackTrace();
} catch (InterruptedException e) {
Log.d(TAG, "Error : InterruptedException : "+e );
e.printStackTrace();
}
return Dns.SYSTEM.lookup(hostName);
}
private void performLookUp(#NotNull String hostName) {
MyUtiluty.getInstance().lookup(hostName,
new MyCallBack() {
#Override
public void onSuccess(String ip) {
completableFuture.complete(ip);
}
#Override
public void onFailure(String errCode) {
completableFuture.complete(null);
}
});
}

How to config tcp server to receive data from multiple client using spring boot?

I would like to configure TCP server to receive and reply data from multiple clients. I searched many other thread but could not found exact way to do. I'm using spring integration first time and have no experience.
Server requirement
should be able to receive and reply data to specific client (can have multiple client, each client should processed separately)
should be able to send data to client and wait for response for specific timeout.
Should be able to detect client is disconnect or not. if Client is disconnect then connection should be closed to save memory. (In earlier method without spring integration I was able to do it by ping client and see sending is failed or not but don't know how to do with spring integration)
I tried below code, In which I'm able to send data to client but could achieve my above requirements
TCP Server Configuration:
#Configuration
public class TcpServerConfig {
private List<TcpConnectionOpenEvent> clientList = new ArrayList<>();
public List<TcpConnectionOpenEvent> getClientList() {
return clientList;
}
#Bean
public TcpReceivingChannelAdapter server(TcpNetServerConnectionFactory cf) {
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
adapter.setConnectionFactory(cf);
adapter.setOutputChannel(inputChannel());
return adapter;
}
#Bean
public MessageChannel inputChannel() {
return new QueueChannel();
}
#Bean
public MessageChannel outputChannel() {
return new DirectChannel();
}
#Bean
public TcpNetServerConnectionFactory cf() {
return new TcpNetServerConnectionFactory(1001);
}
#Bean
public IntegrationFlow outbound() {
return IntegrationFlows.from(outputChannel())
.handle(sender())
.get();
}
#Bean
public MessageHandler sender() {
TcpSendingMessageHandler tcpSendingMessageHandler = new TcpSendingMessageHandler();
tcpSendingMessageHandler.setConnectionFactory(cf());
return tcpSendingMessageHandler;
}
#Bean
public ApplicationListener<TcpConnectionOpenEvent> listener() {
return new ApplicationListener<TcpConnectionOpenEvent>() {
#Override
public void onApplicationEvent(TcpConnectionOpenEvent event) {
outputChannel().send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, event.getConnectionId())
.build());
clientList.add(event);
}
};
}
}
Test Code:
#Service
public class Test {
private static final Logger LOGGER = LoggerFactory.getLogger(MessageServiceImpl.class);
#Autowired
TcpServerConfig tcpServerConfig;
#Autowired
private MessageChannel outputChannel;
#Autowired
private MessageChannel inputChannel;
#Scheduled(fixedRate = 1000)
void task() {
LOGGER.info("Client count: " + tcpServerConfig.getClientList().size());
for (TcpConnectionOpenEvent client : tcpServerConfig.getClientList()) {
outputChannel.send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, client.getConnectionId())
.build());
}
}
}
Any help would be appreciated.
Here is one solution:
#SpringBootApplication
#EnableScheduling
public class So62877512ServerApplication {
public static void main(String[] args) {
SpringApplication.run(So62877512ServerApplication.class, args);
}
#Bean
public IntegrationFlow serverIn(Handler handler) {
return IntegrationFlows.from(Tcp.inboundAdapter(server()))
.transform(Transformers.objectToString())
.filter(handler, "existingConnection", spec -> spec
.discardFlow(f -> f
.handle(handler, "sendInitialReply")))
.handle(handler, "reply")
.get();
}
#Bean
public IntegrationFlow serverOut() {
return f -> f.handle(Tcp.outboundAdapter(server()));
}
#Bean
public TcpServerConnectionFactorySpec server() {
return Tcp.netServer(1234)
.serializer(TcpCodecs.lf())
.deserializer(TcpCodecs.lf()); // compatible with netcat
}
}
#Component
#DependsOn("serverOut")
class Handler {
private static final Logger LOG = LoggerFactory.getLogger(Handler.class);
private final ConcurrentMap<String, BlockingQueue<Message<?>>> clients = new ConcurrentHashMap<>();
private final MessageChannel out;
private final TcpNetServerConnectionFactory server;
public Handler(#Qualifier("serverOut.input") MessageChannel out, TcpNetServerConnectionFactory server) {
this.out = out;
this.server = server;
}
public boolean existingConnection(Message<?> message) {
String connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class);
boolean containsKey = this.clients.containsKey(connectionId);
if (!containsKey) {
this.clients.put(connectionId, new LinkedBlockingQueue<Message<?>>());
}
return containsKey;
}
public void sendInitialReply(Message<String> message) {
LOG.info("Replying to " + message.getPayload());
this.out.send(MessageBuilder.withPayload(message.getPayload().toUpperCase())
.copyHeaders(message.getHeaders()).build());
}
#Scheduled(fixedDelay = 5000)
public void sender() {
this.clients.forEach((key, queue) -> {
try {
this.out.send(MessageBuilder.withPayload("foo")
.setHeader(IpHeaders.CONNECTION_ID, key).build());
Message<?> reply = queue.poll(10, TimeUnit.SECONDS);
if (reply == null) {
LOG.error("Timeout waiting for " + key);
this.server.closeConnection(key);
}
else {
LOG.info("Reply " + reply.getPayload() + " from " + key);
}
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("Interrupted");
}
catch (Exception e) {
LOG.error("Failed to send to " + key, e);
}
});
}
public void reply(Message<String> in) {
BlockingQueue<Message<?>> queue = this.clients.get(in.getHeaders().get(IpHeaders.CONNECTION_ID, String.class));
if (queue != null) {
queue.add(in);
}
}
#EventListener
public void closed(TcpConnectionCloseEvent event) {
this.clients.remove(event.getConnectionId());
LOG.info(event.getConnectionId() + " closed");
}
}
$ nc localhost 1234
foo <- typed
FOO
foo
bar <- typed
foo
bar <- typed
foo
$ <- closed by server - timeout
2020-07-14 14:41:04.906 INFO 64763 --- [pool-1-thread-2] com.example.demo.Handler : Replying to foo
2020-07-14 14:41:13.841 INFO 64763 --- [ scheduling-1] com.example.demo.Handler : Reply bar from localhost:65115:1234:a9fc7e3d-4dda-4627-b765-4f0bb0835153
2020-07-14 14:41:21.465 INFO 64763 --- [ scheduling-1] com.example.demo.Handler : Reply bar from localhost:65115:1234:a9fc7e3d-4dda-4627-b765-4f0bb0835153
2020-07-14 14:41:36.473 ERROR 64763 --- [ scheduling-1] com.example.demo.Handler : Timeout waiting for localhost:65115:1234:a9fc7e3d-4dda-4627-b765-4f0bb0835153
2020-07-14 14:41:36.474 INFO 64763 --- [ scheduling-1] com.example.demo.Handler : localhost:65115:1234:a9fc7e3d-4dda-4627-b765-4f0bb0835153 closed

Simple multithreaded socket server does not work (Socket is closed)

I have a really simple multithreaded server as attached.
When my client calls the server, the server gives below exception:
java.net.SocketException: Socket is closed
but my code did not close the socket.
The first code segment is my client. The second and third code segments define the server and the way it handles requests. I had another single-threaded client-server and it worked properly.
Could somebody help take a look?
public class SocketClient {
public static void main(String[] args) {
String hostname = "127.0.0.1";
int port = 900;
try{
Socket socket = new Socket(hostname, port);
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);
writer.println("GET /");
writer.println();
writer.flush();
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
public class SimpleHTTPServer {
public static void main(String[] args) throws Exception {
//create a network socket which can accept connection on certain TCP port
//create Server which can accept requests
final ServerSocket server = new ServerSocket(900);
System.out.println("Listening for connection on port 900...");
while(true) {
try (Socket socket = server.accept()) { //creates socket when new request is received
System.out.println("received request");
RequestHandler rh = new RequestHandler(socket); //RequestHandler implements runnable interface, pass this object to create Thread
Thread thread = new Thread(rh);
thread.start(); //begins run() method defined in rh
}
}
}
}
public class RequestHandler implements Runnable {
private Socket socket;
public RequestHandler(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
try {
System.out.println("calling handleRequest");
handleRequest();
} catch (Exception e) {
System.err.println(e);
try {
socket.close();
} catch (IOException e1) {
System.err.println("Error Closing socket connection");
System.exit(0);
}
}
}
private void handleRequest() throws Exception {
System.out.println("handleRequest called");
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
System.out.println("1st" + httpResponse);
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
System.out.println("2nd" + httpResponse);
System.out.println("got a new request");
}
}
I changed the server to below and it works-
public class SimpleHTTPServer {
public static void main(String[] args) throws Exception {
//create a network socket which can accept connection on certain TCP port
//create Server which can accept requests
final ServerSocket server = new ServerSocket(900);
System.out.println("Listening for connection on port 900...");
while(true) {
try { //creates socket when new request is received
Socket socket = server.accept();
System.out.println("received request");
RequestHandler rh = new RequestHandler(socket); //RequestHandler implements runnable interface, pass this object to create Thread
Thread thread = new Thread(rh);
thread.start(); //begins run() method defined in rh
// Date today = new Date();
// String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
// socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
// System.out.println("got a new request");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

Is it possible to write a custom redirect in java

I am testing an application.
My test is complex, and I spawn 2 thread that start 2 process builders which spawn 2 java processes.
Is it possible to write a custom redirect that will be similar to inherit but prepend something to every out and err message, so that I would know its origin.
Example code below:
public class test {
public static void main(String... args){
Thread t = new Thread(new testHelper());
t.start();
t = new Thread(new testHelper());
t.start();
}
}
import java.io.IOException;
public class testHelper implements Runnable {
#Override
public void run() {
Class klass = testWorker.class;
System.out.println(klass.getCanonicalName());
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
klass.getCanonicalName());
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = null;
try {
process = processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Child Process is done");
}
}
public class testWorker {
public static void main(String ... args) throws InterruptedException {
System.out.println("Doing some stuff");
Thread.sleep(10000);
System.out.println("Finished doing some stuff");
}
}
No, its not possible. In the source code for java.lang.ProcessBuilder.Redirect the constructor is private and has this to say
/**
* No public constructors. Clients must use predefined
* static {#code Redirect} instances or factory methods.
*/
private Redirect() {}

how to Implement a MIDlet that gets invoked when a SMS is sent to port 50000....the code is not working

How to Implement a MIDlet that gets invoked when a SMS is sent to port 50000?
The code is not working. SMS can't be received on the phone, SMS is sent through the emulator (JAVA Me SDK).
What settings should be done to receive the SMS ?
my code:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.IOException;
import javax.microedition.io.PushRegistry;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
/**
* #author bonni
*/
public class Midletsms extends MIDlet implements CommandListener{
protected Display display;
//boolean started=false;
Form form = new Form("Welcome");
Command mCommandQuit;
public void startApp() {
String url = "sms://:50000";
try {
PushRegistry.registerConnection(url,this.getClass().getName(), "*");
// PushRegistry.registerConnection(url,"Midletsms.class", "*");
} catch (IOException ex) {
} catch (ClassNotFoundException ex) {
}
form.append("This midlet gets invoked when message is sent to port:50000");
display = Display.getDisplay(this);
display.setCurrent(form);
mCommandQuit = new Command("Quit", Command.EXIT, 0);
form.addCommand(mCommandQuit);
form.setCommandListener(this);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void commandAction(Command c, Displayable d) {
// throw new UnsupportedOperationException("Not supported yet.");
String label = c.getLabel();
if(label.equals("Quit"))
{
destroyApp(false);
notifyDestroyed();
}
}
}
Not sure I fully understand the problem. But you need to read about PushRegistry.
So there are two types of push registration, static and dynamic.
The code example you have given uses dynamic registration. You will need to manually invoke this MIDlet at least once in order for the push registration to happen. (Aside: In your example you are doing this in the startApp method, this is a very bad idea! Push registration is a potentially blocking operation, and therefore should not be done in a lifecycle method such as startApp. You should do this in a new thread).
The alternative is static registration, where you include the push information in the jad. The push port will be registered when the MIDlet is installed, without the need to run it.
Finally, you say
sms is sent through the emulator
what does this mean? In order for the app to start you need to send an SMS on the relevant port number from another MIDlet (this could be on the same handset if you want).
I found this code on net from Jimmy's blog and it is perfectly working. You can try it your self,
SMSSender.java
public class SMSSender extends MIDlet implements CommandListener {
private Form formSender = new Form("SMS Sender");
private TextField tfDestination = new TextField("Destination", "", 20, TextField.PHONENUMBER);
private TextField tfPort = new TextField("Port", "50000", 6, TextField.NUMERIC);
private TextField tfMessage = new TextField("Message", "message", 150, TextField.ANY);
private Command cmdSend = new Command("Send", Command.OK, 1);
private Command cmdExit = new Command("Exit", Command.EXIT, 1);
private Display display;
public SMSSender() {
formSender.append(tfDestination);
formSender.append(tfPort);
formSender.append(tfMessage);
formSender.addCommand(cmdSend);
formSender.addCommand(cmdExit);
formSender.setCommandListener(this);
display = Display.getDisplay(this);
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
display.setCurrent(formSender);
}
public void commandAction(Command c, Displayable d) {
if (c==cmdSend) {
SendMessage.execute(tfDestination.getString(), tfPort.getString(), tfMessage.getString());
} else if (c==cmdExit) {
notifyDestroyed();
}
}
}
class SendMessage {
public static void execute(final String destination, final String port, final String message) {
Thread thread = new Thread(new Runnable() {
public void run() {
MessageConnection msgConnection;
try {
msgConnection = (MessageConnection)Connector.open("sms://"+destination+":" + port);
TextMessage textMessage = (TextMessage)msgConnection.newMessage(
MessageConnection.TEXT_MESSAGE);
textMessage.setPayloadText(message);
msgConnection.send(textMessage);
msgConnection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
SMSReceiver.java
public class SMSReceiver extends MIDlet implements CommandListener, MessageListener {
private Form formReceiver = new Form("SMS Receiver");
private TextField tfPort = new TextField("Port", "50000", 6, TextField.NUMERIC);
private Command cmdListen = new Command("Listen", Command.OK, 1);
private Command cmdExit = new Command("Exit", Command.EXIT, 1);
private Display display;
public SMSReceiver() {
formReceiver.append(tfPort);
formReceiver.addCommand(cmdListen);
formReceiver.addCommand(cmdExit);
formReceiver.setCommandListener(this);
display = Display.getDisplay(this);
}
protected void destroyApp(boolean unconditional)
throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException {
display.setCurrent(formReceiver);
}
public void commandAction(Command c, Displayable d) {
if (c==cmdListen) {
ListenSMS sms = new ListenSMS(tfPort.getString(), this);
sms.start();
formReceiver.removeCommand(cmdListen);
} else if (c==cmdExit) {
notifyDestroyed();
}
}
public void notifyIncomingMessage(MessageConnection conn) {
Message message;
try {
message = conn.receive();
if (message instanceof TextMessage) {
TextMessage tMessage = (TextMessage)message;
formReceiver.append("Message received : "+tMessage.getPayloadText()+"\n");
} else {
formReceiver.append("Unknown Message received\n");
}
} catch (InterruptedIOException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ListenSMS extends Thread {
private MessageConnection msgConnection;
private MessageListener listener;
private String port;
public ListenSMS(String port, MessageListener listener) {
this.port = port;
this.listener = listener;
}
public void run() {
try {
msgConnection = (MessageConnection)Connector.open("sms://:" + port);
msgConnection.setMessageListener(listener);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Resources