I am trying to teach myself some networking in Java using the Kryonet library. The following code is almost identical to the code in the kyronet tutorial. https://code.google.com/p/kryonet/#Running_a_server
The client is successfully sending the message "Here is the request!" to the server (the server is printing it out) however the client is not receiving any response from the server even though the server is sending one.
I've tried unsuccessfully to fix it, can anyone see or suggest a possible problem/solution with the code?
(The code follows)
Client
public class Client_test {
Client client = new Client();
public Client_test() {
Kryo kryo = client.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
client.start();
try {
client.connect(50000, "127.0.0.1", 54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
client.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeResponse) {
SomeResponse response = (SomeResponse)object;
System.out.println(response.text);
}
}
});
SomeRequest request = new SomeRequest();
request.text = "Here is the request!";
client.sendTCP(request);
}
}
Server
public class ServerGame {
Server server = new Server();
public ServerGame() {
Kryo kryo = server.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
server.start();
try {
server.bind(54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
server.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeRequest) {
SomeRequest request = (SomeRequest)object;
System.out.println(request.text);
SomeResponse response = new SomeResponse();
response.text = "Thanks!";
connection.sendTCP(response);
}
}
});
}
}
Response & Request classes
public class SomeRequest {
public String text;
public SomeRequest(){}
}
public class SomeResponse {
public String text;
public SomeResponse(){}
}
After many hours watching youtube videos and sifting through the web I found the answer. Which I will post on here as it seems that quite a few people have had this problem so I would like to spread the word.
Basically the client would shut down immediately, before it could receive and output the message packet. This is because "Starting with r122, client update threads were made into daemon threads, causing the child processes to close as soon as they finish initializing.", the solution is "Maybe you could use this? new Thread(client).start();".
So basically instead of using
client.start();
to start the client thread you must use
new Thread(client).start();
Which I believe stops the thread being made into a daemon thread which therefore stops the problem.
Source: https://groups.google.com/forum/?fromgroups#!topic/kryonet-users/QTHiVmqljgE
Yes, inject a tool like Fiddler in between the two so you can see the traffic going back and forth. It's always easier to debug with greater transparency, more information.
Related
I have a Server that can receive multiple request at the same time.
In my Server, I have to make some traitement and wait for response. This traitmenet is done by externe library so I don't how much should I wait.
So the Server looks like :
public class MyServer{
#Override
//method from the library
public void workonRequest(){
//---
response=[...]
}
public void listenRequest() {
new Thread(() -> {
while (true) {
try {
socket = server.accept();
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
socket.setTcpNoDelay(true); //TODO : Not sure !
new Thread(() -> {
try {
handleRequest(input, output);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}).start();
}
And the handle request method is :
public void handleRequest(ObjectInputStream input, ObjectOutputStream output) throws IOException {
try {
while (true) {
//forward the request to the library
//work on it [means using the library and waiting]
// return response
}
}
}
The response object is the result that I want return to the client
How to deal with the problem of waiting for the answer?
How can I make sure that there will be no problems when more than 2 clients send requests at the same time.
Thanks in advance
How to deal with the problem of waiting for the answer ?###
Using while(true) can create issues because you are blocking the thread and opening sub thread and multi streams will make it more complex. There is easy way called reactive programming which handles this kind of multi-threaded issues easily, quarkus async solution and spring, if you still want to manage your sockets from java code you can use akka
How can I make sure that there will be no problems when more than 2 clients send requests at the same time.
That can be done by not blocking the main thread and If you manage to use reactive and/or async approach you will not have that problem.
Reference
https://quarkus.io/guides/getting-started-reactive
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html
I have a client-side driven GUI (Swing) and I need to process more that one request. I can process one request, For example, 'logging in, the user' but I am unable to make any other request like 'fetch all users' from the server.
How can I process more than one request on the server and how would I set it up on the client-side.
Client-Side
private Socket server;
public ClientConnection() {
try {
server = new Socket("127.0.0.1", 12345);
} catch(IOException e) {
System.out.println("Connection Error - Client: " + e.getMessage());
}
}
public void loginUser(User user) {
try {
ObjectOutputStream out = new ObjectOutputStream(server.getOutputStream());
out.flush();
ObjectInputStream in = new ObjectInputStream(server.getInputStream());
//How would I write the request type to the server
out.writeObject((User) user);
out.flush();
User getUserInfo = (User) in.readObject();
//System.out.println("Response from the server: " + getUserInfo.getRole());
out.close();
in.close();
server.close();
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
Server-side
private ServerSocket serverListener;
private Socket client;
public ServerConnection() {
try {
serverListener = new ServerSocket(12345, 10);
} catch(IOException e) {
System.out.println("Server-Side Error: Connection" + e.getMessage());
}
}
public void server() {
try {
System.out.println("Server is listening");
client = serverListener.accept();
//How can I make a request and then process it depending on the type of
//request
//Gets the ObjectOutputStream and the ObjectInputStream and send a User object back to
//the client-side
loginUser();
} catch(IOException e) {
System.out.println(e.getMessage());
e.getStackTrace();
}
}
My initial thinking is to have an Enum class with different request types and then have a switch statement in my server() method and depending on the type of request a method is called to perform those actions but I am not sure on how to send a request type to the server and if handling the request type in the server() method would be best practices.
What you need to think about is how to define the communication between your client and server. Define protocols and message structures.
Let's say you want to introduce multiple request types. It is up to you what those request types will be, but what is going to happen is that you will be introducing the logic to handle the new types of requests on both the client and server.
Just like in REST, both client and server know what GET/POST is - you will also need to have these protocols defined for your communication.
An example would be, your client is sending a request of type fetch-all-users. One way to structure this would be:
{
"requestType": "fetch-all-users",
"body": "..."
}
You can have a common module for the enum types, that is up to you.
Further on, we get to the question on how you would like to process the request on the server side.
A straightforward solution would be adding if-else logic to process the correct request type based on the provided type.
But to avoid the if else logic, you could play around with design patterns.
Create a factory for your requestProcessingActions:
class ActionFactory {
public Action resolve(RequestType requestType) {
final Action resolvedAction;
switch(requestType) {
case fetch-all-users:
resolvedAction = fetchAllUsers();
break;
case log-in-user:
resolvedAction = logInUser();
break;
}
return resolvedAction;
}
}
And call it in your server:
public void server() {
try {
System.out.println("Server is listening");
client = serverListener.accept();
RequestType type = getRequestTypeFromRequest();
ActionFactory.resolve(type);
}
}
I am building a server. I hope that after the Java server and the C# client are connected, I can send information from the HTML to the Java server, and then the Java server sends this information to the client.But I can't get the socket after the successful establishment in the service layer, so my Java server can only send fixed information to the client.
I tried using Class object = new Class(); object.setObject(socket); to save the socket, but when I call this object in the service layer, I get null;
I tried to save the socket using (Map) socket.put("socket", socket), but when I call this method in the service layer, I get null.
This is the code to make the socket. from SocketThread.java
public void run() {
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(5656);
LOGGER.info("socket server start, monitor 5656 port ! ");
Socket socket = serverSocket.accept();
new SocketClientRequest(socket).start();
LOGGER.info("send success ! ");
}catch (Exception ex){
LOGGER.error("send fail ! ");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("服务器延时重启失败 ! ");
}
}
This is a method of reading the information sent by the client using the socket and sending the information to the client. from SocketClientRequest.java
public void run() {
try {
//获取socket中的数据
bufferedInputStream = new
BufferedInputStream(socket.getInputStream());
byte[] clientCharStream = new byte[messageLengthBytes];
bufferedInputStream.read(clientCharStream);
System.out.println(new String(clientCharStream, "utf-8"));
OutputStream out = socket.getOutputStream();
out.write(new String("welcome_send_server!").getBytes());
} catch (IOException e) {
LOGGER.error("read massage error [{}]", e);
}
}
Create a connection when the project starts
#EnableScheduling
#SpringBootApplication
public class GzserverApplication {
public static void main(String[] args) {
SpringApplication.run(GzserverApplication.class, args);
SocketServer socketServer = new SocketServer();
socketServer.start();
}
}
Until this step, everything is fine, but the key problem is coming.
I need to send information to the client through my controller.
this is controller
#ResponseBody
#RequestMapping(value = "firstSend)
public SResult<String> firstSend(String uName, String pNum, String time){
try{
return httpService.firstSend(uName, pNum, time);
}catch (Exception ex){
LOGGER.error(ex.getMessage(), ex);
}
return SResult.failure("fail of connect");
}
this is service
public SResult<String> firstSend(String uName, String pNum, String time) throws Exception {
String token = TokenUtil.sign(uName);
System.out.println("token code : "+token);
SocketObject socketObject = new SocketObject();
Map<String, Socket> socketMap = socketObject.socket();
Socket socket1 = socketMap.get("Socket"); // is null
Socket socket2 = socketObject.getSocket(); // is null
return SResult.success(token);
}
I hope that after the connection is successfully created, the socket can be used in the service layer, and the information is sent to the client through the socket, but no matter what I do, the socket is null in the service layer.please give me a help, thank you very much
You should not be dealing with Sockets if using Spring. Spring is a very extensive abstraction layer, that lets you avoid having to deal with the nasty details that Sockets introduce.
In your controller, you call: SocketObject socketObject = new SocketObject(); This creates a new object, presumably with a null-initialized Socket object. Nowhere in this code do you pass a socket object from the main() scope to any other scope (for example using a method named setSocket(Socket socket).
However, and I cannot stress this enough, you should not use Sockets in Spring. Think about what problem you are trying to solve, and ask yourself (why do I need to send information to the client). It is likely that Spring has a module that will do this for you in a much more scalable and manageable way.
For example, perhaps you need to establish 2-way communication between the server and the client, and need to post information to the client periodically. In this case, the WebSocket protocol (and associated Spring Websocket library) might be for you.
This is likely an XY problem. If you edit your question to illustrate the functionality you are trying to implement, it may be easier to help
Let me explain the purpose of my application so you can guide me about the best possible approach.
The idea is building a web application to remotely manage some particular equipments that my company manufactures. These equipments will periodically connect to the remote server to send/receive certain data (through simple socket communication but they don't use Java); this data will be stored in the corresponding data base and will be available through the web application for the different users.
In the same way, when you access through the web interface, each client will be able to see their equipments and perform different changes in the configuration. At this point there are 2 possible options and this is the reason of this post:
The easiest but not the best option: the user performs some changes and I save those changes in the data base. When the equipment later establish communication to the server, then it'll read those changes and update its configuration.
The ideal solution: as soon as the user save the changes through the web interface and push the "send" button, those changes are sent to the corresponding equipment.
As mentioned above, these equipments will periodically open a socket communication (let's say every 5 minutes) to the server to send their configuration. At this moment, in order to implement the "ideal solution", the only option I can think of is not to close that socket so I can use it to immediately send information back to the equipment when a certain user makes any changes.
If this application grows along the time, I'm afraid that too many open sockets/threads can crash my application.
Let me illustrate with some code I was playing around. I know this is far from the final solution, it's just to help you understand what I'm looking for.
First of all, I register the socket server during the start-up of the web server (Tomcat in this case):
package org.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.sockets.KKMultiServer;
public class ApplicationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
KKMultiServer kKMultiServer = new KKMultiServer();
Thread serverThread = new Thread(kKMultiServer);
serverThread.start();
event.getServletContext().setAttribute("PlainKKMultiServer", kKMultiServer);
}
public void contextDestroyed(ServletContextEvent event) { }
}
This is the main socket server class that listens for new connections:
public class KKMultiServer implements Runnable {
private Map<Long, KKMultiServerThread_v2> createdThreads = new HashMap<Long, KKMultiServerThread_v2>();
#Override
public void run() {
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(5000)) {
while (listening) {
KKMultiServerThread_v2 newServerThread = new KKMultiServerThread_v2(serverSocket.accept(), this);
Thread myThread = new Thread(newServerThread);
myThread.start();
Long threadId = myThread.getId();
System.out.println("THREAD ID: " + threadId);
}
} catch (IOException e) {
System.err.println("Could not listen on port " + 5000);
System.exit(-1);
}
}
public Map<Long, KKMultiServerThread_v2> getCreatedThreads() {
return createdThreads;
}
}
And the thread class created with every single petition from each of the equipments (dispensers) to handle the socket communication:
public class KKMultiServerThread_v2 implements Runnable {
private Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
private long dispenserCode;
private KKMultiServer kKMultiServer;
public KKMultiServerThread_v2(Socket socket, KKMultiServer kKMultiServer) {
this.socket = socket;
this.kKMultiServer = kKMultiServer;
}
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
readDataFromDispenser();
}
private void readDataFromDispenser() {
String inputLine;
try {
while ((inputLine = in.readLine()) != null) {
if (inputLine.equals("Bye")) {
break;
}
if (dispenserCode == 0) {
dispenserCode = 1111; // this code will be unique per equipment
this.kKMultiServer.getCreatedThreads().put(dispenserCode, this);
}
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendDataToDispenser(String dataToSend) {
if (!socket.isClosed() && socket.isConnected()) {
out.println(dataToSend);
} else {
this.kKMultiServer.getCreatedThreads().remove(this);
}
}
}
Now that the socket is created and alive I can use it directly from the web application to send messages back to the equipment (Struts Action in this case)
public class HelloWorldAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String sendMessageToDispenser() throws Exception {
ServletContext context = ServletActionContext.getServletContext();
KKMultiServer kKMultiServer = (KKMultiServer) context.getAttribute("PlainKKMultiServer");
Map<Long, KKMultiServerThread_v2> currentThreads = kKMultiServer.getCreatedThreads();
Iterator<Long> it = currentThreads.keySet().iterator();
while (it.hasNext()) {
Long key = (Long) it.next();
KKMultiServerThread_v2 currentThread = currentThreads.get(key);
currentThread.sendDataToDispenser("DATA TO YOU!");
}
return SUCCESS;
}
}
Do you think it's possible to perform this solution? I mean, keeping these connections open so I can access my equipments whenever necessary (without waiting for the periodically connections). What's the best approach? If you have any other suggestions please let me know.
Thank you very much.
To my mind it clearly depends on how many equipment will be connected to your system. Sockets are not always sending data so it can have low effect on the overall performance. Though, Socket are know to be a little slow, if you have a lot of data to send to/from your equipments, you should consider this.
If you want to have send data from your server to your client you have few solutions
Your server knows all your equipment after registering for example. When starting you equipment connect to the server. (be careful about local network redirection)
Your equipment and server use sockets to communicate
I don't think there is another solution but I can be wrong. If your equipment request your server every X seconds, it will never be exactly perfeclty on time.
I'm trying to figure out how to send data between sockets in Java (this is part of a bigger project and I'll get back and answer my previous two questions related to that once I can resolve this..). I would like to connect a client and a server socket asynchronously in Java, and then send messages between them, and get a callback, say, when I have sent a message from the client to the server.
I think I have managed to get the set-up working. Here is my code:
private AsynchronousServerSocketChannel socListener;
private AsycnchrnonousSocketChannel socClient;
//This is the GUI callback for the button that initiates the socket server
private void button_StartSocketServerActionPerformed(ava.awt.event.ActionEvent evt)
{
try{
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
m_socListener= AsynchronousServerSocketChannel.open().bind(ipSocket);
m_socListener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>()
{
#Override
public void completed(AsynchronousSocketChannel ch, Void att)
{
// accept the next connection
m_socListener.accept(null, this);
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) { }
}
);
}
catch (Exception e){
}
}
//This is the GUI callback for the button that initiates the client socket
private void button_StartClientSocketActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
socClient=AsynchronousSocketChannel.open();
InetAddress ipLocal= InetAddress.getLocalHost();
InetSocketAddress ipSocket=new InetSocketAddress(ipLocal,8221);
socClient.connect(ipSocket, null, new CompletionHandler<Void,Void>()
{
#Override
public void completed(Void att1, Void att2)
{
// handle this connection
}
#Override
public void failed(Throwable exc, Void att) {}
}
);
}
catch (Exception e){
}
}
I'm including the server and the client in the same file for simplicity of testing.
So supposing the connection is successfully established, and I have a process on a timer (say) that was writing data to the server socket, I'd like to have the client socket 'listen' for this new data being sent from the server and then generate a callback when a write occurs (without doing something like periodically checking via a timer and a while loop to check that whether new data has been added). This is accomplishable in C# and a nice tutorial is available at:
http://www.developerfusion.com/article/3918/socket-programming-in-c-part-1/2/
Any tips on how to do this would be greatly appreciated. Thanks!
Chris
You could use RMI to accomplish that, the documentation can be found there:
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136424.html
With this, your server could notify your client as much as you need.