前方高能来袭,这是一套成熟的通过三次约会套路到男神的方法论-三板斧约会法,可能有点婊里婊气,但是实测非常好用,请分享给你身边需要它的姑娘们(手动滑稽)。

【三板斧起手】——诱导邀约

男生约女生,强调不要怂主动出击。

而女生约男生太过主动不合适,所以我们要诱导男生进行流程,让他以为这一切都是“他想做”。

所以我们和男生聊天互动时,要对男生呈现分享的话题表示出极大的兴趣,引导男生和我们多聊天。

举个例子:

“我一直都想试试打篮球呢,过去学校里一直没人教我,自己也不知道怎么开始学,没想到你打篮球这么厉害,好羡慕你。”

“哈哈哈说起来你可能不信,我一直看你们男生打LOL,渐渐的开始感兴趣了,想找一个机会尝试一下呢。”

“嗯嗯我也觉得我需要考一下研究生,不过基础不太好,数学方面一直很弱,所以蛮崇拜你这种能把高数线代玩的转的学霸。”

这个时候,情商高一点的男生都会顺水推舟说“那我教你吧”,这时候你们接触的机会就有了。

不过我们实在不能对直男的情商抱多大希望,所以如果他这个时候直接给你甩了一堆教程安利了一堆书或者教学视频,也是有可能出现的。

来,喝口水,压压飙升的血压,开始卖萌撒个娇:“好多东西啊……我怕没人讲我听不会,你能当下我师傅嘛?请你吃好吃哒。”

同样的道理,我们约男生时最好不要说:“最近新上映了一部电影,我们要不要去看看。”

你要说:

“最近有什么安排嘛……唉说起这个我就郁闷,最近新上映了一部电影,本来说好和闺蜜一起去的,结果她抛弃我去找男朋友了,就剩下我一个人了,好想去看啊,但是感觉一个人去看电影好尴尬。”

有的女生就坐不住了:这不就是传说中装诱惑的绿茶吗?这不就是卖萌示弱勾引男生的心机girl吗?

你是想泡男生的,学着点,坐下,继续听。

【第一斧】培养联系感,释放可得性

关键词:共同话题+相似处+可得性

第一次约会之前,专门抽出一大段时间,什么事都不干,你只负责一件事:好好捯饬自己!

第一次约会别穿的太诱惑,走可爱清新的路线,这种穿衣风格符合大多数直男的审美,化一个裸妆就会让他觉得你“素颜也好美”了。

虽然这看起来很普通难度不大,但是你每一个装扮都要特别用心,就像vava《我的新衣》里唱的:

“look at me,从上到下,就哪怕小的细节都要美到爆炸。”

约会可以小小的迟到5-10分钟,“赶过来”时,一定要主动道歉:“对不起对不起,堵车了,你没有等的太着急吧。”给他一点着急的感觉,然后再用礼貌的道歉刷一下好感。

约会安排什么的,让他安排,记得夸奖他用心,挑的都是你喜欢的地方,让他小小的洋洋自得一下。

如果他一点规划都没有,只会傻傻的问你你想去哪里……好吧先在内心吐槽一下,然后眨眨眼睛:“我觉得都可以呀,不过我比较喜欢xx(咖啡店,西餐,中餐,日料之类的大方向)”

注意,你去根本不是去和他吃饭的!你需要在喝咖啡吃饭的间歇迅速找到共同话题,如故他主动聊迎合他就好了,如果他紧张的说不出话来,你就主动挑话题吧:

“我看你朋友圈xxxx,经常xxxx吧?”

说话的时候扑闪着你的卡姿兰大眼睛,效果满分。

记得找到共同话题时,补上“原来你也喜欢xxxx啊!我对那个很感兴趣呢”,给他足够卖弄的动力,这样能够拉进你们之间的关系。

光有近距离还不够,这个时候需要释放一些可得性,告诉男生:我单身可撩,你还不给我主动点!

建议这么说:“唉,很少有能和我有一样兴趣爱好的人了,我将来找男朋友一定要找一个志趣相投,聊得来的人,这样才不会无聊呢。”

这个叫做拉,给他一个暗示:唉呀妈呀这不说的就是我吗。

别着急,还有后半段呢:“唉,只可惜现在这样的人太少了,难怪我单身。”

这个叫推,让他一下子又不知所措:啥情况啊?坐你对面的这个不就是吗?

别管他,让他纠结去吧。撩女生我们讲推拉,推出去再哄回来,让女生觉得我们坏但是可爱。对撩男生我们讲拉推,拉过来再一把推开,让男生因为我们到底对他有没有意思而纠结。

相信我,当一个人因为你喜不喜欢他开始纠结时,他就快喜欢上你了。

【第二斧】培养亲密感,激发保护欲

关键词:诱惑+收集心疼

我们不管撩汉撩妹,都要展示给对方积极阳光上进的一面。

但有时候,适当的暴露脆弱面会激发男生本能的保护欲,让他想要在你身边照顾你。

但是千万切忌在朋友圈公开发一些病床照,一些孤独寂寞冷的状态,这样你能引发一群男生来关照你,而男神未必理你,更会招来一堆苍蝇。

趁着第一次约会结束后,给他发一条这样的消息:

“今晚和你聊的很开心,咖啡/饭菜/电影也很合心意,好久没有这么开心过了,下次回请你,哈哈。”

男生说好的没问题最好,要是男生说不用了不用了,直接调皮的回一句:

“怎么滴还不给我一个表达礼貌的机会啦~”

道德绑架就道德绑架吧,这是泡汉子呢,哪来那么多讲究。

至于第二次呢,不要再诱导邀约了,如果他没动静,直接点约他。

这个时候不怕显得主动,因为你顺理成章:这是出于礼节的回请,不要多想哦。

这一次约会,梳妆打扮的要求不能低,依旧要一出场就惊艳,至于怎么做到这一步,你还需要多多请教美妆博主,原谅我这个直男不能给出太多的意见。

这次约会的聊天话题前半段依旧正常的瞎扯淡就好,重点是后半段,你一定要开始刷心疼了。

把你平时和小姐妹诉苦的样子摆出来,告诉男生你其实压力也很大,也很脆弱,也渴望温暖。

但是这不算完,刷心疼注意以下两点:1.不能把刷心疼变成诉苦 2.保证唯一特殊性

我们举个例子:

“宏桑你一直都说我很阳光很正能量,但实际上说句实在话,现在又有谁是真的开心呢?我一个女孩子孤身一人来到北京打拼,虽然白天大家都看到我努力工作特别上进,但有的时候被领导批评,工作不顺时,其实我也会伤心难过。”

“但是那有怎么样呢,回到住的地方,大家都去休息了,还不是一个人去微波炉热一下饭,洗个澡振作一下,然后孤零零的睡。”

“就算有时候实在撑不住了,大哭一场,也得闷着头不能发出声来,怕吵到舍友,也怕被别人知道自己其实并不是全能选手。”

“这些话也就我们今天在这里说一说了,平时我绝对不会对其他人说这么多的,大家都很忙,没时间听太多我的事情。”

“抱歉哈,刚刚情绪有点失控,吓到你了”(擦眼泪,不管有没有)

这个时候,你在男生心目中的形象是:一个自立自强的女孩子,有着温柔脆弱的一面,但是却不知道和谁说,想要找一个依靠。

你说他心疼不心疼,想不想保护你,心中的英雄情节有没有被你激发?

扇风够了,我们再点个火:

分离的时候,认真的看着他,对他说:

“xxx,谢谢你今天能听我说这些,你好体贴。希望我将来能遇到像你一样的人。”

看到了吗?“谢谢你听我说这些”“你好体贴”是拉,“遇到像你一样的人(但可能不是你)”再推开。

让他继续纠结去吧。

【第三斧】亲密互动,引导表白

关键词:高强度诱惑+引导表白

Ok,终于我们来到了第三次约会。这一次其实谁约谁真的不困难了,毕竟前两次都出来一起吃喝玩乐过了。

这次见面,告诉你的小姐妹们,怎么诱惑男人怎么来,不论是妆容还是衣着,按照诱惑力max来打扮。

这次约会项目做什么都无所谓,但是诱惑感一定要到位。

比如聊天时假装被笑话逗得前仰后合,趁机拍拍他;比如在他说话时用小迷妹的眼光盯着他;比如吃饭时悄悄用腿碰碰他的腿;比如他开你玩笑时假装要打他……

诱惑+肢体碰触,除非你丑,不然真的没几个男生扛得住双重引诱。

这个时候你做一个事,就足够让他被你吸引:盯着他,温和的笑,傻傻的笑,就够了。

男生版三板斧约会要求第三次约会确立关系,但是女生很难做到主动去和男生表白,我们不如换个方式。

之前有女粉丝问我男生送她到楼下,摸了摸她的头,她想要更进一步但是发现男生榆木脑袋不开窍,怎么办。

很简单,你只需要在分别时大大方方的告别,走一两步,突然停下,回头,用恨铁不成钢的无奈的笑配上幽怨的语气,轻轻说一句:

“你还真让我走啊?”

就够了,真的就够了!

这句话配合上你的表情,已经传达出了这样的意思:你能不能主动点!你能不能配合点!你居然还真让我回去了,都不抱抱我!你这么笨可以去死了!

这样,男生要么瞬间开窍冲上去对你表白,要么害羞忍住了但是回去一晚上纠结的睡不着觉,要么就是完全无感跟没听见一样。

对于最后一种,我们就算了吧,这都快说出来了他都没反应,说明人家是真的无感。

但是前两种就有戏了,之前你释放了足够的可得性,也激发了他的保护欲,最后这一声叹气,是把他推向你的最后一把。

如果他不上,他的内心都会骂自己不是个爷们!

如果他不说,回去以后。立刻开始对他变冷淡。

你要用行动去告诉他:机会不是没有给过你,你没好好把握。至于本姑娘为什么对你冷淡了,自己琢磨去吧。

就算他想不透,他的狐朋狗友也会拍着他的肩膀告诉他哥们你是傻子吗,这个女生喜欢你啊。

相信我,他会坐不住的,他会主动来找你的,甚至主动表白。

等他绷不住的那一刻,我们只需要摸摸他的头,一把抱住他,娇嗔一句:“笨蛋”

“其实我也喜欢你啊”

看,一桩两全其美的好事,就通过三次约会造就了。

<?php

/**
 * 爬取 国外高校犯罪信息数据
 * Class SchoolSpider
 */
class SchoolSpider
{
    private $schoolName;
    //学校名检查api
    private $schoolApi = 'https://ope.ed.gov/campussafety/api/institution/names?filter=';
    //校区
    private $schoolSerachApi = 'https://ope.ed.gov/campussafety/api/institution/search';
    //数据  校区
    private $dataApi = 'https://ope.ed.gov/campussafety/api/campus/';
    //整个学校
    private $totalApi = 'https://ope.ed.gov/campussafety/api/institution/';
    //校区
    private $campisesData;
    //详情数据
    private $dataDetail;
    //详情数据
    public $error;

    public $result=[];

    public function __construct()
    {
        //请求时间不限
        set_time_limit(0);
    }

    public function spiderData($schoolName)
    {
        $this->schoolName = $schoolName;
        $this->result['school_name'] = $this->schoolName;
        if (!$this->checkName() || !$this->getCampises()) {
            return ['code' => -1, 'msg' => $this->error];
        }
        //总的数据
        $this->formatData($this->campisesData);
        //各个分校区数据
        $this->formatData($this->campisesData[0]['Campuses'],1);

        return ['code' => 0, 'msg' => $this->error,'data'=>$this->result];
    }


    /**
     * @name  数据解析
     * @param $campisesData 数据
     * @param $isCampise  是否是分校区数据
     */
    private function formatData($campisesData,$isCampise=false){

        foreach ($campisesData as $campise) {
            if($isCampise){
                //校区名
                $res = $this->getDetailCampuse($campise['UnitID']);
            }else{
                $res = $this->getDetail($campise['UnitID']);
            }

            if(!$res||isset($this->result[$campise['UnitID']])){
                continue;
            }
            $dataDetail = $this->dataDetail;
            //校名
            $this->result[$campise['UnitID']]['campuse'] = $campise['Name'];
            foreach ($dataDetail as $k => $data) {
                if ($k == 0)
                    continue;
                $this->result[$campise['UnitID']]['data'][] = empty($data) ? [] : array_column($data['Cells'], 'Html');
            }
        }
    }

    /**
     * 检查学校名
     * @return array
     */
    private function checkName()
    {
        $school = json_decode($this->httpRequest($this->schoolApi . urlencode($this->schoolName)), true);
        if (!isset($school[0]['Code']) || !$school[0]['Code']) {
            $this->error = '检查学校名 error';
            return false;
        }
        return true;
    }

    /**
     * 获取校区
     * @return array
     */
    private function getCampises()
    {
        $schoolSerachData = "{\"name\":\"" . $this->schoolName . "\",\"city\":\"\",\"state\":[],\"country\":[],\"countryNames\":[],\"institutionType\":[],\"institutionProgram\":[],\"campusLocation\":\"-1\",\"onlyResidentialCampuses\":false,\"enrollmentRange\":[],\"sort\":\"name\",\"sortDirection\":\"asc\",\"all\":false,\"pageNumber\":0,\"fromFavorites\":false}";
        //获取校区列表
        $campisesData = json_decode($this->httpRequest($this->schoolSerachApi, $schoolSerachData), true);

        if (!isset($campisesData['Results'][0]['Campuses']) || empty($campisesData['Results'][0]['Campuses'])) {
            $this->error = '获取校区 error';
            return false;
        }
        $this->campisesData = $campisesData['Results'];
        return true;
    }

    /**
     * @name 获取全部详情
     * @param $unitId
     * @return array
     */
    private function getDetail($unitId)
    {

        $dataDetail = json_decode($this->httpRequest($this->totalApi . $unitId), true);

        if (!isset($dataDetail['Groups'][0]['Screens'][0]['Rows']) || empty($dataDetail['Groups'][0]['Screens'][0]['Rows'])) {
            $this->error = '获取详情 error';
            return false;
        }
        $this->dataDetail = $dataDetail['Groups'][0]['Screens'][0]['Rows'];
        return true;
    }

    /**
     * @name 获取分校区详情
     * @param $unitId
     * @return array
     */
    private function getDetailCampuse($unitId)
    {

        $dataDetail = json_decode($this->httpRequest($this->dataApi . $unitId), true);

        if (!isset($dataDetail['Groups'][0]['Screens'][0]['Rows']) || empty($dataDetail['Groups'][0]['Screens'][0]['Rows'])) {
            $this->error = '获取详情 error';
            return false;
        }
        $this->dataDetail = $dataDetail['Groups'][0]['Screens'][0]['Rows'];
        return true;
    }

    /**
     * @name 请求方法
     * @param $url
     * @param $data
     * @return false|mixed|string
     */
    private function httpRequest($url, $data = '')
    {
        $curl = curl_init();
        $method = $data ? 'POST' : 'GET';
        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_POSTFIELDS => $data,
            CURLOPT_HTTPHEADER => array(
                "Content-Type: application/json;charset=UTF-8",
                "Postman-Token: a30f51b0-cc09-4bfb-801e-830a931994f4",
                "cache-control: no-cache"
            ),
        ));

        $response = curl_exec($curl);
        $err = curl_error($curl);

        curl_close($curl);

        if ($err) {
            echo "cURL Error #:" . $err;
            return json_encode([]);
        } else {
            return strip_tags($response);
        }
    }
}

$a = new  SchoolSpider();
$r = $a->spiderData('Harvard University');
echo  json_encode($r);

<script>
    /**
     * 数组中此元素出现的次数
     * @param search
     * @param array
     * @returns {number}
     */
    function in_array_count(search, array) {
        var num = 0;
        for (var i in array) {
            if (array[i] == search) {
                num++;
            }
        }
        return num;
    }

    /**
     * 数组中此元素是否出现
     * @param search
     * @param array
     * @returns {boolean}
     */
    function in_array(search, array) {
        for (var i in array) {
            if (array[i] == search) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取全部组合
     * @returns {Array}
     */
    function getProperty() {
        var property_name = ['颜色','颜色','尺寸','尺寸','尺寸','内存','内存','厚度','厚度'];         //属性名数组
        var property_value= ['红色','黑色','3.5','5.5','6.5','64G','128G','10mm','20mm'];
        var property_name_unique = [];  //去重的属性名
        var property_value_unique = []; //每个属性名对应的值  二维数组
        var property_name_val_count = [];//每个属性名对应的值个数
        var var_total_group = 1;         //组合的数量

        //所有的属性值
        for(value_key in property_value){
            if (!in_array(property_name[value_key], property_name_unique)) {
                property_name_unique.push(property_name[value_key]);//去重后的属性名
                property_value_unique[property_name[value_key]] = [];
                property_name_val_count[property_name[value_key]] = 0;
            }
            property_value_unique[property_name[value_key]].push(property_value[value_key]);//去重的属性名对应的属性值
            property_name_val_count[property_name[value_key]]++;//去重后的属性名有几个值
        };

        //总组合数 为各个属性 拥有值个数的 累乘
        for (var num_p in property_name_val_count) {
            var_total_group = property_name_val_count[num_p] * var_total_group;
        }


        var ceng = 0;           //当前第几层
        var pipei = [];         //匹配的结果值
        var ceng_old = 'X';     //上次循环时的层数
        var this_ceng_l_j = 1;  //当前层属性值个数 与 过往层个数累乘  var_total_group➗this_ceng_l_j=本层每种结果可出现重复的次数

        //根据不同属性个数 property_name_unique.length 分为 property_name_unique.length 层

        for (var time = 0; time < var_total_group * property_name_unique.length; time++) {
            ceng = Math.floor(time / var_total_group);
            if (ceng == 0) {
                //第一层初始化字符串
                pipei[time % var_total_group] = '';
            }
            //这一层拥有属性值得个数
            this_ceng_l = property_value_unique[property_name_unique[ceng]].length;

            //当前层 属性值个数 与 过往层个数 累乘
            if (ceng_old != ceng) {
                this_ceng_l_j = this_ceng_l * this_ceng_l_j;
            }

            for (var ceng_t_n = 0; ceng_t_n < this_ceng_l; ceng_t_n++) {
                temp_str = pipei[time % var_total_group] + property_name_unique[ceng] + '--' + property_value_unique[property_name_unique[ceng]][ceng_t_n] + '||';
                //这种结果可出现重复的次数是否达到最大值
                if (in_array_count(temp_str, pipei) < var_total_group / this_ceng_l_j) {
                    pipei[time % var_total_group] = temp_str;
                    break;
                }
            }
            ceng_old = ceng;
        }

        return pipei;

    }

</script>

1.命令行界面

命令行界面(英语:Command-lineInterface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。

2.终端

在大型机 (Mainframe) 和小型机 (Minicomputer)的时代里,计算机曾经非常昂贵且巨大,不像现在这样人手一台。这些笨重的计算机通常被安置在单独的房间内,而操作计算机的人们坐在另外的房间里,通过某些设备与计算机进行交互。这种设备就叫做 终端 (Terminal),也叫终端机。

2.1控制台(console)

历史上,终端是链接到计算机的一种带输入输出功能的外设。
但是有一种终端于总不同,它和计算机是一体的,是计算机的一部分。这个特殊的终端就是 控制台(console)。

2.2终端模拟器 (Terminal Emulator)

随着计算机的进化,我们已经见不到专门的终端硬件了,取而代之的则是键盘与显示器。

但是没有了终端,我们要怎么与那些传统的、不兼容图形接口的命令行程序(比如说 GNU 工具集里的大部分命令)交互呢?这些程序并不能直接读取我们的键盘输入,也没办法把计算结果显示在我们的显示器上……(图形界面的原理我这里就不多说了,它们编程的时候图形接口还在娘胎里呢!)

这时候我们就需要一个程序来模拟传统终端的行为,即 终端模拟器 (Terminal Emulator)。

严格来讲,Terminal Emulator 的译名应该是「终端仿真器」。
对于那些命令行 (CLI) 程序,终端模拟器会「假装」成一个传统终端设备;而对于现代的图形接口,终端模拟器会「假装」成一个 GUI 程序。一个终端模拟器的标准工作流程是这样的:

捕获你的键盘输入;
将输入发送给命令行程序(程序会认为这是从一个真正的终端设备输入的);
拿到命令行程序的输出结果(STDOUT 以及 STDERR);
调用图形接口(比如 X11),将输出结果渲染至显示器。
终端模拟器有很多,这里就举几个经典的例子:

GNU/Linux:gnome-terminal、Konsole;
macOS:Terminal.app、iTerm2;
Windows:Win32 控制台、ConEmu 等。

在专门的终端硬件已经基本上仅存于计算机博物馆的现代,人们通常图省事儿,直接称呼终端模拟器为「终端」。

2.3.TTY

简单说,tty就是终端的总称。

最早的 Unix 终端是 ASR-33 电传打字机。而电传打字机 (Teletype / Teletypewriter) 的英文缩写就是 tty,即 tty 这个名称的来源。
由于 Unix 被设计为一个多用户操作系统,所以人们会在计算机上连接多个终端(在当时,这些终端全都是电传打字机)。Unix 系统为了支持这些电传打字机,就设计了名为 tty 的子系统(没错,因为当时的终端全都是 tty,所以这个系统也被命名为了 tty,就是这么简单粗暴),将具体的硬件设备抽象为操作系统内部位于 /dev/tty* 的设备文件。

3. Shell —— 提供用户界面的程序

大家都知道,操作系统有一个叫做 内核 (Kernel) 的东西,它管理着整台计算机的硬件,是现代操作系统中最基本的部分。但是,内核处于系统的底层,是不能让普通用户随意操作的,不然一个不小心系统就崩溃啦!

但我们总还是要让用户操作系统的,怎么办呢?这就需要一个专门的程序,它接受用户输入的命令,然后帮我们与内核沟通,最后让内核完成我们的任务。这个提供用户界面的程序被叫做 Shell (壳层)。

其实 Shell 只是提供了一个用户操作系统的入口,我们一般是通过 Shell 去调用其他各种各样的应用程序,最后来达成我们的目的。比如说我们想要知道一个文件的内容,我们会在 Shell 中输入命令 cat foo.txt,然后 Shell 会帮我们运行 cat 这个程序,cat 再去调用内核提供的 open 等系统调用来获取文件的内容。虽然并不是 Shell 直接去与内核交互,但广义上可以认为是 Shell 提供了与内核交互的用户界面。

{

Shell 通常可以分为两种:
命令行 Shell 与 图形 Shell。顾名思义,前者提供一个命令行界面 (CLI),后者提供一个图形用户界面 (GUI)。Windows 下的 explorer.exe 就是一个典型的图形 Shell(没错,它确实是,因为它接受来自你的指令,并且会帮你与内核交互完成你的指令)。

常见或历史上知名的命令行 Shell 有:
适用于 Unix 及类 Unix 系统:
sh (Bourne shell),最经典的 Unix shell;
bash (Bourne-Again shell),目前绝大多数 Linux 发行版的默认 shell;
zsh (Z shell),我个人最喜欢的 shell;
fish (Friendly interactive shell),专注于易用性与友好用户体验的 shell;
Windows 下的 cmd.exe (命令提示符) 与 PowerShell。
还有其他各种五花八门的 Shell

4.shell与终端的分工

现在我们知道,终端干的活儿是从用户这里接收输入(键盘、鼠标等输入设备),扔给 Shell,然后把 Shell 返回的结果展示给用户(比如通过显示器)。而 Shell 干的活儿是从终端那里拿到用户输入的命令,解析后交给操作系统内核去执行,并把执行结果返回给终端。

不过 Shell 与终端的分工有一些容易混淆的地方,这里以例子进行说明:

  • 终端将用户的键盘输入转换为控制序列(除了字符以外的按键,比如 左方向键 → ^[[D),Shell 则解析并执行收到的控制序列(比如 ^[[D → 将光标向左移动);
  • 不过也有例外,比如终端在接收到 Ctrl + C 组合键时,不会把这个按键转发给当前的程序,而是会发送一个 SIGINT 信号(默认情况下,这会导致进程终止)。其他类似的特殊组合键有 Ctrl-Z 与 Ctrl- 等,可以通过 stty -a 命令查看当前终端的设置。
  • Shell 发出类似「把前景色改为红色(控制序列为 033[31m)」「显示 foo」等指令;
  • 终端接收这些指令,并且照着 Shell 说的做,于是你就看到了终端上输出了一行红色的 foo。
  • 除非被重定向,否则 Shell 永远不会知道它所执行命令的输出结果。我们可以在终端窗口中上下翻页查看过去的输出内容,这完全是终端提供的 feature,与 Shell 没有半毛钱关系;
  • 命令提示符 (Prompt) 是一个完全的 Shell 概念,与终端无关;
  • 行编辑、输入历史与自动补全等功能是由 Shell 提供的(比如 fish 这个 Shell 就有着很好用的历史命令与命令自动补全功能)。不过终端也能自己实现这些功能,比如说 XShell 这个终端模拟器就可以在本地写完一行命令,然后整条发送给远程服务器中的 Shell(在连接状况不佳时很有用,不然打个字都要卡半天);
  • 终端中的复制粘贴功能(Shift + Insert 或者鼠标右键等)基本上都是由终端提供的。举个例子,Windows 默认的终端对于复制粘贴的支持很屎,而换一个终端(例如 ConEmu)后就可以很好地支持复制粘贴。不过 Shell 以及其他命令行程序也可以提供自己的复制粘贴机制(例如 vim)。

使用iptables设定特定端口连接数(万能方法)
限制端口连接数量
首先输入命令service iptables stop关闭iptables(注意:iptables可能会有问题,貌似在旧版本中不被认为是一个服务,而是防火墙,这个问题我还没有解决,如果你解决了请告诉我一声,谢谢)
限制端口并发数很简单,IPTABLES就能搞定了,假设你要限制端口8388的IP最大连接数为5,两句话命令:

iptables -I INPUT -p tcp --dport 8388 -m connlimit --connlimit-above 5 -j DROP
iptables -I OUTPUT -p tcp --dport 8388 -m connlimit --connlimit-above 5 -j DROP

我再举个例子,比如你想限制从1024-10240的端口

iptables -I INPUT -p tcp --dport 1024:10240 -m connlimit --connlimit-above 5 -j DROP
iptables -I OUTPUT -p tcp --dport 1024:10240 -m connlimit --connlimit-above 5 -j DROP

保存IPTABLES规则即可(service iptables save),其他端口以此类推。
输入命令service iptables start启动
最后用命令查看是否生效

iptables -L -n -v

限制端口速度
首先输入命令service iptables stop关闭iptables
限制端口并发数很简单,IPTABLES就能搞定了,假设你要限制端口5037的最大连接速度为60个包每秒,两句话命令:

iptables -A INPUT -p tcp --sport 5037 -m limit --limit 60/s -j ACCEPT
iptables -A INPUT -p tcp --sport 5037 -j DROP

也就是限制每秒接受60个包,一般来说每个包大小为64—1518字节(Byte)。
限制指定ip的访问速度
原理:每秒对特定端口进行速度控制,比如每秒超过10个的数据包直接DROP,从而限制特定端口的速度

iptables -A FORWARD -m limit -d 208.8.14.53 --limit 700/s --limit-burst 100 -j ACCEPT 
iptables -A FORWARD -d 208.8.14.53 -j DROP

最后说一下如何解决防火墙重启后失败的问题

iptables-save >/etc/sysconfig/iptables
echo 'iptables-restore /etc/sysconfig/iptables' >> /etc/rc.local
chmod +x /etc/rc.d/rc.local

对于ssr客户端
限制设备连接数
打开你的配置文件,假设你在 /root 文件夹中安装的ShadowsocksR服务端,那么就是:

vi /root/shadowsocksr/user-config.json

找到协议参数(参数为空 "" 时,默认限制 64个设备数)

"protocol_param": "",

在协议参数中设置你要限制 每个端口最大设备连接数(建议最少2个),比如 限制最大 5个设备同时链接,那么改为:

"protocol_param": "5",

注意:协议参数仅在服务端 协议设置(protocol)为 非原版(origin)协议并不兼容原版(_compatible) 时才有效!
限制端口速度
还是上文的那个地方,第一个是单线程限制,另外一个是总限制

"speed_limit_per_con": 0,
"speed_limit_per_user": 0,

当你使用这个端口 下载某个文件时,单线程下载限速 100KB/S ,多线程下载(比如5个线程)就是 500KB/S 了,Youtube是单线程。