nodejs控制台传输、接收文件

我一边查官网文档一边写的,虽然有send方法,但不知道receive方法在哪,最终还是用emit。

ReceiveService.js

//功能:发送请求并接受文件、保存 
const io = require('socket.io-client');
socket = io('http://localhost:3000')
const fs = require('fs')

//绑定用户终端输入
const readline = require('readline');
const interface = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});
let count=0;

socket.on('recFile', function (data, filename) {
    count++;
    console.log('响应'+count, data)
    fs.writeFileSync('./Client/' + filename, data)
})
interface.on('line', function (input) {
    console.log('input',input)
    console.log('您请求了\'' + input + "\'文件。");

    socket.emit('fileReq', input)

})
interface.on('close', function () {
    console.log('程序已退出!')
})

FileServer.js

//功能:响应请求并发送文件
const fs = require('fs');


//建立web服务器
const app = require('http').createServer(handler)
app.listen(3000);
console.log(app)
const io = require('socket.io')(app)
function handler(req, res) {
    fs.readdir('./Server', function (err, files) {
        if (err) {
            console.log(err)
            res.end('err')
        }
        console.log(files)
        res.end('<meta charset="utf-8">你可以请求这些内容:' + files.toString())
    })
    //res.end('File Server')
}
let count=0;
io.on('connection', function (socket) {
    socket.on('fileReq', function (filename) {
        console.log(filename)
        fs.open('./Server/' + filename, 'r', function (err, fd) {
            if (err) {
                socket.emit('recFile', 'fail')
                return;
            } else {
                fs.stat('./Server/' + filename, function (err, stats) {
                    if (err) {
                        return;
                    }
                    console.log(stats.size)
                    let buf = new Buffer.alloc(stats.size);
                    fs.read(fd, buf, 0, buf.length, 0, function (err, bytes) {
                        console.log(fd)
                        count++;
                        console.log(count)
                        socket.emit('recFile', buf, filename);
                    })
                })

            }
        })

    })
})

Diffle-Hellman密钥交换

数学基础

计算离散对数很困难。

离散对数

素数n的本原根a满足,a的1次方到a的n-1次方 mod n结果不同并且对应1到n-1。(换句话说是1到p-1的置换序列)

对于y=a^x mod p,已知a、x、p计算y容易,但已知y、a、 p ,计算x困难,x被称为离散对数。

至于为什么困难,涉及到相应算法的时间复杂度。计算a的有限次方还行,但猜x的话,就需要遍历了。

算法

借助数学特性,现在我们公开y与a,也就是素数和它的本原根。

用户A随机选择一个秘密的Xa,作为x计算出Ya。用户B同理计算出Yb。

用户A通过计算Yb^Xa mod q产生密钥。用户B同理计算出密钥。

那么,这两个密钥是相同的。

为什么相同呢?毕竟Yb^Xa mod q=(a^Xb mod q)^Xa mod q,也就是a^(Xb*Xa)mod q。

上面的等式我试了一下成立,但还没有理解,先求个余数再乘n次方居然也可以保持结果相同,数学真有意思。

就这样,用户AB都自己随便凑了个数,得到了相同密钥,中间人监听也得不到有用信息。不过,如果中间人假冒A与B,同时拿两份密钥,DH算法一样可以被攻破。

对于踩Mbti捧大五人格的现象的评论

Low Low爆了 看了几篇批判Mbti的文章就开始胡言乱语。Mbti的科学性我没有发言权,但it works。即使测量会有不准确的情况,但分类的思想本身是没有问题的,只不过精度受限,准确度受限。我也发现Mbti不同时期测量结果可能不稳定,但大五人格也出现了不稳定的现象(仅针对我搜索到的16personalities和aspek网站测试题)。受限于条件无法给出统计学数据,但是踩Mbti捧大五人格的人,他们的行为很搞笑,说的话也可笑(可以自行去知乎搜索相关问题,我就不贴了)。我实在不懂,踩Mbti对他们有什么好处,即使是踩Mbti的文章,也不至于全盘否定,而踩Mbti的评论真是贻笑大方。

网络上一直有踩一个捧一个的现象,有的还用词激烈,这群人吃饱了没事干啊。

雅可比松弛法

有道题叫分析,那先了解下这种方法。

查阅了资料后初步得知这是一种通过矩阵迭代解方程组的方法。

给出如下方程:

a11*x1+a12*x2+a13*x3=b1

a21*x1+a22*x2+a23*x3=b2

a31*x1+a32*x2+a33*x3=b3

可以化成如下式子:

x1=(b1-a12*x2-a13*x3)/a11

x2=(b2-a21*x1-a23*x3)/a22

x3=(b3-a31*x1-a32*x2)/a33

我们先假设x1=0, x2=0, x3=0,代入式子右边:

x1=b1/a11

x2=b2/a22

x3=b3/a33

我们得到新的x1,x2,x3,于是我们可以继续将新的值代入方程,又得到新的x1,x2,x3,如此循环下去,X将会越来越接近准确值。

如果以矩阵的形式表示上述方程,即Ax=B。将A分成对角矩阵D,右上三角矩阵U,左下三角矩阵L。Ax=B转化为Dx=b+(L+U)x,继而转成x=b*D^(-1)+(L+U)x*D^(-1)

又由于DLUA都是已知量,可以把上式系数算出来,于是式子可以化简成x(k)=Tx(k-1)+c。

于是又可以令x=[0,0,....,0],然后迭代。

现在我明白这是怎么一回事了,但是刚才才看就挺懵的。

这篇博客以上部分是笔记,想具体了解该算法请左转https://www.cnblogs.com/gongxijun/p/10149337.html

MPI代码分析(书上的题,有些看不懂)

float Arow[N],X[N],NewX,B,error,Temp;//雅可比迭代法的输入应该是矩阵吧,那NewX和B是矩阵,Arow是N*N的矩阵,X是数组,至于error嘛,Allreduce里面用到了,作为recvAddress,大概理解成,如果error超过一定量度,就不会继续迭代
MPI_Comm comm;//MPI通信域
error=SomeLargeValue;//一个常量,error值超过它就不再迭代
初始化A、x和B
MPI_Init(&argc,&argv);//进入MPI环境
comm=MPI_COMM_WORLD;//为MPI通信域赋值
MPI_Comm_rank(comm,&my_rank);//获取当前进程在指定通信域的编号到my_rank
while(error>SomeErrorBound){//一次完整的迭代
Temp=B;//B是常量矩阵
for(int i=0;i<N;i++)Temp-=Arow[i]*X[i];//A是系数矩阵的一列,X是未知数(为上一次迭代计算出的值),算出一个矩阵,用B减去,减了N次
Temp/=A[my_rank];//只除以这个处理器对应的系数矩阵的一行
NewX=Temp+X[my_rank];//新的X要加上Temp
MPI_Allgather(&NewX,1,MPI_FLOAT,&X,1,MPI_FLOAT,comm);//每个处理器处理了一行(获得了一个新的X),聚集起来每个处理器获得所有新的X
Temp=Temp*Temp;//为什么要平方
MPI_Allreduce(&Temp,&error,1,MPI_FLOAT,MPI_SUM,comm);//所有处理器的Temp都被归并到根进程的error,方式是计算总和
}

Ribbon效果

形状

由n、n-1、n-2三个点围成三角形,n++循环。

颜色

透明度取决于alpha值。

渐变色取色环上临近的颜色。我找到rgb变化的规律后,手写了三个分段函数,他们的规律(参照色环上的顺序)大概是R变化时GB不变,G变化时RB不变,B变化时RG不变,他们的周期相同,6个阶段中每个阶段都有一种原色数值上升/下降。

写分段函数用了很多if,其实可以不用分段,渐变并非一定要与色环的顺序一致并且饱和度相当。我们也可以直接用cos选择一个0-256的数,rgb的数值由此决定,每次循环该数值变化一点点,这样也可以渐变。

代码

写的比较乱就不贴了。

同步、异步与阻塞、非阻塞

通常,同步操作是阻塞的,而异步操作非阻塞,但两对概念也可以交叉组合。

同步与异步是基于消息和通信的概念。异步操作立即返回,操作完成后通知,而同步操作等待操作完成才返回(返回就相当于完成通知,也意味着没有通知)。

阻塞与非阻塞的最大区别在于,执行操作后资源是否可用(当然是否阻塞也是他们的区别)。阻塞操作执行后资源可用,非阻塞操作执行后则不一定可用。

例如同步非阻塞,执行语句后就可以做别的,但是资源不可用,没有完成通知,因此需要轮询。异步阻塞,执行语句后不能做别的,执行下一条语句时资源已经可用了,有完成通知(异步阻塞和同步阻塞只差一个通知,基本没有区别)。