I wrote a chat through WebSockets.
Server side is written in Java (Tomcat) and client in JavaScript.
All works fine. But when I try connect to server from two machines which are in local network (they're under router; have one external ip) only one client receives data from server.
Connection ( socket.onopen() ) works for both. socket.send(data) also works on both clients;
But receiving messages ( socket.onmessage() ) works just on first connected client.
How can I resolve this problem?
Problem was in server part.
I wanted to broadcast incoming message to all available connections which were in ArrayList.
After sending message to first user, received message became emptied. So, message was sent, but it was just empty string.
My english is bad. So I will whow :
before :
protected void onTextMessage(CharBuffer message) throws IOException {
// List<MessageInbound> connections
for (MessageInbound user : connections )
user.getWsOutbound.writeTextMessage(message);
}
after:
protected void onTextMessage(CharBuffer message) throws IOException {
String msg = message.toString();
for (MessageInbound user : connections )
user.getWsOutbound.writeTextMessage(CharBuffer.wrap(msg));
}
Related
I am using Websocket Rxjs in my application. My connection gets established with the server and after subscribing to it I receive all the data in an array. Now when I try to send the some data back to the server, it just doesn't send, it get's stored in the buffer array of destination object of websocket observable (screenshot below). I am sharing the snippet of the code also.
import { webSocket } from 'rxjs/webSocket';
const subject = webSocket('ws://localhost:8081');
subject.subscribe({
next: msg => console.log('message received: ' + msg),
error: err => console.log(err),
complete: () => console.log('complete')
});
// Upon clicking a button I send this to the sever. You can see it in the screenshot.
subject.next({
"action" : "read",
"id" : 1595
});
My connection remains active though. It doesn't gets closed but still I am facing this issue. What could be the issue with this? Is it something with the backend ? If yes, then what could it be ? Any help will be appreciated. Thank you. :)
It seems that the problem is in your websocket server, but to be sure try instead to connect to a test server like the echo server of Postman:
wss://ws.postman-echo.com/raw
In each time the client sends a message to this server it will send it back to the client directly.
By the way: Postman now has the possibility yo to connect to your websocket server and test it.
Here you can read how to do that:
https://blog.postman.com/postman-supports-websocket-apis/
I wrote a program in c++ to upgrade an HTTP session to a WebSocket. The server correctly receives the upgrade request, and responds with 101 switching protocols. Firefox receives the 101 response, but in the console claims it couldn't connect. Here's the full output in Firefox.
The interesting thing is, in the network tab you can see the 101 response come in so it did establish an HTTP connection, the server got it, accepted it, tried to upgrade, and sent an upgrade response, but it's at that point that firefox doesn't upgrade to a WebSocket and prints the error.
I tried in Google Chrome as well. Similar error, but a bit more detail. WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
My code c++ hangs on the while loop, no errors thrown, which I think means it thinks the connection is still working?
I did notice it's sending Sec-Websocket-Protocol, even though I only asked for ws, not wss. Do chrome and firefox disallow non secure websockets? Or am I missing something in my code?
C++:
#define PORT (unsigned short) 3000
#define MAX_BUF 2048
int main()
{
Poco::Net::ServerSocket x(PORT);
Poco::Timespan timeout(25000000);
if (x.poll(timeout, 1)) {
Poco::Net::StreamSocket ss = x.acceptConnection();
Poco::AutoPtr<Poco::Net::HTTPServerParams> params = new Poco::Net::HTTPServerParams();
Poco::Net::HTTPServerSession sess(ss,params);
Poco::Net::HTTPServerResponseImpl res(sess);
Poco::Net::HTTPServerRequestImpl req(res, sess, params);
if (req.getMethod()=="GET" && req.get("Upgrade")=="websocket") {
Poco::Net::WebSocket webSock(req,res);
while (!webSock.available());
char buf[MAX_BUF];
memset(buf,0,MAX_BUF);
int flags = 0;
webSock.sendFrame("Hello, World!\n",15);
webSock.receiveFrame(buf,MAX_BUF,flags);
printf("received %s\n",buf);
}
}
else {
printf("Timeout!\n");
}
return 0;
}
Javascript:
$(document).ready(function() {
webSoc = new WebSocket("ws://localhost:3000");
webSoc.onopen = function (event) {
$("#c").click(function () {
console.log("Sending 'Hello, World!'");
webSoc.send("Hello, World!\n");
});
}
});
I've tried new WebSocket("ws://localhost:3000") with and without the echo-protocol parameter, because I read it in an answer to a question I didn't understand, which I can't find now.
I've created a pretty straight forward Java websocket and I'm trying to put it to the test in our test environment. On my local machine, the websocket opens seamlessly, stays with the readystate code '1' and all seems to work well.
On my test machine however, even though the socket appears to open, I still check the readystate and it gives the code '1', the upgrade from Https to websocket happens in the network tab, the OnOpen function in my Java code doesn't seem to get triggered ( I'm trying to log the userId that's coming with the new connection on socket open and that doesn't show either in my test environment logs. On my local machine, that works as well)
private static final ArrayList<Session> connectedSessions = new ArrayList<>();
#OnClose
public void closeSession(Session session) {
try {
connectedSessions.remove(session);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
#OnMessage
public void onMessage(String message, final Session session) {
broadcastMessage(message, session);
}
#OnOpen
public void openSession(#PathParam("userId") String userId, Session session) {
try {
session.getUserProperties().put("USER_ID", userId);
connectedSessions.add(session);
LOGGER.info("-------- Connection id ---------" + userId);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
On the front end I'm using angular, but no other websocket framework, just plain javascript, and for my backend I'm running Xframe 2.2 with Websphere application server 9.0. I'm sure I'm calling the right endpoint since it works on my local machine and I've tested it multiple times with multiple sessions.
EDIT: adding the angular code below
this.ws= new WebSocket("wss://" + env.websocketUrl + "socket" + this.context.settings.userId);
this.ws.onmessage = (event) => {
this.update(event.data, this.context.settings.userId);
};
doSomething(data) {
this.ws.send(data);
}
The thing to note is that the message gets sent. I checked the frames of the WS, but I get no response. It stays "pending"
Can be closed. Turns out my company is blocking any http2 calls that runs on our test/prod servers. It's why websockets were working on my local machine.
So I am trying to make some sort of connection between my Java app and my Web app, I looked up websockets and they look really simple and easy to use :). And I created myself a Java Server, which uses the ServerSocket class.
Now the problem is I am able to connect to the server from the web, with the websocket, but I am unable to send data to the server... but when I tried to send data from a Java Client it worked fine... what might be the problem?
My Java/Scala (I followed this tutorial: https://www.tutorialspoint.com/java/java_networking.htm) server:
class Server(val port: Int) extends Thread {
private val serverSocket = new ServerSocket(port)
override def run(): Unit = {
try {
while(true) {
println("Waiting for client on port: " + serverSocket.getLocalPort)
val server = serverSocket.accept()
println(server.getRemoteSocketAddress)
val in = new DataInputStream(server.getInputStream())
println(in.readUTF())
val out = new DataOutputStream(server.getOutputStream())
out.writeUTF("Hello world!")
server.close()
}
} catch {
case s: SocketTimeoutException => println("Connection timed out!");
case e: Exception => e.printStackTrace()
}
}
}
My web js (I followed https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications ):
/**
* Created by samuelkodytek on 20/12/2016.
*/
var conn = new WebSocket('ws://127.0.0.1:8080');
conn.onopen = function(e) {
console.log("Connection established!");
conn.send("Hello!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
A web socket server is not the same thing as a simple socket server. A server that offers web sockets must first offer HTTP or HTTPS services because the web socket is established when a web client sends an HTTP request with an Upgrade option and special fields for establishing the web socket. Even after the web socket is established, the connection still does not behave exactly like a regular socket. The Web Socket protocol uses frames to send or receive data. This is all considerably different from what you seem to expect.
One other thing that you should be aware of is that the browser will enforce the rule that the web socket must come from the same host as the page that is attempting to establish the web socket (the same protocol, address, and TCP port).
Is it possible to programmatically check if a WebSocket connection failed with a 403 response? For instance, with the following server code:
package main
import (
"errors"
"io"
"log"
"net/http"
"golang.org/x/net/websocket"
)
func main() {
handler := websocket.Handler(func(ws *websocket.Conn) {
io.Copy(ws, ws)
})
handshake := func(conf *websocket.Config, req *http.Request) error {
if req.URL.Path == "/sekret" {
return nil
}
return errors.New("Oops!")
}
server := &websocket.Server{
Handshake: handshake,
Handler: handler,
}
log.Fatal(http.ListenAndServe(":8080", server))
}
And the following sample JS connection that triggers a 403 response:
var ws = new WebSocket("ws://localhost:8080/something");
ws.onerror = console.log;
The error response is an Event with type "error". On the other hand, the following JS code triggers a net::ERR_CONNECTION_REFUSED (at least on Chrome):
var ws = new WebSocket("ws://localhost:8081/something");
ws.onerror = console.log;
The error event object looks almost exactly the same. Is there some way to distinguish error types in WebSocket connections from the client side? (I'm specifically looking for 403 responses, so I can alert the user to take special action.)
Apparently it's deliberate:
My understanding is that for security reasons, WebSocket error statuses are fairly restricted to limit the ability of malicious JS to probe an internal network.