套接字应用程序

这章节是关于实现 lib_chan 库的 lib_chan 的代码在 TCP/IP 之上实现了一个完整的网络层,能够提供认证和Erlang 数据流功能。一旦理解了 lib_chan 的原理,就能量身定制我们自己的通信基础结构,并把它叠加在TCP/IP 之上了。 就lib_chan 本身而言,它是一种构建分布式系统的有用组件。

一:简单示例:

用一个简单的示例来展示如何使用 lib_chan 。我们会创建一个简单的服务器,让它 计算阶乘和斐波那契数,并用一个密码来保护它。 这个服务器将在2233 端口工作。
创建服务器的过程共分四步。
(1) 编写配置文件。
(2) 编写服务器代码。
(3) 启动服务器。
(4) 通过网络访问服务器。

1. 编写配置文件

下述代码时这个示例的配置文件:

%% socket_dist/config1
{port,2233}.
{service, math, password, "qwerty", mfa, mod_math, run, []}.
这个配置文件里有一些 service 元组,它们的形式如下:
{service, <Name>, password, <P>, mfa, <Mod>, <Func>, <ArgList>}
里面的参数由原子 servicepassword mfa 分隔。 mfa module, function, args ”的缩写, 意思是接下来的三个参数应当被解释为模块名、函数名和一个用来调用函数的参数列表。 在我们的示例里,配置文件指定了一个名为math (数学)的服务,它的工作端口是 2233 。这个服务由密码qwerty 保护,实现它的模块名为 mod_math ,启动方式是调用 mod_math:run/3 , run/3的第三个参数是 [ ]

2.编写服务器代码

这个数学服务器的代码如下:
%% socket_dist/mod_math.erl
-module(mod_math).
-export([run/3]).

run(MM, ArgC, Args) ->
    io:format("mod_math:run_starting~n"
              "Argc = ~p Args = ~p~n",[ArgC, Args]),
    loop(MM).

loop(MM) ->
    receive
        {chan, MM, {factorial, N}} ->
            MM !{send, fac(N)},
            loop(MM);
        {chan, MM, {fibonacci, N}} ->
            MM !{send, fib(N)},
            loop(MM);
        {chan_closed, MM} ->
            io:format("mod_math stopping~n"),
            exit(normal)
    end.

fac(0) -> 1;
fac(N) -> N*fac(N-1).
fib(1) -> 1;
fib(2) -> 1;
fib(N) -> fib(N-1) + fib(N-2).
当某个客户端连接到 2233 端口并请求 math 服务时, lib_auth 会对它进行认证,如果密码正确,就会通过mod_math:run(MM, ArgC, ArgS) 函数分裂出一个处理进程。 MM 中间人 PID , ArgC来自客户端, ArgS 则来自配置文件。这个数学服务器很简单,它所做的就是等待一个 {chan, MM, {factorial, N}}消息,然后执行 MM ! {send, fac(N)}来把结果发回客户端。

3.启动服务器

像下面这样启动服务器:
1> lib_chan:start_server("./configl").
ConfigData = [{port,2233},{service,math,password,"qwerty",mfa,mod_math,run,[]}
true

4.通过网络访问服务器

可以在单台机器上进行代码测试:
2> {ok, S} = lib_chan:connect("localhost", 2233, math,
                              "qwerty", {yes, go}).
{ok,<0.47.0>}

3> lib_chan:rpc(S, {factorial, 20}).
2432902008176640000

4> lib_chan:rpc(S, {fibonacci, 15}).
610

5> lib_chan:disconnect(S).
close

二:lib_chan的原理

构建 lib_chan 使用了四个模块里的代码。
(1)  lib_chan 扮演“主模块”的角色。程序员只需要了解 lib_chan 所导出的那些方法。其他
三个模块(稍后讨论)会在 lib_chan 的内部使用。
(2)  lib_chan_mm 负责编码和解码 Erlang 消息,并管理套接字通信。
(3)lib_chan_cs 负责设立服务器并管理客户端连接。它的主要工作之一是限制同时连接的
最大客户端数量。
(4)  lib_chan_auth 包含的代码用于进行简单的质询 / 响应认证。

1. lib_chan

lib_chan 的结构如下:
-module(lib_chan).
start_server(ConfigFile) ->
    %% 读取配置文件并检查语法
    %% 调用start_port_server(Port, ConfigData)
    %% 其中Port是所需的端口,ConfigData包含配置数据
    ...

start_port_server(Port, ConfigData) ->
     lib_chan_cs:start_raw_server(
          fun(Socket) ->
               start_port_instance(Socket, ConfigData),
          end, ...).
     %% Lib_chan_cs负责管理连接。
     %% 新连接建立后会胡用start_raw_server的参数,
     %% 也就是这个fUn。
start_port_instance(Socket, ConfigData) ->
    %% 它会在客户瑞连接服务器时执行分裂。
    %% 我们会设立一个中间人并执行认证,
    %% 如果一切顺利就调用
    %% really_start (MM, ArgC, {Mod,Func,ArgS})
    %% (后三个参数来自配置文件)
    ....

really_start(MM, ArgC, {Mod, Func, Args}) ->
   apply(Mod, Func, [MM, ArgC, Args]).

connect(Host,Port,Service,Password,Argc)->
    %% 客户瑞代码
    ...

2.lib_chan_mm中间人

lib_chan_mm 实现了一个中间人。它能对应用程序隐藏套接字通信,并把 TCP 套接字上的数据流转变成Erlang 消息。中间人负责组装消息(它可能是碎片化的)和编码 / 解码 Erlang 数据类型,也就是把它们转换成能通过套接字发送和接收的字节流。可以通过下图来进行理解:

带中间人的套接字通信
M1 机器上的 MM1 进程表现得就像是 P2 的代理,而在 M2 机器上的 MM2 进程表现得就像是 P1
代理。 MM1和 MM2 都是中间人进程的 PID 。中间人进程的代码如下:
loop(Socket, Pid) ->
    receive
        {tcp, Socket, Bin} ->
            Pid ! {chan, self(), binary_to_term(Bin)},
            loop(Socket, Pid);
        {tcp_closed, Socket} ->
            Pid ! {chan_closed, self()};
        close ->
            gen_tcp:close(Socket);
        {send, T} ->
            gen_tcp:send(Socket, [term_to_binary(T)]),
            loop(Socket, Pid)
    end.
这个循环是套接字数据和 Erlang 消息传输这两个世界之间的接口。

3.lib_chan_cs

lib_chan_cs 负责设立客户端和服务器通信。下面是它导出的两个重要方法:
(1) start_raw_server(Port, Max, Fun, PacketLength)
        它会启动一个监听器来监听Port上的连接。允许的最大同时会话数是Max。Fu是一个元数为1的fin,Fun(Socket)会在连接开始时执行。套接字通信会假定包长度为PacketLength。
(2) start:raw_client(Host, Port, PacketLength) => {ok, Socket} | {error, Why}
        它会尝试连接由start_raw_server打开的端口。

4. lib_chan_auth

如果某个客户端想使用 math 服务,就必须向服务器证明它知道共享秘密。这个过程如下所示:
(1) 客户端向服务器发送一个请求来表示它希望使用 math 服务。
(2) 服务器计算出一个随机字符串 C ,然后把它发给客户端。这就是 质询 。字符串是由 lib_chan_auth:make_challenge()函数生成的。可以用交互方式来看它是如何工作的:
1> C = lib_chan_auth:make_challenge().
"qnyrgzqefvnjdombanrsmxikc"
(3) 客户端接收字符串( C )并计算出响应( R ),其中 R = MD5(C  ++ Secret) ,它是由
lib_chan_auth:make_response 生成的。这里有一个例子:
2> R = lib_chan_auth:make_response(C,"qwerty").
"e759ef3778228beae988d91a67253873"

(4)这个响应被发回服务器。服务器接收响应并检查它是否正确,做法是算出预期的响应值。 这是由lib_chan_auth:is_response_correct实现的。如下:

3> lib_chan_auth:is_response_correct(C, R, "qwerty").
true 

完整的lib_chan代码我打算单独列一篇来记录,因此本章就介绍一个例子和原理。

想要看lib_chan的详细代码可以跳转到下一篇:

http://t.csdnimg.cn/MXOOy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/229879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浪潮信息KeyarchOS EDR 安全防护测评

背景 近几年服务器安全防护越来越受到企业的重视&#xff0c;企业在选购时不再仅仅看重成本&#xff0c;还更看重安全性&#xff0c;因为一旦数据泄露&#xff0c;被暴力破解&#xff0c;将对公司业务造成毁灭性打击。鉴于人们对服务器安全性的看重&#xff0c;本篇文章就来测…

Proteus仿真--160128LCD中文显示温度与时间

本文介绍基于160128LCD的中文温度与时间显示设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 本文基于51单片机实现160128LCD的中文温度与时间的现实&#xff0c;其中万年历芯片选用DS1302时钟芯片&#xff0c;温度传感器选用DS18B20温度传感器 仿真图如下 仿真…

Linux基础——进程初识(一)

1. 硬件 ①冯诺依曼体系 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。其详细结构如下图所示 在这里有几点要说明 1. 这里的储存器实际上指的是内存 2. 输入设备与输出设备都属于外设 常见的输入设备…

Java-网络通信总结

文章目录 网络程序设计基础局域网与互联网 网络协议IP协议TCP/IP 协议端口域套接字 TCP 程序InterAddress 类ServerSocket 类 UDP 程序DatagramPacket 类DatagramSocket 类 网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。Java 已经将网络程序所需要的元素…

三防平板|手持终端PDA|8寸/10寸工业三防平板电脑主板方案定制

近年来&#xff0c;随着科技的快速发展&#xff0c;三防平板成为了各行各业中不可或缺的工具。三防平板采用IP67级别的防护设计&#xff0c;通过了多项测试标准&#xff0c;如国标和美标&#xff0c;具备防水、防摔、防尘、防撞、防震、防跌落以及防盐雾等多重防护功能。因此&a…

红队系列-内网横向

内网横向 渗透测试-内网横向MS-17010利用方法总结原理介绍漏洞利用MSFLadon 渗透测试-从公有云到内网漫游RCE-反序列化-frp0x01 前言0x02 前期打点0x03 想办法打内网0x04对上面的IP进行渗透0x05 愉快的内网漫游 windows凭据窃取MimikatzProcdumpGet-PassHashes.ps1 Windows远程…

Python开发运维:Python常见异常类型

目录 一、理论 1.异常 一、理论 1.异常 &#xff08;1&#xff09;概念 异常是程序因为某种原因无法正常工作了&#xff0c;比如缩进错误、缺少软件包、环境 错误、连接超时等都会引发异常。 一个健壮的程序应该把所能预知的异常都应做相应的处理&#xff0c;保障程序长期运…

Linux文件系统与基础IO

文章目录 1 C文件接口1.1 fopen1.2 fwrite、fread、rewind、fclose 2 文件系统调用2.1 open2.1.1 参数2&#xff1a;flags2.1.2 参数3&#xff1a;mode2.1.3 返回值——file descriptor 2.2 write2.3 read2.4 close 3 文件的本质3.1 struct file3.2 一个进程如何与多个文件相关…

luceda ipkiss教程 43:画渐变圆弧型波导

案例分享&#xff1a; from si_fab import all as pdk import ipkiss3.all as i3 from ipcore.properties.restrictions import RestrictTuple from ipkiss.geometry.shapes.modifiers import __ShapePathBase__ import numpy as np from math import atan2class ShapePathTa…

电子学会C/C++编程等级考试2021年06月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:数字变换 给定一个包含5个数字(0-9)的字符串,例如 “02943”,请将“12345”变换到它。 你可以采取3种操作进行变换 1. 交换相邻的两个数字 2. 将一个数字加1。如果加1后大于9,则变为0 3. 将一个数字加倍。如果加倍后大于…

2023-12-08 LeetCode每日一题(出租车的最大盈利)

2023-12-08每日一题 一、题目编号 2008. 出租车的最大盈利二、题目链接 点击跳转到题目位置 三、题目描述 你驾驶出租车行驶在一条有 n 个地点的路上。这 n 个地点从近到远编号为 1 到 n &#xff0c;你想要从 1 开到 n &#xff0c;通过接乘客订单盈利。你只能沿着编号递…

CSS import 规则

导入 “navigation.css” 样式到当前的样式表&#xff1a; import “navigation.css”; /* 使用字符串 / 或者 import url(“navigation.css”); / 使用 url 地址 */ 属性定义及使用说明 CSS import 用于从其他样式表导入样式规则。 import 规则必须在 CSS 文档的头部&#xff…

[HITCON 2017]SSRFme perl语言的 GET open file 造成rce

这里记录学习一下 perl的open缺陷 这里首先本地测试一下 发现这里使用open打开 的时候 如果通过管道符 就会实现命令执行 然后这里注意的是 perl 中的get 调用了 open的参数 所以其实我们可以通过管道符实现命令执行 然后这里如果file可控那么就继续可以实现命令执行 这里就…

计算机基础知识67--BBS

迁移表格 # 以后你写的每个python项目&#xff0c;都必须有一个txt文件叫 requirements.txt,里面放了当前项目所有的依赖&#xff0c;别人拿到项目---》需要执行 pip install -r requirements.txt # 装好该项目所有依赖 django3.2.20 # 模块 pillow mysqlclient # 主体项目功…

第一课【习题】使用DevEco Studio高效开发

用哪一种装饰器修饰的组件可作为页面入口组件 ArkTS Stage模型支持API Version 9&#xff0c;关于其工程目录结构说法正确的是&#xff1f; 4. DevEco Studio提供模拟器供开发者运行和调试HarmonyOS应用/服务&#xff0c;以下说法错误的是&#xff1f; DevEco Studio支持使…

执行npm run dev报Error: error:0308010C:digital envelope routines::unsupported问题

vue2element-ui项目&#xff0c;在执行npm run dev的时候突然报错&#xff1a; (node:19424) [DEP0111] DeprecationWarning: Access to process.binding(http_parser) is deprecated. (Use node --trace-deprecation ... to show where the warning was created) Er…

尝试通过AI模型进行简单的编码

一、前言 最近尝试通过AI来编程&#xff0c;总体感觉还是能处理写简单的问题&#xff0c;复杂的问题目前还是无法解决。主要的痛点还是数据噪音&#xff0c;就是AI永远不会承认它不会&#xff0c;它会给你的一个错误的信息&#xff0c;它也不会告诉你你的问题它暂时无法完整正…

多段图问题-动态规划解法

一、多段图问题 问题描述&#xff1a;设图G(V, E)是一个带权有向图&#xff0c;如果把顶点集合V划分成k个互不相交的子集Vi (2≤k≤n, 1≤i≤k)&#xff0c;使得对于E中的任何一条边(u, v)&#xff0c;必有u∈Vi&#xff0c;v∈Vim (1≤i≤k, 1&#xff1c;im≤k)&#xff0c;…

【带头学C++】----- 九、类和对象 ---- 9.4 拷贝构造函数、赋值

目录 9.4 拷贝构造函数、赋值 9.4.1 定义拷贝构造函数 9.4.2 拷贝构造和无参构造、有参构造的关系 9.4.3 拷贝构造的几种调用形式 1、旧对象给新对象初始化&#xff0c;调用拷贝构造 2、给对象取别名不会调用拷贝构造 3、普通对象作为函数参数&#xff0c;调用函数时会发…

【Java用法】Hutool树结构工具-TreeUtil快速构建树形结构的两种方式 + 数据排序

Hutool树结构工具-TreeUtil快速构建树形结构的两种方式 数据排序 一、业务场景二、Hutool官网树结构工具2.1 介绍2.2 使用2.2.1 定义结构2.2.2 构建Tree2.2.3 自定义字段名 2.3 说明 三、具体的使用场景3.1 实现的效果3.2 业务代码3.3 实现自定义字段的排序 四、踩过的坑4.1 坑…