9.2 创建 UDPack 对象
在 2.3 连接握手 提到过,客户端和服务端创建 UDPack 对象时,需要一对公/私钥,本节将介绍如何通过程序自动生成。
生成公/私钥
const { generateKeyPairSync } = require('crypto')
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
})
console.debug(publicKey, privateKey)
程序控制台输出如下:
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAmTI5PMlbyhhO5GPJmiMFzK6elIVM6R5zjYrYb+NbfvL0yhPdQSPo
v16iQH1+zsyjVZ2YF+B4zZ7db927qJ352Uu4o0lDdxflVmzLOw23SaYyMw1zZUVm
gIFxhqGdiPIfetCAO6cXLvB3q6fXlJVMQVZ4YAskQn0X410LQwXeX1h62+imJzib
S7+Y6V+zNStkGfIbin0Rc17EsSzHcUOCyuY70kTmgN3ljCYaCcVCVvGaS8WHlmA0
IixBiWSh/E+Mlah+FBIjlpi3J6YMkihfIiD58lwO0fDgjKTjKP6ZSFM9zgwMRU6C
TzTC5evZI66A61CuMuvlM4a+n5UEKdV7HK+91C1i4pi2s4BR56d0/IgVNO39a6jQ
9RMMAr/fO7cCn4usolKYpH4WXEr5y/jkBvgkshg01gn0X38qwvbxsn6j1+fXF1RW
LgaS94G21IxBHjr6xvA96QqDjiiJQY/FiRfBjHPHmssa2wzUkKfYWYOJ0IMdhdk/
o1FP1ZALVcZLCBhKALKpktvNZdAX1RbI2fkvncwXItktJDkthc9ki4k3NpssjESg
13gLNM9Nd1v07q9A7jCr1Erxjt9voGmrwIpPkq1Qw8Z0kkEA+Fuhr9/LGfL4XgP/
cXoADIixYzvWX1WfuMn91af/kffQqpw/le9BF3fRQl0RY26ovElswVUCAwEAAQ==
-----END RSA PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
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
WABFbrhl+CvyVfbF2RtsY24jDdhmLn6rxBQci4sCggEANe4lLaQqSOeXQHwQkoVQ
rTfMB+dN3CmoazGeqmsaXTzMUq9quJM2z09ho/jNQFBG/3N5EQLk+Q3y3akmQF8l
25LvD6HtfVqSjQ1BUP1WuchYQiPtDj9vcQE7SxIEfwZ/aajZTaJalurIr3OoE2vl
2OEUHdv+06mZxi1VbP+aFrxsYRMmm0z2HCnFQx5idNsx4jTdzQCqzM5r9EQhMha9
dJLbek8MDVe01yDowkjGABVKW1CNW8nbCwwonQnZtN21c4inG0QCAjaV+Q37L9qX
yM2VfRzjnRKgHr1ck/zgzb92Iwhh6SJNFSruNSSSzJzrlV7NezvKSJeIjabJ+fUh
LwKCAQEAnj/yuTO4PxII5from4TFgQBLFZWhGDM37YrdfEAAWZAy4CLkZ/zjV+dI
/uEahzYvccACZ5LtJomPWu6R53CfvUXlY9n2se4cR9lYXcxeyor0+7SWBNbMg/fj
7dNy6tUtbsya+6eZVh4U3B32w/k2k9hMKKRpnpzw4kyT9bUr6+i0W5oi27Sefx7x
oVRkPSWTSxP6+RZ2JCPMHbu/EKKGncD+bYc8ExLJJ52hWFrFlaNmPopIeoEVVLeC
mZrs3mfGv/NHQIvpgOkMkVM4txWymeWlbU82eiCDIu1YKcoMg1210i3khKf9XdI7
zaa+e8jk4tqiK6e3ZOT0SHbnrImPHQ==
-----END PRIVATE KEY-----
分别是 PEM 格式的公钥和私钥,可以分别单独保存到公钥 pubkey.pem 和私钥 prikey.pem 文件中。后面创建 UDPack 对象时,需要传入文件路径。
创建服务端 UDPack 对象
let serverPort = 12345,
pubkey = fs.readFileSync(`${__dirname}/keys/pubkey.pem`),
prikey = fs.readFileSync(`${__dirname}/keys/prikey.pem`),
authToken = (token) => (token === 'ec670f20b06411ebbe1d23acebc27dbf')
const udpack = new UDPack({ port: serverPort, host: '0.0.0.0', pubkey, prikey, authToken })
可以看到,服务端需要传入 pubkey、prikey 及 authToken,authToken 是一个简单的自定义 token 认证函数,客户端握手时,必须提供值为 ec670f20b06411ebbe1d23acebc27dbf
的 token,才能连接服务端。
创建客户端 UDPack 对象
let localPort = 0,
pubkey = fs.readFileSync(`${__dirname}/keys/pubkey.pem`),
token = 'ec670f20b06411ebbe1d23acebc27dbf'
const udpack = new UDPack({ port: localPort, host: '0.0.0.0', pubkey, token })
可以看到,客户端需要传入 pubkey 和 token,token 必须传 ec670f20b06411ebbe1d23acebc27dbf
,port 传入 0 会随机生成一个端口号。
连接服务端
let serverAddr = '127.0.0.1',
serverPort = 12345
udpack.connect(serverPort, serverAddr, (err) => {
if (err) {
logger.error(err.message, err.stack)
} else {
logger.info('connect to server')
}
})
创建会话
udpack.on('session', (session) => {
session.on('goaway', (code) => {
udpack.connect(serverPort, serverAddr, (err) => {
if (err) {
logger.error(err.message, err.stack)
} else {
logger.info('connect to server again')
}
})
})
})
上述代码可获得创建后的 session 对象,并在 session 对象上注册了 goaway 处理函数,实现断线重连。因为后面通信主要依靠创建于 session 之上的 Stream 实现,所以这里没有过多的逻辑。