NodeJS:TCP 套接字服务器只在第一次返回数据 [英] NodeJS: TCP socket server only returns data the first time

查看:30
本文介绍了NodeJS:TCP 套接字服务器只在第一次返回数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 node.js 中编写一个小型中继脚本,用于侦听本地套接字上的传入 TCP 连接,并在收到连接时将流量转发给第 3 方.它还必须从第 3 方获取任何返回的数据并将其发送回原始本地套接字.我试过像 http 之类的代码://delog.wordpress.com/2011/07/19/a-tcp-relay-mechanism-with-node-js/ 它确实有效,但它要求发送方是一个正在侦听socket 本身,我的实用程序旨在与任何尝试创建出站 TCP 连接的程序一起使用.不幸的是,我遇到的问题是第一次一切正常,客户端将数据发送到路由器"程序,路由器将其转发到另一台服务器,然后从客户端返回数据.但是,当客户端程序结束或终止并尝试重新连接时,我得到了:

I'm attempting to write a small relay script in node.js that listens for incoming TCP connections on a local socket, and when it gets one, forwards the traffic to a 3rd party. It must also take any returned data from that 3rd party and send it back to the original local socket. I've tried code like http://delog.wordpress.com/2011/07/19/a-tcp-relay-mechanism-with-node-js/ and it does work, but it requires the sender be a server that is listening on a socket itself, and my utility is intended to work with any program that tries to create an outbound TCP connection. Unfortunately, the problem I'm running into is that everything works great the first time with the client sending the data to the "router" program, and the router forwarding it to another server, and then returning the data from the client. However, when the client program ends or is terminated and attempts to reconnect, I get this:

events.js:72
    throw er; // Unhandled 'error' event
          ^
Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:275:12)
at Socket.<anonymous> (/root/tcp_loop.js:37:17)
at Socket.emit (events.js:117:20)
at Socket.<anonymous> (_stream_readable.js:748:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:410:10)
at emitReadable (_stream_readable.js:406:5)
at readableAddChunk (_stream_readable.js:168:9)
at Socket.Readable.push (_stream_readable.js:130:10)
at TCP.onread (net.js:528:21)

我撕掉了所有的逻辑并将测试用例提炼成一小段代码:一个既充当路由器(侦听端口 8124)又充当远程"服务器(端口 9999)的服务器,尽管我的测试表明远程服务器在同一台机器上,在互联网上等情况下没有区别.这是服务器代码:

I ripped out all of the logic and distilled the test case into a small bit of code: one server that acts as both the router (listening on port 8124) as well as the "remote" server (on port 9999), though my testing indicates it makes no difference weather the remote server is on the same machine, on the Internet, etc. Here is the server code:

var net = require('net'),
    util = require('util')
;

// The loop_server simulates a remote service.
// The error occurs whether using it here, or actually forwarding
// the data to a remote host.
var loop_server = net.createServer(function(loop) {
    console.log("Loop server connected");
    loop.on("end", function() {
        console.log("Loop server disconnected");
    });
    loop.on("data", function(data) {
        console.log("Loop got data: " + data);
        loop.write(data);
    });
}).listen(9999, function() {
    console.log("Loop server bound");
});

var remote_socket = net.connect(9999, function() {
    console.log("Remote connected");

    var local_server = net.createServer(function(local_socket) { //'connection' listener
        console.log('Local server connected');
        local_socket.on('end', function() {
            console.log('Local server disconnected');
            // local_socket.destroy();
        });

        local_socket.on('data', function(ldata) {
            console.log("Local socket got data: " + ldata);
            remote_socket.write(ldata);
        });

        remote_socket.on('data', function(rdata) {
            console.log("Remote socket got data: " + rdata);
            local_socket.write(rdata);
        });

        local_socket.write('hello\r\n');
    }).listen(8124, function() { //'listening' listener
        console.log('Local server bound');
    });
}); // remote_socket

失败的是remote_socket.on('data', ...处理程序中的local_socket.write(rdata);.它第一次工作路由器启动,客户端连接,但不再连接.

The thing that's failing is the local_socket.write(rdata); in the remote_socket.on('data', ... handler. It works the first time the router is started and the client connects, but never again.

作为参考,这里是我一直在使用的小客户端应用程序的代码.我使用 perl 脚本、telnet 等得到相同的结果:

For reference, here is the code for the little client app that I've been using. I get the same result with a perl script, telnet, etc.:

var net = require('net');

var client = new net.Socket();
client.connect(8124, function() {
    console.log('CONNECTED TO: localhost:8124');
    client.write('Single text message from the client app');
});

client.on('data', function(data) {
    console.log('DATA: ' + data);
});

client.on('close', function() {
    sconsole.log('Connection closed');
});

任何见解将不胜感激.我觉得我一定在这里遗漏了一些非常简单的东西......

Any insight would be greatly appreciated. I feel like I must be missing something extremely simple here...

更新:

下面的 Nitzin 解决方案是一种更好的方法,但在我下面的特定示例中,解决方案是在创建新侦听器之前删除旧的 remote_socket.on('data') 侦听器,例如:

Nitzin's solution below is a better way to do this, but in my particular example below, the solution is to remove old remote_socket.on('data') listeners before creating new ones, e.g.:

var remote_socket = net.connect(9999, function() {
    console.log("Remote connected");

    var local_server = net.createServer(function(local_socket) { //'connection' listener
        console.log('Local server connected');

        remote_socket.removeAllListeners('data');

        ...

        remote_socket.on('data', function(rdata) {
            console.log("Remote socket got data: " + rdata);
            local_socket.write(rdata);
        });

推荐答案

你不应该破坏套接字.它关闭套接字的两端.你应该只 .end() 它,它关闭你的写作结束.

You should not destroy the socket. It closes both ends of the socket. You should only .end() it, which closes your writing end.

编辑

正如我最初写的那样,破坏套接字很糟糕,但你真正的问题是完全不同的:你的代理(你称之为本地")和回声(你称之为远程")服务器向后:proxy 服务器应该为代理服务器获得的每个新连接建立一个到 echo 服务器的新连接,而不是像您现在拥有的那样.

Destroying the socket is bad, as I originally wrote, but your real problem is something completely different: you got your proxy (what you call "local") and echo (what you call "remote") servers backwards: the proxy server should make a new connection to the echo server for each new connection the proxy server gets, not the other way around as you have it now.

唯一需要的 end() 在客户端,让服务器知道你已经写完了.

The only end() needed is in the client, to let the server know you're done writing.

这是client.js:

var net = require('net');

var client = new net.Socket();

client.connect(8124, function() {
    console.log('CLIENT: CONNECTED: localhost:8124');
    client.write('single text message from the client app');
    client.end();
});

client.on('data', function(data) {
    console.log('CLIENT: GOT DATA: ' + data);
});

client.on('close', function() {
    console.log('CLIENT: CONNECTION CLOSED');
});

这里是servers.js:

var net = require('net'),
    util = require('util');

net.createServer(function(conn) {
    console.log('ECHO_SERVER: CONN: new connection');
    conn.on('end', function() {
        console.log('ECHO_SERVER: CONN: disconnected');
    });
    conn.on('data', function(data) {
        console.log('ECHO_SERVER: CONN: GOT DATA: ' + data);
        conn.write(data);
    });
}).listen(9999, function() {
    console.log('ECHO_SERVER STARTED');
});

net.createServer(function(conn) {

    console.log('PROXY_SERVER: CONN: new connection');

    var remote = net.connect(9999, function() {
        console.log('PROXY_SERVER: CONNECTED TO ECHO_SERVER');
        conn.on('end', function() {
            console.log('PROXY_SERVER: CONN: disconnected');
            remote.end();
        });
        conn.on('data', function(data) {
            console.log('PROXY_SERVER: CONN: GOT DATA FOR  ECHO_SERVER: ' + data);
            remote.write(data);
        });
        remote.on('data', function(data) {
            console.log('PROXY_SERVER: CONN: GOT DATA FROM ECHO_SERVER: ' + data);
            conn.write(data);
        });
    });

}).listen(8124, function() {
    console.log('PROXY_SERVER STARTED');
});

如您所见,对于到代理服务器的每个 conn,都会有一个新的 remote 进入回显服务器.

As you can see, for each conn to the proxy server, there is a new remote going to the echo server.

这篇关于NodeJS:TCP 套接字服务器只在第一次返回数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆