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.
Related
I'm working on setting up my first websocket server for a communications app. I can't seem to figure out how websockets are implemented in Java.
I've tried, unsuccessfully, creating an annotation based Endpoint, but I'm not sure where the client info is going to come through. This is basically the gist of my code, without going into mundane details.
I'm trying to make the class MessageHelper deal with the websocket info transfer, I just can't grasp how to actually get the transfer there.
class MainServer implements Runnable {
// VARIABLES
ServerSocket serverSocket = null;
int port;
// CONSTRUCTORS
MainServer(int p) {
this.port = p;
}
// METHODS
public void run() {
openServerSocket();
while(!isStopped()){
try{
clientSocket = serverSocket.accept();
} catch(IOException e) {
// Do something
}
new Thread(new MainThread(clientSocket)).start();
}
}
}
// Other methods below.
public class MainThread {
final Socket socket;
MainThread(Socket s) {
this.socket = s;
}
public void run() {
try{
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String input = br.readLine(), read = br.readLine();
while(!input.isEmpty()) {
read += "\n";
read += input;
input = br.readLine();
}
/**
* Everything works fine, I'm just not sure where to go
* from here. I tried creating MessageHelper into the java
* websocket implementation using annotations but it did not
* accept input from the client after the handshake was
* made. My client would send something but it would just
* give and EOFException.
**/
if(websocketHandshakeRequest(read)) {
MessageHelper messageHelper =
new MessageHelper(this.socket);
} else {
// Do something
}
} catch(Exception e) {
// Do something.
}
}
}
Don't be confused about the name WebSocket. A TCP socket and a WebSocket are entirely different kind of "sockets".
In Java you use a ServerSocket for TCP sockets. TCP is a transport layer protocol used to implement application layer protocols like POP3 and HTTP.
WebSocket is a HTTP/1.1 protocol upgrade commonly used in web servers and web browsers. You cannot use a ServerSocket for the WebSocket protocol, at least not so straight forward as you might think. First, you have to implement the HTTP/1.1 protocol and then the WebSocket protocol on top of that.
In the Java world you can use web servers like Tomcat or Jetty which provide WebSocket implementations and a high level Java API. This API is part of the Jave Enterprise Edition (JEE). See also the Jave EE 7 Tutorial - Chapter 18 Java API for WebSocket.
E.g. Jetty is a lightweight JEE web server which can be embedded in your application or run as a stand-alone server. See Jetty Development Guide - Chapter 26. WebSocket Introduction.
So in a Java web application running in a WebSocket enabled JEE web server like Jetty you can implement a server side WebSocket as follows:
package com.example.websocket;
import org.apache.log4j.Logger;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#ServerEndpoint("/toUpper")
public class ToUpperWebsocket {
private static final Logger LOGGER = Logger.getLogger(ToUpperWebsocket.class);
#OnOpen
public void onOpen(Session session) {
LOGGER.debug(String.format("WebSocket opened: %s", session.getId()));
}
#OnMessage
public void onMessage(String txt, Session session) throws IOException {
LOGGER.debug(String.format("Message received: %s", txt));
session.getBasicRemote().sendText(txt.toUpperCase());
}
#OnClose
public void onClose(CloseReason reason, Session session) {
LOGGER.debug(String.format("Closing a WebSocket (%s) due to %s", session.getId(), reason.getReasonPhrase()));
}
#OnError
public void onError(Session session, Throwable t) {
LOGGER.error(String.format("Error in WebSocket session %s%n", session == null ? "null" : session.getId()), t);
}
}
You register your class as a WebSocket handler for the specific path with the #ServerEndpoint annotation. Your WebSocket URL is then ws://host:port/context/toUpper or wss://host:port/context/toUpper for HTTPS connections.
Edit:
Here is a very simplistic HTML page to demonstrate the client side connection to the above WebSocket. This page is served by the same webserver as the WebSocket. The webapplication containing the WebSocket is deployed at context "websocket" on localhost port 7777.
<html>
<body>
<h2>WebSocket Test</h2>
<div>
<input type="text" id="input" />
</div>
<div>
<input type="button" id="connectBtn" value="CONNECT" onclick="connect()" />
<input type="button" id="sendBtn" value="SEND" onclick="send()" disable="true" />
</div>
<div id="output">
<h2>Output</h2>
</div>
</body>
<script type="text/javascript">
var webSocket;
var output = document.getElementById("output");
var connectBtn = document.getElementById("connectBtn");
var sendBtn = document.getElementById("sendBtn");
var wsUrl = (location.protocol == "https:" ? "wss://" : "ws://") + location.hostname + (location.port ? ':'+location.port: '') + "/websocket/toUpper";
function connect() {
// open the connection if one does not exist
if (webSocket !== undefined
&& webSocket.readyState !== WebSocket.CLOSED) {
return;
}
updateOutput("Trying to establish a WebSocket connection to <code>" + wsUrl + "</code>");
// Create a websocket
webSocket = new WebSocket(wsUrl);
webSocket.onopen = function(event) {
updateOutput("Connected!");
connectBtn.disabled = true;
sendBtn.disabled = false;
};
webSocket.onmessage = function(event) {
updateOutput(event.data);
};
webSocket.onclose = function(event) {
updateOutput("Connection Closed");
connectBtn.disabled = false;
sendBtn.disabled = true;
};
}
function send() {
var text = document.getElementById("input").value;
webSocket.send(text);
}
function closeSocket() {
webSocket.close();
}
function updateOutput(text) {
output.innerHTML += "<br/>" + text;
}
</script>
</html>
If you're willing to use Java Spring - which I think would be great for your use case, it's pretty easy to setup a websocket server and client connection.
There's an example here - https://spring.io/guides/gs/messaging-stomp-websocket/
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.
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 using RabbitMQ and web-stomp in the web browser according to this tutorial:
https://www.rabbitmq.com/web-stomp.htm
I succeded to connect and the get messages in the browser.
But,
the message I sent and consumed in the client is still in the queue and not being dequeing(I did manual ack and auto ack), it still exists.
when I subscribe to a queue I'm not getting all the messages in the queue, but only the last.. only when the websocket is open and then the server send the message i get the last message but not the old ones.
The server Code:
private static final String EXCHANGE_NAME = "amq.topic";
public static void AddToQueue(String RoutingKey, String message) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
channel.basicPublish(EXCHANGE_NAME, RoutingKey, null, message.getBytes());
channel.close();
connection.close();
}
The client code:
var ws = new SockJS('http://' + window.location.hostname + ':15674/stomp');
$scope.client = Stomp.over(ws);
$scope.client.heartbeat.outgoing = 0;
$scope.client.heartbeat.incoming = 0;
var on_connect = function(x) {
$scope.client.subscribe("/topic/status", function(d) {
console.log(d.body);
});
};
var on_error = function() {
console.log('error');
};
$scope.client.connect('guest', 'guest', on_connect, on_error, '/');
Thanks.
Solved it, the exchange name needs to be "amq.topic"
So I made a simple UDP Client for android, and for some reason it doesn't want to work. I've been struggling with this for like 5 hours now, and I can't find the problem. I even looked almost all the tutorials on the internet, to compare the codes, but I had no luck.
String serverString = "192.168.1.109";
int port = 7777;
Log.d("adam", "Debug");
DatagramSocket socket = null ;
String msg = "Hello World!";
try {
socket = new DatagramSocket() ;
InetAddress host = InetAddress.getByName(serverString);
byte [] data = msg.getBytes() ;
DatagramPacket packet = new DatagramPacket( data, data.length, host, port );
Log.d("adam", "Debug2");
socket.send(packet) ;
Log.d("adam", "Packet sent" );
} catch( Exception e )
{
Log.d("adam", "Exception");
Log.e("adam", Log.getStackTraceString(e));
}
finally
{
if( socket != null ) {
socket.close();
}
}
My mainfest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
Here is the debug img:
As you can see the "Packet sent" text is not in the logcat. So the problem is probably with the send() function. Any idea what could be the problem?
Never ever run networking on the main thread. Do not do the work around that Mark suggests.
When you send data you should use an ASyncTAsk or a Thread.
Here is a very simple threaded function:
Thread sendDate = new Thread() {
#Override
public void run() {
String serverString = "192.168.1.109";
int port = 7777;
Log.d("adam", "Debug");
DatagramSocket socket = null ;
String msg = "Hello World!";
try {
socket = new DatagramSocket() ;
InetAddress host = InetAddress.getByName(serverString);
byte [] data = msg.getBytes() ;
DatagramPacket packet = new DatagramPacket( data, data.length, host, port );
Log.d("adam", "Debug2");
socket.send(packet) ;
Log.d("adam", "Packet sent" );
} catch( Exception e )
{
Log.d("adam", "Exception");
Log.e("adam", Log.getStackTraceString(e));
}
finally
{
if( socket != null ) {
socket.close();
}
}
}
};
sendDate.start();
If you want to tell the user if the data was sent then you should use an ASyncTask