Non-http TCP connection on Cloudfoundry

2019-02-19 00:28发布

I'm a nooby mobile developer trying to take advantage of cloudfoundry's service to run my server to handle some chats and character movements. I'm using Noobhub to achieve this (TCP connection between server and client using Node.js and Corona SDK's TCP connection API)

So basically I'm trying a non-http TCP connection between Cloudfoundry(Node.js) and my machine(lua).

Link to Noobhub(There is a github repo with server AND client side implementation.

I am doing

Client

...
socket.connect("myappname.cloudfoundry.com", 45234)
...

(45234 is from server's process.env.VCAP_APP_PORT value I retrieved from console output I got through "vmc logs myappname" after running the application.)

Server

...
server.listen(process.env.VCAP_APP_PORT)

When I try to connect, it just times out.

On my local machine, doing Client

...
socket.connect("localhost",8989)

Server

...
server.listen(8989)

works as expected. It's just on cloudfoundry that it doesn't work.

I tried a bunch of other ways of doing this such as setting the client's port connection to 80 and a bunch of others. I saw a few resources but none of them solved it. I usually blow at asking questions so if you need more information, please ask me!

P.S.

Before you throw this link at me with an angry face D:< , here's a question that shows a similar problem that another person posted.

cannot connect to TCP server on CloudFoundry (localhost node.js works fine)

From here, I can see that this guy was trying to do a similar thing I was doing. Does the selected answer mean that I MUST use host header (i.e. use http protocol) to connect? Does that also mean cloudfoundry will not support a "TRUE" TCP socket much like heroku or app fog?

2条回答
老娘就宠你
2楼-- · 2019-02-19 00:58

"Cloud Foundry uses an L7 router (ngnix) between clients and apps. The router needs to parse HTTP before it can route requests to apps. This approach does not work for non-HTTP protocols like WebSockets. Folks running node.js are going to run into this issue but there are no easy fixes in the current architecture of Cloud Foundry." - http://www.subbu.org/blog/2012/03/my-gripes-with-cloud-foundry

I decided to go with pubnub for all my messaging needs.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-02-19 01:14

Actually, process.env.VCAP_APP_PORT environment variable provides you the port, to which your HTTP traffic is redirected by the Cloud Foundry L7 router (nginx) based on the your apps route (e.g. nodejsapp.vcap.me:80 is redirected to the process.env.VCAP_APP_PORT port on the virtual machine), so you definitely should not use it for the TCP connection. This port should be used to listen HTTP traffic. That is why you example do work locally and do not work on Cloud Foundry.

The approach that worked for me is to listen to the port provided by CF with an HTTP server and then attach Websocket server (websocket.io in my example below) to it. I've created sample echo server that works both locally and in the CF. The content of my Node.js file named example.js is

var host = process.env.VCAP_APP_HOST || "localhost";
var port = process.env.VCAP_APP_PORT || 1245;

var webServerApp = require("http").createServer(webServerHandler);  
var websocket = require("websocket.io");
var http = webServerApp.listen(port, host);
var webSocketServer = websocket.attach(http);

function webServerHandler (req, res) {
    res.writeHead(200);
    res.end("Node.js websockets.");
}
console.log("Web server running at " + host + ":" + port);

//Web Socket part
webSocketServer.on("connection", function (socket) {
    console.log("Connection established."); 

    socket.send("Hi from webSocketServer on connect");

    socket.on("message", function (message) { 
        console.log("Message to echo: " + message);
        //Echo back
        socket.send(message);
    });

    socket.on("error", function(error){
        console.log("Error: " + error);
    });

    socket.on("close", function () { console.log("Connection closed."); });
});

The dependency lib websocket.io could be installed running npm install websocket.io command in the same directory. Also there is a manifest.yml file which describes CF deploy arguments:

---
applications:
- name: websocket
  command: node example.js
  memory: 128M
  instances: 1
  host: websocket
  domain: vcap.me
  path: .

So, running cf push from this directory deployed app to my local CFv2 instance (set up with the help of cf_nise_installer) To test this echo websocket server, I used simple index.html file, which connects to server and sends messages (everything is logged into the console):

<!DOCTYPE html>
    <head>
        <script>        
        var socket = null;
        var pingData = 1;
        var prefix = "ws://";

        function connect(){
            socket = new WebSocket(prefix + document.getElementById("websocket_url").value);
            socket.onopen = function() { 
                console.log("Connection established"); 
            };
            socket.onclose = function(event) { 
                if (event.wasClean) {
                    console.log("Connection closed clean");
                } else {
                    console.log("Connection aborted (e.g. server process killed)");
                }
                    console.log("Code: " + event.code + " reason: " + event.reason);
                };             
            socket.onmessage = function(event) { 
                console.log("Data received:  " + event.data);
            };
            socket.onerror = function(error) { 
                console.log("Error: " + error.message);               
            };
        }        
        function ping(){
            if( !socket || (socket.readyState != WebSocket.OPEN)){
                console.log("Websocket connection not establihed");
                return;
            }            
            socket.send(pingData++);
        }        
        </script>
    </head>
    <body>
        ws://<input id="websocket_url">
        <button onclick="connect()">connect</button>
        <button onclick="ping()">ping</button>
    </body>
</html>

Only thing to do left is to enter server address into the textbox of the Index page (websocket.vcap.me in my case), press Connect button and we have working Websocket connection over TCP which could be tested by sending Ping and receiving echo. That worked well in Chrome, however there were some issues with IE 10 and Firefox.

What about "TRUE" TCP socket, there is no exact info: according to the last paragraph here you cannot use any port except 80 and 443 (HTTP and HTTPS) to communicate with your app from outside of Cloud Foundry, which makes me think TCP socket cannot be implemented. However, according to this answer, you can actually use any other port... It seems that some deep investigation on this question is required...

查看更多
登录 后发表回答