Ubuntu TCP打孔过程中的EADDR重用错误
我正在尝试实现TCP打孔。客户端使用服务器交换公共/私有ip详细信息。所有的实现都是在Ubuntu 20.04上完成的。客户端A和客户端B位于不同的NAT后面,服务器位于公共ip上 客户端A代码:Ubuntu TCP打孔过程中的EADDR重用错误,ubuntu,web,networking,tcp,hole-punching,Ubuntu,Web,Networking,Tcp,Hole Punching,我正在尝试实现TCP打孔。客户端使用服务器交换公共/私有ip详细信息。所有的实现都是在Ubuntu 20.04上完成的。客户端A和客户端B位于不同的NAT后面,服务器位于公共ip上 客户端A代码: var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); var addressOfS = 'x.x
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var addressOfS = 'x.x.x.x'; // replace this with the IP of the server running publicserver.js
var portOfS = 9999;
var socketToS;
var tunnelEstablished = false;
function connectToS () {
console.log('> (A->S) connecting to S');
socketToS = require('net').createConnection({host : addressOfS, port : portOfS}, function () {
console.log('> (A->S) connected to S via', socketToS.localAddress, socketToS.localPort);
// letting local address and port know to S so it can be can be sent to client B:
socketToS.write(JSON.stringify({
name: 'A',
localAddress: socketToS.localAddress,
localPort: socketToS.localPort
}));
});
socketToS.on('data', function (data) {
console.log('> (A->S) response from S:', data.toString());
var connectionDetails = JSON.parse(data.toString());
if(connectionDetails.name == 'A') {
// own connection details, only used to display the connection to the server in console:
console.log("");
console.log('> (A)', socketToS.localAddress + ':' + socketToS.localPort, '===> (NAT of A)', connectionDetails.remoteAddress + ':' + connectionDetails.remotePort, '===> (S)', socketToS.remoteAddress + ':' + socketToS.remotePort);
console.log("");
}
if(connectionDetails.name == 'B') {
console.log('> (A) time to listen on port used to connect to S ('+socketToS.localPort+')');
listen(socketToS.localAddress, socketToS.localPort);
// try connecting to B directly:
connectTo(connectionDetails.remoteAddress, connectionDetails.remotePort);
}
});
socketToS.on('end', function () {
console.log('> (A->S) connection closed.');
});
socketToS.on('error', function (err) {
console.log('> (A->S) connection closed with err:', err.code);
});
}
connectToS();
function connectTo (ip, port) {
if(tunnelEstablished) return;
console.log('> (A->B) connecting to B: ===> (B)', ip + ":" + port);
var c = require('net').createConnection({host : ip, port : port}, function () {
console.log('> (A->B) Connected to B via', ip + ":" + port);
tunnelEstablished = true;
});
c.on('data', function (data) {
console.log('> (A->B) data from B:', data.toString());
});
c.on('end', function () {
console.log('> (A->B) connection closed.');
});
c.on('error', function (err) {
console.log('> (A->B) connection closed with err:', err.code);
setTimeout(function () {
connectTo(ip, port);
},500);
});
}
var tunnelSocket = null;
function listen (ip, port) {
var server = require('net').createServer(function (socket) {
tunnelSocket = socket;
console.log('> (A) someone connected, it\s:', socket.remoteAddress, socket.remotePort);
socket.write("Hello there NAT traversal man, you are connected to A!");
tunnelEstablished = true;
readStuffFromCommandLineAndSendToB();
});
server.listen(port, ip, function (err) {
if(err) return console.log(err);
console.log('> (A) listening on ', ip + ":" + port);
});
}
function readStuffFromCommandLineAndSendToB () {
if(!tunnelSocket) return;
rl.question('Say something to B:', function (stuff) {
tunnelSocket.write(stuff);
readStuffFromCommandLineAndSendToB();
});
}
客户B代码:
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// based on http://www.bford.info/pub/net/p2pnat/index.html
var addressOfS = 'x.x.x.x'; // replace this with the IP of the server running publicserver.js
var portOfS = 9999;
var socketToS;
var tunnelEstablished = false;
function connectToS () {
console.log('> (B->S) connecting to S');
socketToS = require('net').createConnection({host : addressOfS, port : portOfS}, function () {
console.log('> (B->S) connected to S via', socketToS.localAddress, socketToS.localPort);
// letting local address and port know to S so it can be can be sent to client A:
socketToS.write(JSON.stringify({
name: 'B',
localAddress: socketToS.localAddress,
localPort: socketToS.localPort
}));
});
socketToS.on('data', function (data) {
console.log('> (B->S) response from S:', data.toString());
var connectionDetails = JSON.parse(data.toString());
if(connectionDetails.name == 'B') {
// own connection details, only used to display the connection to the server in console:
console.log("");
console.log('> (B)', socketToS.localAddress + ':' + socketToS.localPort, '===> (NAT of B)', connectionDetails.remoteAddress + ':' + connectionDetails.remotePort, '===> (S)', socketToS.remoteAddress + ':' + socketToS.remotePort);
console.log("");
}
if(connectionDetails.name == 'A') {
console.log('> (B) time to listen on port used to connect to S ('+socketToS.localPort+')');
listen(socketToS.localAddress, socketToS.localPort);
// try connecting to A directly:
connectTo(connectionDetails.remoteAddress, connectionDetails.remotePort);
}
});
socketToS.on('end', function () {
console.log('> (B->S) connection closed.');
});
socketToS.on('error', function (err) {
console.log('> (B->S) connection closed with err:', err.code);
});
}
connectToS();
function connectTo (ip, port) {
if(tunnelEstablished) return;
console.log('> (B->A) connecting to A: ===> (A)', ip + ":" + port);
var c = require('net').createConnection({host : ip, port : port}, function () {
console.log('> (B->A) Connected to A via', ip + ":" + port);
tunnelEstablished = true;
});
c.on('data', function (data) {
console.log('> (B->A) data from A:', data.toString());
});
c.on('end', function () {
console.log('> (B->A) connection closed.');
});
c.on('error', function (err) {
console.log('> (B->A) connection closed with err:', err.code);
setTimeout(function () {
connectTo(ip, port);
},500);
});
}
var tunnelSocket = null;
function listen (ip, port) {
var server = require('net').createServer(function (socket) {
tunnelSocket = socket;
console.log('> (B) someone connected, it\s:', socket.remoteAddress, socket.remotePort);
socket.write("Hello there NAT traversal man, you are connected to B!");
tunnelEstablished = true;
readStuffFromCommandLineAndSendToA();
});
server.listen(port, ip, function (err) {
if(err) return console.log(err);
console.log('> (B) listening on ', ip + ":" + port);
});
}
function readStuffFromCommandLineAndSendToA () {
if(!tunnelSocket) return;
rl.question('Say something to A:', function (stuff) {
tunnelSocket.write(stuff);
readStuffFromCommandLineAndSendToA();
});
}
服务器代码
var socketA = null;
var socketB = null;
var detailsA = {
name: 'A',
localAddress: null,
localPort: null,
remoteAddress: null,
remotePort: null
};
var detailsB = {
name: 'B',
localAddress: null,
localPort: null,
remoteAddress: null,
remotePort: null
};
// assuming A will connect first:
var server = require('net').createServer(function (socket) {
if(!socketA) {
aConnects(socket);
}else{
bConnects(socket);
}
});
server.listen(9999, function (err) {
if(err) return console.log(err);
console.log('server listening on', server.address().address + ':' + server.address().port);
});
function aConnects (socket) {
socketA = socket;
console.log('> (A) assuming A is connecting');
console.log('> (A) remote address and port are:', socket.remoteAddress, socket.remotePort);
console.log('> (A) storing this for when B connects');
detailsA.remoteAddress = socket.remoteAddress;
detailsA.remotePort = socket.remotePort;
socket.on('data', function (data) {
console.log('> (A) incoming data from A:', data.toString());
var localDataA = JSON.parse(data.toString());
if(!localDataA.name || localDataA.name != 'A') return console.log('> (A) this is not the local data of A');
console.log('> (A) storing this for when B connects');
console.log('');
detailsA.localAddress = localDataA.localAddress;
detailsA.localPort = localDataA.localPort;
console.log('> (A) sending remote details back to A');
socket.write(JSON.stringify(detailsA));
console.log('> (A)', detailsA.localAddress + ':' + detailsA.localPort, '===> (NAT of A)', detailsA.remoteAddress + ':' + detailsA.remotePort, '===> (S)', socket.localAddress + ':' + socket.localPort);
});
socket.on('end', function () {
console.log('> (A) connection closed.');
socketA = null;
});
socket.on('error', function (err) {
console.log('> (A) connection closed with err (',err,').');
socketA = null;
});
}
function bConnects(socket) {
socketB = socket;
console.log('> (B) assuming B is connecting');
console.log('> (B) remote address and port are:', socket.remoteAddress, socket.remotePort);
console.log('> (B) storing this');
detailsB.remoteAddress = socket.remoteAddress;
detailsB.remotePort = socket.remotePort;
socket.on('data', function (data) {
console.log('> (B) incoming data from B:', data.toString());
var localDataB = JSON.parse(data.toString());
if(!localDataB.name || localDataB.name != 'B') return console.log('> (B) this is not the local data of B');
console.log('> (B) storing this');
console.log('');
detailsB.localAddress = localDataB.localAddress;
detailsB.localPort = localDataB.localPort;
console.log('> (B) sending remote details back to B');
socket.write(JSON.stringify(detailsB));
console.log('> (B)', detailsB.localAddress + ':' + detailsB.localPort, '===> (NAT of B)', detailsB.remoteAddress + ':' + detailsB.remotePort, '===> (S)', socket.localAddress + ':' + socket.localPort);
console.log('> (S->A) sending B\'s details:', detailsB);
socketA.write(JSON.stringify(detailsB));
console.log('> (S->B) sending A\'s details:', detailsA);
socketB.write(JSON.stringify(detailsA));
console.log('');
});
socket.on('end', function () {
console.log('> (B) connection closed.');
socketB = null;
});
socket.on('error', function (err) {
console.log('> (B) connection closed with err (',err,').');
socketB = null;
});
}
服务器详细信息
客户A
客户B