Commit 7d5ae443 authored by 神楽坂玲奈's avatar 神楽坂玲奈

test

parent 688ab046
/.idea/
\ No newline at end of file
/.idea/
/node_modules/
{
"server_address": "127.0.0.1",
"server_port": 9999,
"port": 9998,
"server_port": 500,
"port": 495,
"timeout": 10,
"interval": 1000
"interval": 1000,
"table": 1,
"proto": 250
}
[
{
"id": 1,
"address": "10.198.0.1",
"interface": "mc-yangtze",
"subnets": [
"192.168.1.0/24",
"10.198.1.0/24",
"10.198.2.0/24"
]
},
{
"id": 3,
"address": "10.198.0.3",
"interface": "mc-south",
"subnets": [
"10.198.3.0/24"
]
},
{
"id": 7,
"address": "10.198.0.7",
"interface": "mc-fractal",
"subnets": [
"10.198.7.0/24"
]
},
{
"id": 9,
"address": "10.198.0.9",
"interface": "mc-marcia",
"subnets": [
"10.198.9.0/24"
]
}
]
This diff is collapsed.
{
"name": "railgun-network-client",
"version": "1.0.0",
"description": "",
"name": "railgun-routing-client",
"version": "0.0.1",
"author": "zh99998 <zh99998@gmail.com>",
"scripts": {
"start": "ts-node src/main.ts"
},
"main": "index.js",
"devDependencies": {
"@types/node": "^14.14.14",
"ts-node": "^9.1.1"
"@types/node": "^16.6.1",
"ts-node": "^10.2.0",
"typescript": "^4.3.5"
}
}
{
"id": 3,
"peers": [
{
"id": 23,
"address": "10.200.23.3",
"subnets": ["10.198.0.25"],
"mark": 18003
}
]
}
// 这个文件两端共用
export interface PeerQuality {
delay: number;
jitter: number;
reliability: number;
}
// 路由器向中心服务器发送的消息
export interface UploadMessage {
id: number; // router id
ack: number;
peers?: Record<number, PeerQuality>;
}
// 中心服务器向路由器发送的消息
export interface DownloadMessage {
seq: number,
to: number,
nextHop: number;
}
// 路由器向路由器发送的消息
export interface PeerMessage {
id: number;
seq: number;
time: number;
}
import config from '../config.json';
import { Socket } from 'dgram';
import { PeerMeasure } from './protocol';
import { PeerMessage, PeerQuality } from '../protocol';
export interface PeerHello {
id: number;
seq: number;
time: number;
}
export interface PeerConfig {
export interface RouterConfig {
id: number;
address: string;
subnets: string[];
}
export class Peer implements PeerHello, PeerMeasure, PeerConfig {
export class Peer implements PeerMessage, PeerQuality, RouterConfig {
id: number;
address: string;
subnets: string[];
delay: number = 0;
jitter: number = 0;
reliability: number = 0;
seq: number = 0;
time: number = 0;
constructor(config: PeerConfig) {
constructor(config: RouterConfig) {
Object.assign(this, config);
}
......@@ -37,7 +29,7 @@ export class Peer implements PeerHello, PeerMeasure, PeerConfig {
this.time = 0;
}
onMessage(data: PeerHello) {
onMessage(data: PeerMessage) {
if (data.seq == 0 || data.seq < this.seq - config.timeout || data.seq > this.seq + config.timeout) {
// 收到 seq = 0 或 seq 与之前差距较大,就 reset
this.reset();
......@@ -57,23 +49,14 @@ export class Peer implements PeerHello, PeerMeasure, PeerConfig {
this.time = data.time;
}
update(socket: Socket, self: PeerHello) {
update(time: number) {
if (this.reliability == 0) {
return;
}
// 有几个包没到
const step = Math.floor((self.time - this.time + this.delay - config.interval) / config.interval);
const step = Math.floor((time - this.time + this.delay - config.interval) / config.interval);
if (step > config.timeout) {
this.reset();
return;
}
// if(self.time - this.time )
socket.send(JSON.stringify(self), config.port, this.address, (error, bytes) => error && console.warn(error));
}
// pickServer(): PeerMeasure {
// const { id, delay, reliability } = this;
// return { id, delay, reliability };
// }
}
import { Peer } from './Peer';
const tableOffset = 10000;
const groupTableOffset = 11000;
import config from '../config.json';
import routers from '../routers.json';
export class RouteWriter {
routes: Route[];
constructor() {}
reset() {
// TODO: 所有 neighbor 重设为直连,不是 neighbor 的设为 unreachable
// 只是记下来,commit的时候再写入
}
add(to: Peer, via: Peer) {
for (const subnet of to.subnets) {
this.routes.push({ to: subnet, via: via.address, table: 'main' });
static reset() {
console.log(`route flush table ${config.table} proto ${config.proto}`);
for (const peer of routers.filter(r => r.interface)) {
this.set(peer.id, peer.id);
}
this.routes.push({ to: 'default', via: via.address, table: tableOffset + to.id });
}
// groupAdd(to: Peer, via: Peer) {
// this.routes.push({ to: 'default', via: via.address, table: groupTableOffset + to.id });
// }
commit() {
// TODO: 写进系统,用 ip -batch
static set(toId: number, viaId: number) {
const to = routers.find(r => r.id == toId);
const via = routers.find(r => r.id == viaId);
for (const address of [to.address, ...to.subnets]) {
console.log(`route replace ${address} dev ${via.interface}`);
}
}
}
export interface Route {
to: string;
via: string;
table: number | string;
}
import { RouteWriter } from './RouteWriter';
import { Peer, PeerHello, PeerMeasure } from './Peer';
import { Socket } from 'dgram';
import config from '../config.json';
import { RouteWriter } from './RouteWriter';
import { Peer } from './Peer';
import { DownloadMessage, PeerMessage, PeerQuality, UploadMessage } from '../protocol';
export class Server {
ack = 0;
onMessage(data: ServerMessage, socket: Socket, self: PeerHello, peers: Map<number, Peer>) {
if (data.seq && this.ack != data.seq) {
onMessage(socket: Socket, message: DownloadMessage, self: PeerMessage) {
if (message.seq && this.ack != message.seq) {
return;
}
const routeWriter = new RouteWriter();
if (data.seq === 0) {
routeWriter.reset();
if (message.seq === 0) {
RouteWriter.reset();
}
for (const [to, via] of Object.entries(data.routes).map(([to, via]) => [peers.get(parseInt(to)), peers.get(via)])) {
routeWriter.add(to, via);
}
// for (const [to, via] of Object.entries(data.groups).map(([to, via]) => [peers.get(parseInt(to)), peers.get(via)])) {
// routeWriter.groupAdd(to, via);
// }
this.ack = data.seq + 1;
RouteWriter.set(message.to, message.nextHop);
this.ack = message.seq + 1;
const response: UploadMessage = {
id: self.id,
ack: this.ack
};
socket.send(
JSON.stringify({
id: self.id,
ack: this.ack,
}),
config.server_port,
config.server_address
);
socket.send(JSON.stringify(response), config.server_port, config.server_address);
}
update(socket: Socket, self: PeerHello, peers: Map<number, Peer>) {
const p: PeerMeasure[] = [];
update(socket: Socket, self: PeerMessage, peers: Peer[]) {
const p: Record<number, PeerQuality> = {};
for (const peer of peers.values()) {
for (const peer of peers) {
if (peer.reliability === 0) {
continue;
}
......@@ -52,15 +46,12 @@ export class Server {
const reliability = (peer.reliability * (config.timeout - step)) / config.timeout;
const { id, delay } = peer;
p.push({ id, delay, reliability });
// jitter 还没算
p[id] = { delay, jitter: 0, reliability };
}
socket.send(JSON.stringify({ id: self.id, ack: this.ack, peers: p }), config.server_port, config.server_address);
const message: UploadMessage = { id: self.id, ack: this.ack, peers: p };
socket.send(JSON.stringify(message), config.server_port, config.server_address);
}
}
export interface ServerMessage {
seq: number;
routes: { [to: number]: number };
groups: { [to: number]: number };
}
import dgram from 'dgram';
import assert from 'assert';
import { Peer, PeerHello } from './Peer';
import config from '../config.json';
import { Server, ServerMessage } from './Server';
import { id, peers as peersConfig } from '../peers.json';
import routers from '../routers.json';
import { Server } from './Server';
import { Peer } from './Peer';
import { DownloadMessage, PeerMessage } from '../protocol';
const self: PeerHello = { id, seq: 0, time: 0 };
const self: PeerMessage = { id: parseInt(process.env.RAILGUN_ID), seq: 0, time: 0 };
const server = new Server();
const peers = new Map<number, Peer>();
for (const peer of peersConfig) {
peers.set(peer.id, new Peer(peer));
}
const peers = routers.filter(r => r.id !== self.id && r.interface).map(r => new Peer(r));
const socket = dgram.createSocket('udp4');
socket.on('message', (msg, rinfo) => {
try {
if (rinfo.address == config.server_address && rinfo.port == config.server_port) {
// from server
const hello: ServerMessage = JSON.parse(msg.toString());
server.onMessage(hello, socket, self, peers);
} else {
// from client
const hello: PeerHello = JSON.parse(msg.toString());
assert.ok(hello.id);
const peer = peers.get(hello.id);
assert.ok(peer && rinfo.address == peer.address && rinfo.port == config.port);
peer.onMessage(hello);
const socket = dgram
.createSocket('udp4')
.on('listening', () => {
const address = socket.address();
console.log(`listening ${address.address}:${address.port}`);
})
.on('message', (msg, rinfo) => {
try {
if (rinfo.address == config.server_address && rinfo.port == config.server_port) {
// from server
const message: DownloadMessage = JSON.parse(msg.toString());
server.onMessage(socket, message, self);
} else {
// from client
const message: PeerMessage = JSON.parse(msg.toString());
assert(message.id);
const peer = peers.find(p => p.id === message.id);
assert(peer && rinfo.address == peer.address && rinfo.port == config.port);
peer.onMessage(message);
}
} catch (e) {
console.warn(e);
}
} catch (e) {
console.warn(e);
}
});
});
socket.on('listening', () => {
const address = socket.address();
console.log(`listening ${address.address}:${address.port}`);
});
socket.bind(config.port);
socket.bind(config.port, routers.find(r => r.id == self.id).address);
setInterval(() => {
self.time = Date.now();
for (const peer of peers.values()) {
peer.update(socket, self);
const message = JSON.stringify(self);
for (const peer of peers) {
peer.update(self.time);
socket.send(message, config.port, peer.address);
}
server.update(socket, self, peers);
self.seq++;
......
export interface PeerMeasure {
id: number;
delay: number;
reliability: number;
}
export interface ServerMessage {
id: number;
ack: number;
peers: PeerMeasure[];
}
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"target": "esnext",
"sourceMap": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"lib": []
},
"exclude": [
"node_modules"
]
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment