C# 计算器设计 代码,及过程图解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 计算器设计 代码,及过程图解相关的知识,希望对你有一定的参考价值。

C#设计计算机 过程 全解............

你看行不,你慢慢的看就没有什么问题的啊!QQ联系877737008
C#编写的windows计算器
初学C#时写的比较基础的windows Form 程序,该计算器实现了基础的数学运算,如加,减,乘,除等任务.主要是通过该程序学习vs.net的编程环境,以及windows Form程序. 如图
步骤如下:
1.新建一个windows应用程序
2.在窗体上添加21个按钮作为计算器的按键,并设计这些控件的Name和Text属性,再在表单中添加一个文本框控件,将其Text属性设为空。
3.设置清除按钮btn_clear,并添加清除所有全局变量及文本框内容的代码,在form1.cs中定义一个方法append_num(i),用于处理编辑框中输入的数字;为数字为0的按钮添加click事件btuuon0_click,在该事件的处理代码中处理所有数字的输入,然后其他的数字按钮共享该代码,所有这些按钮通过sender对象来确定当前用户选择的安钮;为”+“号按钮添加click事件btn_plus_click事件,并使log,exp,sqrt等按钮的ckick事件共享该事件的代码。
下面是Form1.cs的代码:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace jisuanqi

/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form

private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.Button button7;
private System.Windows.Forms.Button button8;
private System.Windows.Forms.Button button9;
private System.Windows.Forms.Button btn_clear;
private System.Windows.Forms.TextBox textBox1;
/// <summary>
/// 必需的设计器变量。
public double dblFirst=0.0;//用来存放第一个操作数
public double dblSecond=0.0;//用来存放第二个操作数
public bool blnFirstOper=true; //判断是不是第一个操作符
public bool blnClear=false;
public String strOper; //记录操作符
private System.Windows.Forms.Button btn_dot;
private System.Windows.Forms.Button btn_equ;
private System.Windows.Forms.Button btn_plus;
private System.Windows.Forms.Button btn_minus;
private System.Windows.Forms.Button btn_mul;
private System.Windows.Forms.Button btn_div;
private System.Windows.Forms.Button btn_abs;
private System.Windows.Forms.Button btn_sqrt;
private System.Windows.Forms.Button btn_exp;
private System.Windows.Forms.Button btn_log;
private System.Windows.Forms.Button button0;

/// </summary>
private System.ComponentModel.Container components = null;

public Form1()

//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();

//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//


/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )

if( disposing )

if (components != null)

components.Dispose();


base.Dispose( disposing );


#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()

this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.button5 = new System.Windows.Forms.Button();
this.button6 = new System.Windows.Forms.Button();
this.button7 = new System.Windows.Forms.Button();
this.button8 = new System.Windows.Forms.Button();
this.button9 = new System.Windows.Forms.Button();
this.button0 = new System.Windows.Forms.Button();
this.btn_dot = new System.Windows.Forms.Button();
this.btn_equ = new System.Windows.Forms.Button();
this.btn_clear = new System.Windows.Forms.Button();
this.btn_plus = new System.Windows.Forms.Button();
this.btn_minus = new System.Windows.Forms.Button();
this.btn_mul = new System.Windows.Forms.Button();
this.btn_div = new System.Windows.Forms.Button();
this.btn_abs = new System.Windows.Forms.Button();
this.btn_sqrt = new System.Windows.Forms.Button();
this.btn_exp = new System.Windows.Forms.Button();
this.btn_log = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button1.Location = new System.Drawing.Point(24, 184);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(48, 32);
this.button1.TabIndex = 0;
this.button1.Text = "1";
this.button1.Click += new System.EventHandler(this.button0_Click);
//
// button2
//
this.button2.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button2.Location = new System.Drawing.Point(104, 184);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(48, 32);
this.button2.TabIndex = 1;
this.button2.Text = "2";
this.button2.Click += new System.EventHandler(this.button0_Click);
//
// button3
//
this.button3.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button3.Location = new System.Drawing.Point(184, 184);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(48, 32);
this.button3.TabIndex = 2;
this.button3.Text = "3";
this.button3.Click += new System.EventHandler(this.button0_Click);
//
// button4
//
this.button4.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button4.Location = new System.Drawing.Point(24, 128);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(48, 32);
this.button4.TabIndex = 3;
this.button4.Text = "4";
this.button4.Click += new System.EventHandler(this.button0_Click);
//
// button5
//
this.button5.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button5.Location = new System.Drawing.Point(104, 128);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(48, 32);
this.button5.TabIndex = 4;
this.button5.Text = "5";
this.button5.Click += new System.EventHandler(this.button0_Click);
//
// button6
//
this.button6.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button6.Location = new System.Drawing.Point(184, 128);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(48, 32);
this.button6.TabIndex = 5;
this.button6.Text = "6";
this.button6.Click += new System.EventHandler(this.button0_Click);
//
// button7
//
this.button7.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button7.Location = new System.Drawing.Point(24, 80);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(48, 32);
this.button7.TabIndex = 6;
this.button7.Text = "7";
this.button7.Click += new System.EventHandler(this.button0_Click);
//
// button8
//
this.button8.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button8.Location = new System.Drawing.Point(104, 80);
this.button8.Name = "button8";
this.button8.Size = new System.Drawing.Size(48, 32);
this.button8.TabIndex = 7;
this.button8.Text = "8";
this.button8.Click += new System.EventHandler(this.button0_Click);
//
// button9
//
this.button9.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button9.Location = new System.Drawing.Point(184, 80);
this.button9.Name = "button9";
this.button9.Size = new System.Drawing.Size(48, 32);
this.button9.TabIndex = 8;
this.button9.Text = "9";
this.button9.Click += new System.EventHandler(this.button0_Click);
//
// button0
//
this.button0.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.button0.Location = new System.Drawing.Point(24, 240);
this.button0.Name = "button0";
this.button0.Size = new System.Drawing.Size(48, 32);
this.button0.TabIndex = 9;
this.button0.Text = "0";
this.button0.Click += new System.EventHandler(this.button0_Click);
//
// btn_dot
//
this.btn_dot.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_dot.Location = new System.Drawing.Point(104, 240);
this.btn_dot.Name = "btn_dot";
this.btn_dot.Size = new System.Drawing.Size(48, 32);
this.btn_dot.TabIndex = 10;
this.btn_dot.Text = ".";
this.btn_dot.Click += new System.EventHandler(this.btn_dot_Click);
//
// btn_equ
//
this.btn_equ.Font = new System.Drawing.Font("LiSu", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_equ.Location = new System.Drawing.Point(184, 240);
this.btn_equ.Name = "btn_equ";
this.btn_equ.Size = new System.Drawing.Size(48, 32);
this.btn_equ.TabIndex = 11;
this.btn_equ.Text = "=";
this.btn_equ.Click += new System.EventHandler(this.btn_equ_Click);
//
// btn_clear
//
this.btn_clear.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_clear.Location = new System.Drawing.Point(24, 16);
this.btn_clear.Name = "btn_clear";
this.btn_clear.Size = new System.Drawing.Size(48, 32);
this.btn_clear.TabIndex = 12;
this.btn_clear.Text = "C";
this.btn_clear.Click += new System.EventHandler(this.btn_clear_Click);
//
// btn_plus
//
this.btn_plus.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_plus.Location = new System.Drawing.Point(264, 240);
this.btn_plus.Name = "btn_plus";
this.btn_plus.Size = new System.Drawing.Size(48, 32);
this.btn_plus.TabIndex = 13;
this.btn_plus.Text = "+";
this.btn_plus.Click += new System.EventHandler(this.btn_plus_Click);
//
// btn_minus
//
this.btn_minus.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_minus.Location = new System.Drawing.Point(264, 184);
this.btn_minus.Name = "btn_minus";
this.btn_minus.Size = new System.Drawing.Size(48, 32);
this.btn_minus.TabIndex = 14;
this.btn_minus.Text = "-";
this.btn_minus.Click += new System.EventHandler(this.btn_plus_Click);
//
// btn_mul
//
this.btn_mul.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_mul.Location = new System.Drawing.Point(264, 128);
this.btn_mul.Name = "btn_mul";
this.btn_mul.Size = new System.Drawing.Size(48, 32);
this.btn_mul.TabIndex = 15;
this.btn_mul.Text = "*";
this.btn_mul.Click += new System.EventHandler(this.btn_plus_Click);
//
// btn_div
//
this.btn_div.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_div.Location = new System.Drawing.Point(264, 80);
this.btn_div.Name = "btn_div";
this.btn_div.Size = new System.Drawing.Size(48, 32);
this.btn_div.TabIndex = 16;
this.btn_div.Text = "/";
this.btn_div.Click += new System.EventHandler(this.btn_plus_Click);
//
// btn_abs
//
this.btn_abs.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_abs.Location = new System.Drawing.Point(344, 240);
this.btn_abs.Name = "btn_abs";
this.btn_abs.Size = new System.Drawing.Size(48, 32);
this.btn_abs.TabIndex = 17;
this.btn_abs.Text = "abs";
this.btn_abs.Click += new System.EventHandler(this.btn_abs_Click);
//
// btn_sqrt
//
this.btn_sqrt.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_sqrt.Location = new System.Drawing.Point(344, 184);
this.btn_sqrt.Name = "btn_sqrt";
this.btn_sqrt.Size = new System.Drawing.Size(48, 32);
this.btn_sqrt.TabIndex = 18;
this.btn_sqrt.Text = "sqrt";
this.btn_sqrt.Click += new System.EventHandler(this.btn_abs_Click);
//
// btn_exp
//
this.btn_exp.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_exp.Location = new System.Drawing.Point(344, 128);
this.btn_exp.Name = "btn_exp";
this.btn_exp.Size = new System.Drawing.Size(48, 32);
this.btn_exp.TabIndex = 19;
this.btn_exp.Text = "exp";
this.btn_exp.Click += new System.EventHandler(this.btn_abs_Click);
//
// btn_log
//
this.btn_log.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.btn_log.Location = new System.Drawing.Point(344, 80);
this.btn_log.Name = "btn_log";
this.btn_log.Size = new System.Drawing.Size(48, 32);
this.btn_log.TabIndex = 20;
this.btn_log.Text = "log";
this.btn_log.Click += new System.EventHandler(this.btn_abs_Click);
//
// textBox1
//
this.textBox1.Font = new System.Drawing.Font("SimSun", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.textBox1.Location = new System.Drawing.Point(136, 16);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(256, 32);
this.textBox1.TabIndex = 23;
this.textBox1.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(440, 302);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.btn_log);
this.Controls.Add(this.btn_exp);
this.Controls.Add(this.btn_sqrt);
this.Controls.Add(this.btn_abs);
this.Controls.Add(this.btn_div);
this.Controls.Add(this.btn_mul);
this.Controls.Add(this.btn_minus);
this.Controls.Add(this.btn_plus);
this.Controls.Add(this.btn_clear);
this.Controls.Add(this.btn_equ);
this.Controls.Add(this.btn_dot);
this.Controls.Add(this.button0);
this.Controls.Add(this.button9);
this.Controls.Add(this.button8);
this.Controls.Add(this.button7);
this.Controls.Add(this.button6);
this.Controls.Add(this.button5);
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "计算器";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);


#endregion

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()

Application.Run(new Form1());


private void button0_Click(object sender, System.EventArgs e)

if(sender==button0)append_num(0);
if(sender==button1)append_num(1);
if(sender==button2)append_num(2);
if(sender==button3)append_num(3);
if(sender==button4)append_num(4);
if(sender==button5)append_num(5);
if(sender==button6)append_num(6);
if(sender==button7)append_num(7);
if(sender==button8)append_num(8);
if(sender==button9)append_num(9);



private void btn_clear_Click(object sender, System.EventArgs e)

dblFirst=0.0;
dblSecond=0.0;
blnFirstOper=true;
blnClear=false;
textBox1.Text="";
textBox1.Focus();


private void btn_dot_Click(object sender, System.EventArgs e)

if(textBox1.Text=="")
textBox1.Text="0";
else
textBox1.Text=textBox1.Text+".";
blnClear=false;



private void btn_equ_Click(object sender, System.EventArgs e)

if(textBox1.Text!="")
if(blnFirstOper==true)
dblFirst=Convert.ToDouble(textBox1.Text);
else
dblSecond=Convert.ToDouble(textBox1.Text);
switch(strOper)

case"+":
dblFirst+=dblSecond;
break;
case"-":
dblFirst-=dblSecond;
break;
case"*":
dblFirst*=dblSecond;
break;
case"/":
dblFirst/=dblSecond;
break;

strOper="=";
blnFirstOper=false;
textBox1.Text=Convert.ToString(dblFirst);
blnClear=true;


private void btn_plus_Click(object sender, System.EventArgs e)

if(textBox1.Text!="")
if(blnFirstOper==true)
dblFirst=Convert.ToDouble(textBox1.Text);
else
dblSecond=Convert.ToDouble(textBox1.Text);
switch(strOper)

case"+":
dblFirst+=dblSecond;
break;
case"-":
dblFirst-=dblSecond;
break;
case"*":
dblFirst*=dblSecond;
break;

case"/":
dblFirst/=dblSecond;
break;

if(sender==btn_plus)
strOper="+";
else if(sender==btn_minus)
strOper="-";
if(sender==btn_mul)
strOper="*";
if(sender==btn_div)
strOper="/";
blnFirstOper=false;
textBox1.Text=Convert.ToString(dblFirst);
blnClear=true;


private void btn_abs_Click(object sender, System.EventArgs e)

double tx;
tx=Convert.ToDouble(textBox1.Text);
if(sender==btn_abs)
textBox1.Text=Convert.ToString(Math.Abs(tx));
else if(sender==btn_sqrt)

if(tx<0)
MessageBox.Show("负数不能计算平方根");
else
textBox1.Text=Convert.ToString(Math.Sqrt(tx));

else if(sender==btn_exp)
textBox1.Text=Convert.ToString(Math.Exp(tx));
else if(sender==btn_log)

if(tx<0)
MessageBox.Show("负数不能计算对数");
else
textBox1.Text=Convert.ToString(Math.Log(tx));



private void append_num(int i)

if(blnClear)

if(blnFirstOper==true)
dblFirst=Convert.ToDouble(textBox1.Text);
else
dblSecond=Convert.ToDouble(textBox1.Text);
textBox1.Text="";
blnClear=false;

if((textBox1.Text!="")||(i!=0))
textBox1.Text=textBox1.Text+i.ToString();
else
textBox1.Text="0";




参考技术A 我刚做了个,功能还不错,注释也写的很详细,相信如果你有点底子的话应该看的懂,但是你是不是给点分呢? 参考技术B 你帮我写一个吧,只要过程,我还给你5分~ 参考技术C 我到是做过一个,不过,要这么详细给你说而且还.......
就.........

为 GlusterFS 设计新的xlator (编译及调用过程分析)

GlusterFS 是一个开源的网络分布式文件系统,前一阵子看了一点GlusterFS(Gluster)的代码,修改了部分代码,具体是增加了一个定制的xlator,简单记录一下。

Gluster与xlator

随着计算机技术的发展,不管哪一个领域的数据都呈现出爆炸性增长的趋势,因此产生了大数据处理与存储技术。单机的存储基本不可能满足大量离线数据(文本)的存储需求了,于是在网络分布式文件系统越来越受到重视。开源的分布式文件系统非常多,GlusterFSLustreCephHDFSFastDFS,关于这些文件系统的分类与区别,可以参考这里,我觉得从块,文件,对象的角度划分比较靠谱。我本是做高性能计算的存储方面研究的,阴差阳错地入了Gluster的坑,具体原因不表了。

Gluster是基于FUSE的用户态文件系统,意味着编译安装Gluster不需要去牵涉内核,关于FUSE,其实Gluster做的比较粗暴,用一个死循环去读取/dev/fuse这个块设备,再丢给客户端或者网络,但是FUSE的原理还是值得去研究的,我也是一知半解。兼容POSIX标准,意味着Linux标准库的read,write等I/O函数不需要经过修改就可以在Gluster上运行。

一个网络分布式文件系统的套路通常是,服务端有多台机子构成一个统一的名字空间,文件以某种分布方式存放在不同的服务器上。而客户端看到的却是一个整体,如一个目录,并且客户端可以被挂载在多个不同的节点,因此可以随时随地访问你的数据。每个文件系统为了实现这一套,都会有各种各样的概念,但本质都是一样的,例如Gluster里面有一些基础的概念, 其中brick是一个存储节点上的一个输出目录, volume是一系列的brick,代表一个功能子集,translator(xlator)是连接子volume的,xlator本身也是某一个volume的具体实现。

Gluster支持多种数据分布方式:

  1. Distributed(默认分布方式)
    一个文件分布在一个brick上,不同的文件可能分布在不同的brick上。没有容错。Distributed方式的分配粒度是文件。
    技术分享图片

  2. Replicated
    每一个文件都会在每个brick存一个copy,replica数目可以由配置文件指定。Replicated的分配粒度是文件。
    技术分享图片

  3. Distributed Replicated volume
    前两者的结合,brick的数量是replia的n倍,假如有N个brick,replica是2,则distribute数目是N/2,相邻的两个brick互为备份。先distribute,再replicate。
    技术分享图片

  4. Striped Volume
    文件被分成固定大小的块,以RR方式分布在不同的服务器上。Striped的分配粒度是文件块。
    技术分享图片

  5. Distributed Striped volume
    与striped 方式不同的是,file只在特定的brick上面stripe,相当于先distribute,再stripe。
    技术分享图片

xlator是Gluster设计的精髓所在,每一个功能都可以用一个xlator来实现,例如每种分布规则对应一个xlator,另外一些feature可以封装在一个xlator中,如文件加密。并且可以在配置文件中各种xlator混合,嵌套使用,每个xlator编译后会生成一个动态链接库,运行时按需加载。

举一个例子,上面五种分布方式的第五种 Distributed Striped Volume,他的配置文件这样写:

*************************************************************
### Add client feature and attach to remote subvolume

##  client 1
volume client1
  type protocol/client
  option transport-type tcp/client
  option remote-host  10.0.0.1 # IP address of the remote brick
  option remote-port 6996 # default server port is 6996
  option remote-subvolume brick1 # name of the remote volume
end-volume

## client 2
volume client2
  type protocol/client
  option transport-type tcp/client
  option remote-host 10.0.0.2
  option remote-port 6996
  option remote-subvolume brick2
end-volume

## client 3
volume client3
  type protocol/client
  option transport-type tcp/client
  option remote-host 10.0.0.3
  option remote-port 6996
  option remote-subvolume brick3
end-volume

## client 4
volume client4
  type protocol/client
  option transport-type tcp/client
  option remote-host 10.0.0.4
  option remote-port 6996
  option remote-subvolume brick4
end-volume

#stripe, subvolume is clients
volume stripe1
  type cluster/stripe
  subvolumes client1 client2
end-volume

volume stripe2
  type cluster/stripe
  subvolumes client3 client4
end-volume

#distribute, subvolume is stripes
volume dht
  type cluster/distribute
  subvolumes stripe1 stripe2
end-volume

配置文件是一种树形的xlator结构,树的根是fuse_xlator_t,在配置文件初始化的时候,由根向叶子深度优先初始化。写配置文件的顺序与Gluster读配置的顺序是相反的,例如:dht最先被读取。client端的配置文件的写法要比server端复杂,server端只需要指定哪个目录输出就足够了。

技术分享图片

如图所示,左边是客户端的xlator嵌套关系,fuse初始化之后会初始化子卷 subvolume,即调用dht的初始化函数,依次完成初始化。同样,一个I/O请求被FUSE接受,会经过一些封装传递给dht,dht可能经过一些定位,传递给他的某一个subvolume,...一直请求由client xlator通过网络包发给对应的server。server端收到请求也同样是一样的嵌套处理,最终会把请求送到posix xlator,这个xlator里封装了最原始的系统调用,read,write等。这就是Gluster整个系统的执行流程。

技术分享图片

上图是官方文档提供的所有类型的xlator,具体都可以在源代码xlators/目录里找到。

xlator中的调用(STACK_WIND)与回调(STACK_UNWIND)

Gluster在不同层级的xlator之间的通信有点类似于递归,主要依赖于代码中的两个宏,分别是STACK_WINDSTACK_UNWIND。每一个xlator中的相关函数都有一对,如 write 函数有着对应的 write_cbk 函数,两个函数与两个宏定义配合使用。

技术分享图片

我们把xlator的关系简化成三层,FUSE,DHT,POSIX,关系如上图左边所示。假设系统从/dev/fuse中读到了一个write请求,系统将这个请求丢给FUSE xlator,在FUSE xlator中调用fuse_write,通过STACK_WIND将请求传递给他的subvolume,调用subvolume对应的write函数,即dht_write, dht_write同理通过STACK_WIND调用posix_write。在图中posix是最底层的xlator,因此posix_write将不会调用STACK_WIND,而是调用STACK_UNWIND将返回值或者结果返回给父volume,对应着调用父volume中的_cbk函数,即dht_write_cbk,该函数做完相应的处理后继续通过STACK_UNWIND返回到fuse_write_cbk中,这样一个write才算完成。

调用 (STACK_WIND)

接着具体分析一下STACK_WIND是如何工作的。下面是STACK\_WIND的宏定义。

/* make a call */
#define STACK_WIND(frame, rfn, obj, fn, params ...)                                do {                                                                                call_frame_t *_new = NULL;                                                xlator_t     *old_THIS = NULL;                                                                                                                  _new = CALLOC (1, sizeof (call_frame_t));                                ERR_ABORT (_new);                                                        typeof(fn##_cbk) tmp_cbk = rfn;                                                _new->root = frame->root;                                                _new->next = frame->root->frames.next;                                        _new->prev = &frame->root->frames;                                        if (frame->root->frames.next)                                                        frame->root->frames.next->prev = _new;                                frame->root->frames.next = _new;                                        _new->this = obj;                                                        _new->ret = (ret_fn_t) tmp_cbk;                                                _new->parent = frame;                                                        _new->cookie = _new;                                                        LOCK_INIT (&_new->lock);                                                frame->ref_count++;                                                                                                                                old_THIS = THIS;                                                        THIS = obj;                                                             fn (_new, obj, params);                                                        THIS = old_THIS;                                                } while (0)

在dht xlator中,dht_write 函数里这样调用STACK_WIND:

STACK_WIND (frame, dht_writev_cbk,
                    subvol, subvol->fops->writev,
                    fd, vector, count, off, iobref);

把参数代入到宏定义中,可以按照下面的代码理解:

new->parent = frame;
new->this = subvolume;
typeof(fn##_cbk) tmp_cbk = dht_writev_cbk;
new->ret = (ret_fn_t) tmp_cbk; 
fn = subvol->fops->writev;
params = {fd, vector, count, off, iobref};
obj = subvol;
//用subvolume->fop->writev 
//参数为new,new为新的frame,  new的父节点设置为frame,
//obj 就是subvolume
fn (_new, obj, params);

可以看到STACK_WIND主要做了三件微小的事,1 传递调用之间的上下文,代码中是frame 这个数据结构,2 记录当前函数的回调函数,一般是对应的cbk函数,也有特例,像dht xlator中逻辑比较复杂的lookup操作(关于Gluster的核心dht xlator的调用分析可以参考这里),3 调用子subvolume的对应函数,将操作向下传递。

因此按照我们简化的xlator关系,即dht的subvolume是posix,那上面的STACK_WIND就调用了posix_writev

posix_writev (call_frame_t *frame, xlator_t *this,
          fd_t *fd,struct iovec *vector, int32_t count,
          off_t offset,struct iobref *iobref))

回调 (STACK_UNWIND)

接下来看一下STACK_UNWIND的工作原理。Gluster中有两种回调的宏,一个是STACK_UNWIND, 另一个是STACK_UNWIND_STRICT,两者的差别只是第一个参数,原理是一样的。通常xlator源码里面用的是STACK_UNWIND_STRICT,原因在宏定义的注释里写了,STACK_UNWIND_STRICT是类型安全的。下面是STACK_UNWIND_STRICT的宏定义。

/* return from function in type-safe way */
#define STACK_UNWIND_STRICT(op, frame, params ...)                              do {                                                                                fop_##op##_cbk_t      fn = NULL;                                        call_frame_t *_parent = NULL;                                           xlator_t     *old_THIS = NULL;                                                                                                                  fn = (fop_##op##_cbk_t )frame->ret;                                     _parent = frame->parent;                                                _parent->ref_count--;                                                        old_THIS = THIS;                                                        THIS = _parent->this;                                                   frame->complete = _gf_true;                                             fn (_parent, frame->cookie, _parent->this, params);                        THIS = old_THIS;                                                } while (0)

前面提到如果你的xlator是最底层的(如客户端的client xlator,服务端的posix xlator),那么这个xlator里不应该存在 xxx_cbk 函数,而是在操作返回之前调用STACK_UNWIND或者STACK_UNWIND_STRICK。posix xlator里面用的是STACK_UNWIND_STRICT 向父volume返回。 STACK_UNWIND_STRICT的第一句是将第一个参数连接成cbk函数,以下是posix的调用:

STACK_UNWIND_STRICT (writev, frame, op_ret, op_errno, &preop, &postop);

把参数代入到宏定义中,可以按照下面的代码理解:

//这里的frame就是STACK_WIND里的obj
//因此 fn = dht_writev_cbk
fn = (fop_writev_cbk_t)frame->ret;
//parent 就是dht的frame  
_parent = frame->parent;
//因此这里调用的是
//dht_writev_cbk(dht_frame,posix_frame,dht,params);
//实际第二个cokkie参数在dht_write_cbk会被忽略
fn (_parent, frame->cookie, _parent->this, params); 

可以看到替换后,首先将上下文换成正确的上下文,即父volume的frame,然后代码的最后一句实际是调用了父volume的 cbk 方法,即dht_write_cbk,在dht_write_cbk里会继续调用STACK_UNWIND_STRICT, 这样就会将结果返回到根xlator。

工程编译,configure与make

为Gluster新增xlator实际是改变了源码的结构,因此要想xlator正确工作,需要了解一下自动编译的知识。首先看一下Gluster的代码结构:

技术分享图片

Gluster里提供了一个默认的xlator模板叫做defaults,在libglusterfs/src/defaults.c里,里面定义了一个文件系统基本操作,包括cbk方法,但是他不做任何操作,方法里面只有基本的STACK_WINDSTACK_UNWIND调用。假设我们要在cluster中加一个新的分布规则叫dadada,那应该在对应的目录下新建自己的目录和源码,如图:

技术分享图片

然后需要将新增的xlator加到编译选项中。为此我特意了解了一下C语言大型工程的编译套路,仅仅也是能够修改的水平。首先基础的编译方法是用make命令执行Makefile文件,GNU提供了一系列的工具帮助我们自动生成Makefile文件。下面是生成Makefile的操作过程(原图):

技术分享图片

首先通过autoscan根据源代码生成对应的configure.ac(或者configure.in)文件,不过通常这一步不需要我们做,一般开源项目里都提供了configure.ac文件。然后aclocal命令根据configure.ac生成aclocal.m4,再运行autoconf命令生成configure文件,然后需要运行automake -a命令生成makefile.in,但这三个步骤Gluster里面有一个autogen.sh的脚本帮我们做了。生成的configure文件是可以执行的,必要的时候修改一下文件权限。执行configure文件,该文件会和makefile.in一起生成所需要的Makefile文件。

因此可以看到,在编译中通常我们只需要提供configure.ac(configure.in)Makefile.am两种文件,其他都是通过工具自动生成的。所以我们要为我们的dadada做以下修改:

1 修改configure.ac, 将cluster/dadadacluster/dadada/src 仿照其他的结构添加到configure.ac中。当然要修改的不只下图中的一处。

技术分享图片

2 修改Makefile.am,包括cluster/Makefile.am,cluster/dadada/Makefile.am, cluster/dadada/src/Makefile.am,基本就是改一些名字。

# cluster/Makefile.am
SUBDIRS = stripe afr dht ec dadada

CLEANFILES = 

# cluster/dadada/Makefile.am
SUBDIRS = src

# cluster/dadada/src/Makefile.am  根据代码的结构修改

xlator_LTLIBRARIES = dadada.la
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/cluster

dadada_la_SOURCES = dadada.c 

dadada_la_LDFLAGS = -module -avoidversion
dadada_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la

noinst_HEADERS = dadada.h

AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -fno-strict-aliasing -D$(GF_HOST_OS)     -I$(top_srcdir)/liblwfs/src $(GF_CFLAGS) -shared -nostartfiles

CLEANFILES = 

uninstall-local:
    rm -f $(DESTDIR)$(xlatordir)/dadada.so

3 运行autogen.sh,该脚本是用aclocal和autoconf生成configure文件,以及用automake生成Makefile.in
4 运行configure, configure是用Makefile.in 生成Makefile
5 make && make install

配置文件以及其他

在完成编译之后便可以自己写配置文件进行测试了,一个示例的配置文件:

##  client 1
volume client1
  type protocol/client
  option transport-type tcp/client
  option remote-host  10.0.0.1 # IP address of the remote brick
  option remote-port 6996 # default server port is 6996
  option remote-subvolume brick1 # name of the remote volume
end-volume

## client 2
volume client2
  type protocol/client
  option transport-type tcp/client
  option remote-host 10.0.0.2
  option remote-port 6996
  option remote-subvolume brick2
end-volume

#dadada, subvolume is clients
volume dadada
  type cluster/dadada
  subvolumes client1 client2
end-volume

以上就是关于增加xlator所能想起来的基础知识,当然写一个xlator是非常困难的,需要理解和研究的东西的太多。有一个建议就是涉及逻辑的操作最好在cbk函数里面做处理,嵌套调用写在 STACK_UNWIND 前面。另外Gluster在高性能领域用的比较少,所有的文件系统都是有利有弊的,例如Gluster的一大特色就是没有集中的元数据服务器,文件的定位是根据文件名计算hash值来做的,因此Gluster没有分布式文件系统中常见的元数据瓶颈问题,但是在没有指定文件名时候做查询(ls),Gluster性能就不会很好,因为要全盘扫描,关于Gluster性能的探讨,推荐这个系列的博客。关于Gluster开发过程的调试方法,可以参考这里

以上。

参考
https://www.gluster.org/
http://lustre.org/
http://ceph.com/
https://hadoop.apache.org/docs/r1.0.4/cn/hdfs_design.html
https://github.com/happyfish100/fastdfs
https://turodj.gitbooks.io/those-things-about-architecture/content/cun_chu.html
http://gluster.readthedocs.org/en/latest/Administrator%20Guide/glossary/
http://lidawn.github.io/2015/04/30/parallel-io-basic/
http://blog.csdn.net/liuhong1123/article/details/8118258
https://www.ibm.com/developerworks/cn/linux/l-makefile/
http://blog.csdn.net/liuaigui/article/details/6284551
http://pl.atyp.us/hekafs.org/index.php/2011/11/

原文地址 https://lidawn.github.io/2016/11/28/glusterfs-xlator/

























以上是关于C# 计算器设计 代码,及过程图解的主要内容,如果未能解决你的问题,请参考以下文章

对于‘用C#编写一个员工工资计算’问题的代码编写风格和结构设计考虑的比较发现自己还是太弱,大家可以在评论区中提出我代码中的不足

图解后缀表达式的计算过程

服务器端架构及实战 — C#分享

图解后缀表达式的计算过程

C#图解教程 第六章 深入理解类

图解TensorFlow架构与设计