I'm making a live connection between a Socket Server (Java) and a Socket Client (NodeJS). This is for a webinterface.
I can send data from NodeJS to Java, but not the other way around. I commented in the code, which positions I mean. I tried it already like you see with out.write("Hello World\n"); (with flush, of course). I tried also with out.println("Hello World"); (with flush, of course).
public class WebHandler {
private ServerSocket server;
private static Socket sock;
public void listen(int port) {
try {
server = new ServerSocket(port);
} catch (IOException e) {
System.out.println("Could not listen on port " + port);
System.exit(-1);
}
Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.getPlugin(), new BukkitRunnable() {
#Override
public void run() {
try {
System.out.println("Waiting for connection");
final Socket socket = server.accept();
sock = socket;
final InputStream inputStream = socket.getInputStream();
final InputStreamReader streamReader = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(streamReader);
// readLine blocks until line arrives or socket closes, upon which it returns null
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
WebHandler.sendMessage();
} catch (IOException e) {
System.out.println("Accept failed: " + port);
System.exit(-1);
}
}
}, 0, 100);
}
// CRITICAL
public static void sendMessage() {
try {
PrintWriter out = new PrintWriter(sock.getOutputStream());
out.write("Hello World from Java!" + "\n");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
var net = require('net');
var client = net.connect(9090, 'localhost');
client.setEncoding('utf8');
setInterval(function() {
console.log("Writing....")
var ret = client.write('Hello from node.js\n');
console.log("Wrote", ret)
}, 5000);
// CRITICAL
client.on('data', function(data) {
console.log('Received: ' + data);
});
Please don't let you distract because of the Bukkit.getScheduler()... It's only a Task Manager. Thanks in advance :D
You don't receive a message from java because you have set an interval which will always send messages to the server and the server will be stuck in the while loop.
I would suggest to stop the interval at some point so that sendMessage() will be called.
Related
I'm following this tutorial : https://www.baeldung.com/websockets-spring
I tested the app and it works perfectly when running on the embedded-tomcat server. However, when I try to deploy and run the same app on an external tomcat server it breaks, because instead of the URL being
localhost:8080/chat
it becomes
myhostIP:port/spring-boot-web-jsp/chat
So I modified the javascript file adding /spring-boot-web-jsp in front of the existing URLs. When I run the webapp the sockets connect successfully and send data. However now my Spring MVC Controller doesn't work.
My javascript :
var stompClient = null;
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('conversationDiv').style.visibility
= connected ? 'visible' : 'hidden';
document.getElementById('response').innerHTML = '';
}
function connect() {
var socket = new SockJS('/spring-boot-web-jsp-1.0/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/spring-boot-web-jsp-1.0/topic/messages', function(messageOutput) {
showMessageOutput(JSON.parse(messageOutput.body));
});
});
}
function disconnect() {
if(stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendMessage() {
var from = document.getElementById('from').value;
var text = document.getElementById('text').value;
stompClient.send("/spring-boot-web-jsp-1.0/app/chat", {},
JSON.stringify({'from':from, 'text':text}));
}
function showMessageOutput(messageOutput) {
var response = document.getElementById('response');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(messageOutput.from + ": "
+ messageOutput.text + " (" + messageOutput.time + ")"));
response.appendChild(p);
}
My Controller :
#MessageMapping("/chat")
#SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
My message broker :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat");
registry.addEndpoint("/chat").withSockJS();
}
}
I've tried modifying the Controller to :
#MessageMapping("app/chat")
#SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
#MessageMapping("spring-boot-web-jsp-1.0/app/chat")
#SendTo("spring-boot-web-jsp-1.0/topic/messages")
public OutputMessage send(Message message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
and a bunch of other variations but none of them work.
How can I modify the Controller and javascript file to work when testing through external Apache Tomcat as well as embedded (setting a relative URL of some sort)? And how can I get this to work properly on the external Tomcat?
Remove your tomcat/webapps/ROOT directory
Rename your final jar/war/ear file to ROOT.jar/war/ear
Deploy it on tomcat
Tomcat will deploy your app under root directory localhost:8080/chat
Im trying to make a simple application. That is When I write a word at edittext in android app such as "Hi", Then android app send message "Hi" to node.js server and node.js server send message "Hi has sent successflly" to android app. This is just a example, actually my object is android send a data(message) to server, and receive another data(message) from server.
The problem is this. When I write a word at android app and press button, the message transmitted successfully(I can confirm by console at node.js). But I cant send message to android from node.js .. When I press send button, My android app shut down..
What android says is "java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Activity.runOnUiThread(java.lang.Runnable)' on a null object reference" ..
Yesterday, this error didn't happened and another error occured. "cannot cast string to JSONObject."
I will show you my code.
Server Side(Node.js)
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = 12000;
app.get('/', function(req, res) {
res.sendFile('index.html');
})
io.on('connection', function(socket) {
console.log('Android device has been connected');
socket.on('message', function(data) {
console.log('message from Android : ' + data);
Object.keys(io.sockets.sockets);
Object.keys(io.sockets.sockets).forEach(function (id) {
console.log("ID : ", id );
io.to(id).emit('message', data);
console.log(data + ' has sent successfully');
})
/*if (data != null) {
io.emit('message', {message : data + ' has received successfully'});
}*/
})
socket.on('disconnect', function() {
console.log('Android device has been disconnected');
})
})
http.listen(port, function() {
console.log('Server Start at port number ' + port);
})
Client Side (Android)
private Emitter.Listener handleIncomingMessages = new Emitter.Listener(){
#Override
public void call(final Object... args){
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject data = (JSONObject) args[0];
String message;
try {
message = data.getString("text").toString();
Log.i("result", message);
addMessage(message);
} catch (JSONException e) {
Log.e("result", "Error : JSONException");
return;
} catch (ClassCastException e) {
Log.e("result", "Error : ClassCastException");
e.printStackTrace();
return;
}
}
});
}
};
private void sendMessage(){
String message = mInputMessageView.getText().toString().trim();
mInputMessageView.setText("");
addMessage(message);
JSONObject sendText = new JSONObject();
try{
sendText.put("text", message);
socket.emit("message", message);
}catch(JSONException e){
}
}
private void addMessage(String message) {
mMessages.add(new Message.Builder(Message.TYPE_MESSAGE)
.message(message).build());
// mAdapter = new MessageAdapter(mMessages);
mAdapter = new MessageAdapter( mMessages);
mAdapter.notifyItemInserted(0);
scrollToBottom();
}
private void scrollToBottom() {
mMessagesView.scrollToPosition(mAdapter.getItemCount() - 1);
}
I already searched similar problems that other people asked, but It didn't give me solution. Please help me. Thank you for reading long question.
p.s Because Im not English speaker, Im not good at English .. There will be many problems at grammar and writing skills. Thanks for understanding...
Reason this happens is because method getActivity() returns null. This might happen if you run this on a fragment after it is detached from an activity or activity is no longer visible. I would do a normal null check before like:
Activity activity = getActivity();
if(activity != null) {
activity.runOnUiThread(new Runnable() {...}
}
I'm not familiar with socket.emit() method but it might throw network exception since it's running on UI thread and you are not allowed to do that. I recommend using RxJava/RxAndroid if you want to do this on another thread.
If you want to do network operation just use it like this:
Observable
.fromRunnable(new Runnable {
void run() {
// here do your work
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Void>() {
#Override
public void onCompleted() {
// not really needed here
}
#Override
public void onError(Throwable e) {
// handle errors on UI thread
}
#Override
public void onNext(Void void) {
// do something on UI thread after run is done
}
});
Basically what it does it calls method call from Callable you just made on separate thread and when it's over it invokes onNext method if no exception was thrown or onError method if exception was thrown from Subscriber class.
Note that Response class isn't part of the RxJava/RxAndroid API and you can make it if you want. You can make it a simple POJO class or anything else you need it to be. If you don't need to have response you can use Runnable instead of Callable and it will work just fine.
In order for this to work you need to add this dependencies to your modules Gradle file:
dependencies {
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
}
I'm trying to send binary data between server (C#) application and client (js-application -- made by WebSocket). Connection between server and client is established and handshake is OK. Messages from client are receiving by server, but when I'm trying to send binary data to client, the event "onmessage" doesn't work.
This is fragments of my C# code. Sending binary data in "sendFile" function.
class Listener
{
private IPAddress ip;
private int port;
private TcpListener server;
private TcpClient client;
private NetworkStream stream;
private bool isSuccHandshaked;
public Listener()
{
ip = IPAddress.Loopback;
port = 8080;
server = new TcpListener(ip, port);
isSuccHandshaked = false;
}
private void makeHandshake()
{
//...
}
private String decodeMessage(Byte[] bytes)
{
//...
}
private void sendFile()
{
Byte[] dataToSend = File.ReadAllBytes("test.txt");
stream.Write(datatosend, 0, datatosend.Length);
stream.Flush();
}
public void startListen()
{
server.Start();
Console.WriteLine("Server has started on {0}. Port: {1}. {2}Waiting for a connection...", ip, port, Environment.NewLine);
client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
stream = client.GetStream();
while (!isSuccHandshaked)
{
makeHandshake();
}
while (true)
{
if (client.Available > 0)
{
Byte[] bytes = new Byte[client.Available];
stream.Read(bytes, 0, bytes.Length);
String message = decodeMessage(bytes);
sendFile();
}
}
}
}
}
and js-code:
var address = 'ws://localhost:8080';
var socket = new WebSocket( address );
socket.binaryType = "arraybuffer";
socket.onopen = function () {
alert( 'handshake successfully established. May send data now...' );
socket.send( "Aff" );
};
socket.onclose = function () {
alert( 'connection closed' );
};
socket.onmessage = function ( evt ) {
console.log( "Receive message!" );
console.log( "Got ws message: " + evt.data );
}
Maybe there is some peculiar properties in receiving data with WebSocket protocol? Wich useful approaches to send binary data from C# code to js you can recommend?
A websocket is not a raw TCP socket. It uses HTTP negotiation and its own framing protocol you have to comply with. If you are interested in writing your own server in C# take a look at this.
However if you only want to use them, you can either use the default Microsoft implementation with IIS, or you can use one of the many standalone websockets components. I maintain one named WebSocketListener.
I'm making a website with a game on it. For the game i need to send data trought sockets. Everything is working fine with loading the page but I can't get the handshaking to work.
class ServerClient {
public ServerClient() {
handshake();
}
private void handshake() {
try {
String line;
String key = "";
boolean socketReq = false;
while (true) {
line = input.readLine();
if (line.startsWith("Upgrade: websocket"))
socketReq = true;
if (line.startsWith("Sec-WebSocket-Key: "))
key = line;
if (line.isEmpty())
break;
}
if (!socketReq)
socket.close();
String encodedKey = DatatypeConverter.printBase64Binary(
MessageDigest.getInstance("SHA-1")
.digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes()));
System.out.println(encodedKey);
output.println("HTTP/1.1 101 Switching Protocols");
output.println("Upgrade: websocket");
output.println("Connection: Upgrade");
output.println("Sec-WebSocket-Accept: " + encodedKey);
output.flush();
output.close(); // output = new PrintWriter(
// Socket.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
The socketReq variable is there because I don't want anyone to connect to localhost:25580 straight from their browser.
My send and receive functions are in different Threads and they will be started after the handshake.
The result of new WebSocket("ws://localhost:25580") in JS is
WebSocket connection to 'ws://localhost:25580/' failed: Error during WebSocket handshake: net::ERR_CONNECTION_CLOSED
I was having
Error during WebSocket handshake: Incorrect 'Sec-WebSocket-Accept' header value
but I guess I changed something in the code.
I searched for hours trought Article 1 and Article 2 and from other sites. Just couldn't get the whole thing to work properly.
I don't get the point of the keys and why we have to encode them.
The socket is connected to the browser and I am getting the headers from it.
Host: localhost:25580
Sec-WebSocket-Key: iWLnXKrA3fLD6h6UGMIigg==
How does the handshaking work?
You are getting a net::ERR_CONNECTION_CLOSED error, because you are closing the connection with output.close().
If you want to keep the connection open, obviously don't close it during a handshake.
Done!
Found the answers from http://blog.honeybadger.io/building-a-simple-websockets-server-from-scratch-in-ruby/ and It's working perfectly!
The code:
public ClientSocket(Socket socket) {
try {
this.socket = socket;
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.output = new PrintWriter(socket.getOutputStream());
handshake();
}
private void handshake() {
try {
String line;
String key = "";
while (true) {
line = input.readLine();
if (line.startsWith("Sec-WebSocket-Key: ")) {
key = line.split(" ")[1];
System.out.println("'" + key + "'");
}
if (line == null || line.isEmpty())
break;
}
output.println("HTTP/1.1 101 Switching Protocols");
output.println("Upgrade: websocket");
output.println("Connection: Upgrade");
output.println("Sec-WebSocket-Accept: " + encode(key));
output.println();
output.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
private String encode(String key) throws Exception {
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] bytes = MessageDigest.getInstance("SHA-1").digest(key.getBytes());
return DatatypeConverter.printBase64Binary(bytes);
}
Now I just have to decode the messages.
I have been trying to transfer audio files between my android app and my node-webkit app but I'm new to the world of socket.io/nodejs/delivery.js.
Here is my code:
android-code ERROR-LINE: os.write(mybytearray, 0, mybytearray.length);
protected Void doInBackground(Void... arg0) {
Socket sock;
try {
// sock = new Socket("MY_PCs_IP", 1149);
sock = new Socket("192.168.0.10", 5001);
System.out.println("Connecting...");
// sendfile
File myFile = new File(this.currentSong.getPath());
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
System.out.println("Sending...");
os.write(mybytearray, 0, mybytearray.length);
os.flush();
System.out.println("Sended..");
// RESPONSE FROM THE SERVER
BufferedReader in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
in.ready();
String userInput = in.readLine();
System.out.println("Response from server..." + userInput);
sock.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
node-webkit-code
var io = require('socket.io').listen(5001),
dl = require('delivery'), //delivery.server
fs = require('fs');
io.sockets.on('connection', function(socket){
delivery = dl.listen(socket);
delivery.on('receive.success',function(file){
fs.writeFile("music/"+file.name,file.buffer, function(err){
if(err){
console.log('File could not be saved.');
}else{
console.log('File saved.');
addSong("music/"+file.name);
};
});
});
});
Note: My server side works well it's already tested by a js client
This is the error I am getting:
Android side Error:
08-28 14:56:36.180: W/System.err(30510): java.net.SocketException: sendto failed: EPIPE (Broken pipe)
08-28 14:56:36.180: W/System.err(30510): at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:499)
08-28 14:56:36.180: W/System.err(30510): at libcore.io.IoBridge.sendto(IoBridge.java:468)
08-28 14:56:36.180: W/System.err(30510): at java.net.PlainSocketImpl.write(PlainSocketImpl.java:507)
So maybe I'm wrong trying to do a bad connection because of protocols.. between a socket and socket.io..?
if any one can help my out I will be pleased. I already looked around but as I said I'm new to this world and I get hazy
basically my question is: What's wrong? and How I accomplish my objective?
Thanks for your time
I am using com.koushikdutta.async.http.socketio.SocketIOClient
there is some problems with this library and socket.io but it it's solved by using this dependency on node-webkit
"socket.io": "~0.9",
also need to read file->base64 codification-> then emit the string on the server side must do this:
socket.on('finishFileTransfer',function(){
fs.writeFile("music/"+fileName,new Buffer(file,'base64'), function(err){
if(err){
console.log('File could not be saved.');
}else{
console.log('File saved.');
addSong("musica/"+fileName);
}
file = "";
fileName = null;
});
});