分类 Blog 下的文章

2023年法定节假日

2022-12-31,
2023-01-01,
2023-01-02,
2023-01-21,
2023-01-22,
2023-01-23,
2023-01-24,
2023-01-25,
2023-01-26,
2023-01-27,
2023-04-05,
2023-04-29,
2023-04-30,
2023-05-01,
2023-05-02,
2023-05-03,
2023-06-22,
2023-06-23,
2023-06-24,
2023-09-29,
2023-09-30,
2023-10-01,
2023-10-02,
2023-10-03,
2023-10-04,
2023-10-05,
2023-10-06,

2023年调休

2023-01-28,
2023-01-29,
2023-04-23,
2023-05-06,
2023-06-25,
2023-10-07,
2023-10-08,

ASN.1 - 数据结构描述语言

引用自Wiki

ASN.1 is a standard interface description language for defining data structures that can be serialized and deserialized in a cross-platform way.

也就是说ASN.1是一种用来定义数据结构的接口描述语言,它不是二进制,也不是文件格式,看下面的例子你就会明白了:

FooQuestion ::= SEQUENCE {
    trackingNumber INTEGER,
    question       IA5String
}

这段代码定义了FooQuestion的数据结构,下面是FooQuestion这个数据接口的某个具体的数据:

myQuestion FooQuestion ::= SEQUENCE {
    trackingNumber     5,
    question           "Anybody there?"
}

ASN.1用在很多地方比如下面要讲的X.509PKCS group of cryptography standards

文件编码格式

DER编码格式

引用自Wiki

ASN.1 is closely associated with a set of encoding rules that specify how to represent a data structure as a series of bytes

意思是ASN.1有一套关联的编码规则,这些编码规则用来规定如何用二进制来表示数据结构,DER是其中一种。

把上面的FooQuestion的例子用DER编码则是(16进制):

30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f

翻译过来就是:

30 — type tag indicating SEQUENCE
13 — length in octets of value that follows
  02 — type tag indicating INTEGER
  01 — length in octets of value that follows
    05 — value (5)
  16 — type tag indicating IA5String 
     (IA5 means the full 7-bit ISO 646 set, including variants, 
      but is generally US-ASCII)
  0e — length in octets of value that follows
    41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f — value ("Anybody there?")

看到这里你应该对DER编码格式有一个比较好的认识了。

PEM编码格式

引用自Wiki

Privacy-Enhanced Mail (PEM) is a de facto file format for storing and sending cryptographic keys, certificates, and other data, based on a set of 1993 IETF standards defining “privacy-enhanced mail.”

PEM是一个用来存储和发送密码学key、证书和其他数据的文件格式的事实标准。许多使用ASN.1的密码学标准(比如X.509PKCS)都使用DER编码,而DER编码的内容是二进制的,不适合与邮件传输(早期Email不能发送附件),因此使用PEM把二进制内容转换成ASCII码。文件内容的格式像下面这样:

-----BEGIN label-----
BASE64Encoded
-----END label-----

label用来区分内容到底是什么类型,下面会讲。

和PEM相关的RFC有很多,与本文内容相关的则是RFC7468,这里面规定了很多label,不过要注意不是所有label都会有对应的RFC或Specification,这些label只是一种约定俗成。

PEM实际上就是把DER编码的文件的二进制内容用base64编码一下,然后加上-----BEGIN label-----这样的头和-----END label-----这样的尾,中间则是DER文件的Base64编码。

我们可以通过下面的方法验证这个结论,先生成一个RSA Private Key,编码格式是PEM格式:

openssl genrsa -out key.pem

查看一下文件内容,可以看到label是RSA PRIVATE KEY

----BEGIN RSA PRIVATE KEY-----
BASE64Encoded
-----END RSA PRIVATE KEY-----

然后我们把PEM格式转换成DER格式:

openssl rsa -in key.pem -outform der -out key.der

如果你这个时候看一下文件内容会发现都是二进制。然后我们把DER文件的内容Base64一下,会看到内容和PEM文件一样(忽略头尾和换行):

base64 -i key.der -o key.der.base64

证书、密码学Key格式

上面讲到的PEM是对证书、密码学Key文件的一种编码方式,下面举例这些证书、密码学Key文件格式:

X.509证书

引用自Wiki

In cryptography, X.509 is a standard defining the format of public key certificates. X.509 certificates are used in many Internet protocols, including TLS/SSL, which is the basis for HTTPS, the secure protocol for browsing the web.

X.509是一个Public Key Certificates的格式标准,TLS/SSL使用它,TLS/SSL是HTTPS的基础所以HTTPS也使用它。而所谓Public Key Certificates又被称为Digital CertificateIdentity Certificate

An X.509 certificate contains a public key and an identity (a hostname, or an organization, or an individual), and is either signed by a certificate authority or self-signed.

一个X.509 Certificate包含一个Public Key和一个身份信息,它要么是被CA签发的要么是自签发的。

下面这种张图就是一个X.509 Certificate:

事实上X.509 Certificate这个名词通常指代的是IETF的PKIX Certificate和CRL Profile,见RFC5280。所以当你看到PKIX Certificate字样的时候可以认为就是X.509 Certificate。

PKCS系列

引用自Wiki

In cryptography, PKCS stands for “Public Key Cryptography Standards”

前面提到的X.509是定义Public Key Certificates的格式的标准,看上去和PKCS有点像,但实际上不同,PKCS是Public Key密码学标准。此外Public-Key Cryptography虽然名字看上去只涉及Public Key,实际上也涉及Priviate Key,因此PKCS也涉及Private Key。

PKCS一共有15个标准编号从1到15,这里只挑讲PKCS #1、PKCS #8、PKCS #12。

PKCS #1

PKCS #1,RSA Cryptography Standard,定义了RSA Public Key和Private Key数学属性和格式,详见RFC8017

PKCS #8

PKCS #8,Private-Key Information Syntax Standard,用于加密或非加密地存储Private Certificate Keypairs(不限于RSA),详见RFC5858

PKCS #12

PKCS #12定义了通常用来存储Private Keys和Public Key Certificates(例如前面提到的X.509)的文件格式,使用基于密码的对称密钥进行保护。注意上述Private Keys和Public Key Certificates是复数形式,这意味着PKCS #12文件实际上是一个Keystore,PKCS #12文件可以被用做Java Key Store(JKS),详见RFC7292

openssl pkcs12 -export \
  -in <cert> \
  -inkey <private-key> \
  -name my-cert \
  -caname my-ca-root \
  -CAfile <ca-cert> \
  -chain
  -out <pkcs-file>

PKCS #12一般不导出PEM编码格式。

PEM格式速查

当你不知道你的PEM文件内容是什么格式的可以根据下面查询。

X.509 Certificate

RFC7468 - Textual Encoding of Certificates

-----BEGIN CERTIFICATE-----
BASE64Encoded
-----END CERTIFICATE-----

X.509 Certificate Subject Public Key Info

RFC7468 - Textual Encoding of Subject Public Key Info

-----BEGIN PUBLIC KEY-----
BASE64Encoded
-----END PUBLIC KEY-----

PKCS #1 Private Key

没有RFC或权威Specification,该格式有时候被称为traditional format、SSLeay format(见SO

-----BEGIN RSA PRIVATE KEY-----
BASE64Encoded
-----END RSA PRIVATE KEY-----

PKCS #1 Public Key

同上没有RFC或权威Specification

-----BEGIN RSA PUBLIC KEY-----
BASE64Encoded
-----END RSA PUBLIC KEY-----

PKCS #8 Unencrypted Private Key

RFC7468 - One Asymmetric Key and the Textual Encoding of PKCS #8 Private Key Info

-----BEGIN PRIVATE KEY-----
BASE64Encoded
-----END PRIVATE KEY-----

PKCS #8 Encrypted Private Key

RFC7468 - Textual Encoding of PKCS #8 Encrypted Private Key Info

-----BEGIN ENCRYPTED PRIVATE KEY-----
BASE64Encoded
-----END ENCRYPTED PRIVATE KEY-----

Private Key操作命令

生成

生成PKCS #1格式的RSA Private Key

openssl genrsa -out private-key.p1.pem 2048

转换

PKCS #1 -> Unencrypted PKCS #8

openssl pkcs8 -topk8 -in private-key.p1.pem -out private-key.p8.pem -nocrypt

PKCS #1 -> Encrypted PKCS #8

openssl pkcs8 -topk8 -in private-key.p1.pem -out private-key.p8.pem

过程中会让你输入密码,你至少得输入4位,所以PKCS #8相比PKCS #1更安全。

PKCS #8 -> PKCS #1

openssl rsa -in private-key.p8.pem -out private-key.p1.pem

如果这个PKCS #8是加密的,那么你得输入密码。

PKCS #8 Unencrypted -> PKCS #8 Encrypted

openssl pkcs8 -topk8 -in private-key.p8.nocrypt.pem -out private-key.p8.crypt.pem

过程中会让你输入密码,你至少得输入4位。

PKCS #8 Encrypted -> PKCS #8 Unencrypted

openssl pkcs8 -topk8 -in private-key.p8.crypt.pem -out private-key.p8.nocrypt.pem -nocrypt

过程中会要求你输入Private Key密码。

Public Key操作命令

从PKCS #1/#8提取

提取指的是从Private Key中提取Public Key,openssl rsa同时支持PKCS #1和PKCS #8的RSA Private Key,唯一的区别是如果PKCS #8是加密的,会要求你输入密码。

提取X.509格式RSA Public Key

openssl rsa -in private-key.pem -pubout -out public-key.x509.pem

提取PKCS #1格式RSA Public Key

openssl rsa -in private-key.pem -out public-key.p1.pem -RSAPublicKey_out

从X.509证书提取

openssl x509 -in cert.pem -pubkey -noout > public-key.x509.pem

转换

X.509 RSA Public Key -> PKCS #1 RSA Public Key

openssl rsa -pubin -in public-key.x509.pem -RSAPublicKey_out -out public-key.p1.pem

PKCS #1 RSA Public Key -> X.509 RSA Public Key

openssl rsa -RSAPublicKey_in -in public-key.p1.pem -pubout -out public-key.x509.pem

参考资料

https://chanjarster.github.io/post/x509-pkcs-file-formats/

步骤一:

先将自动更新之类的取消掉。

步骤二:

执行下面两条命令:

defaults write com.apple.systempreferences AttentionPrefBundleIDs 0


Killall Dock

就完成了。

HTML

<form class="layui-form" method="">
<input type="hidden" name="venue_info_id" value="1">
<div class="layui-row" style="padding-top: 40px">
    <div class="layui-form-item text-right">
       <button class="layui-btn" type="button" lay-filter="doCreateEvent" lay-submit>
          <i class="layui-icon">&#xe605;</i>提交保存
       </button>
     </div>
</div>
</form>


JS

form.on('submit(doCreateEvent)', function(data){
    layer.confirm('确定添加预约?', {
        skin: 'layui-layer-admin',
        shade: .1
    }, function (i) {
        layer.close(i);
        var loadIndex = layer.load(2);
        $.post("/api/xxx", data.field, function (res) {
            layer.close(loadIndex);
            if (200 === res.code) {
                layer.msg(res.msg, {icon: 1});
                setTimeout(function (){
                    parent.location.reload();
                }, 2500)
            } else {
                layer.msg(res.msg, {icon: 2});
            }
        });
    });
});



这个可能只有自个能看明白了。

{field: 'start_time', title: '生效时间', templet: function(d) {
    return util.toDateString(d.start_time * 1000, 'yyyy-MM-dd HH:mm:ss')
}},

在弹窗内的

admin.open({
  success: function(mData) {
     //时间选择器
      laydate.render({
         elem: '#start_time',
         type: 'datetime',
         value: mData ? new Date(mData.start_time * 1000) : '',
      });
  }
});


QQ20221008-000133@2x.png

内核:在一些系统中,当系统调用发生时,操作系统或者操作系统内核会编程应用程序内存的一部分。

栈:栈中包含活动记录,其中包含当前活动函数调用的返回地址和局部变量等信息。

共享库:为了动态链接共享库文件而创建的一个内存片段

堆内存:被用作堆内存来使用和分配的一块内存空间。如果运行时需要一些可变大小的小内存块,那么这些内存就是从这个区域中分配的

未初始化的数据: 没有初始化的全局变量被放在固定地址中。通常,这段区域都会被初始化为0。

初始化的数据: 任何被赋予了初始值的数据都被组织在内存中的一段连续的区域内,因此他们就能够与程序页一同被有效地载入

程序页:构成应用程序的机器代码指令就是程序页。当有硬件支持时,程序页通常是只读的,这样就可以防止程序意外的重写其自身指令区域。

第0页:通常,一个以地址0为开始的内存片段会被保留下来被设置为不可读区域,他可以用来捕捉一种常见的错误,这种错误就是使用一个NULL指针访问数据。

第一部分 C++内存地址分配简介

1 内存地址是从高地址到低地址进行分配的:

int i=1;
int j=1;
cout
2 函数参数列表的存放方式是,先对最右边的形参分配地址,后对最左边的形参分配地址。

3 Little-endian模式的CPU对操作数的存放方式是从低字节到高字节的

0x1234的存放方式入下:

0X4000 0x34

0X4001 0x12

4 Big-endian模式的CPU对操作数的存放方式是从高字节到低字节的

0x1234的存放方式入下:

0x4000 0x12

0x4001 0x34

5 联合体union的存放顺序是所有成员都从低地址开始存放。

6 一个变量的地址是由它所占内存空间中的最低位地址表示的。

0X4000 0x34

0X4001 0x12

0x1234 的地址位0x4000

7 堆栈的分配方式是从高内存地址向低内存地址分配的。

int ivar=0;

int iarray[2]={11, 22};

注意iarray[2]越界使用,比如对其赋值

iarray[2]=0;

那么则同时对ivar赋值为0,可能产生死循环,因为它们的地址相同,即&ivar等于&iarray[2]。

第二部分 C/C++内存区划分

一 在C中分为这几个存储区

1.栈 由编译器自动分配释放;

2.堆 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收;

3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束释放;

4.另外还有一个专门放常量的地方。 程序结束释放。

在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的”adgfdf”这样的字符串存放在常量区。比如:

int  a = 0; //全局初始化区  
char *p1; //全局未初始化区  
void main()  
{       
int b;                   //栈       
char s[] = "abc"; //栈       
char *p2;         //栈       
char *p3 = "123456";       //123456{post.content}在常量区,p3在栈上       
static int c = 0;          //全局(静态)初始化区       
p1 = (char *)malloc(10);   //分配得来得10字节的区域在堆区       
p2 = (char *)malloc(20);   //分配得来得20字节的区域在堆区       
strcpy(p1, "123456");      
//123456{post.content}放在常量区,编译器可能会将它与p3所指向的"123456"优化成一块  
}  

二.在C++中,内存分成5个区

他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区

1.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。

2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

3.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。

4.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

5.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。

在bbs上,堆与栈的区分问题,似乎是一个永恒的话题。   

首先,我们举一个例子:

void f()
{
int* p=new int[5];
}
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?它分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。

在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:

00401028 push 14h
0040102A call operator new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax 这里写代码片
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。

好了,我们回到我们的主题:堆和栈究竟有什么区别?

主要的区别由以下几点:

1、管理方式不同;

2、空间大小不同;

3、能否产生碎片不同;

4、生长方向不同;

5、分配方式不同;

6、分配效率不同;

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:

打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。

注意:Reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在它弹出之前,在它上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。

生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,不需要我们手工实现。

分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高(我的注释:关于EBP寄存器请参考另一篇文章)。

堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法

(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间

(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,

然后进行返回。显然,堆的效率比栈要低得多。

从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。

虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。

无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生意想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:)

转自:https://www.2cto.com/kf/201802/718986.html

一、导语【坑】:

项目中遇到删除列表中某一个item的需求,当使用splice的时候,理解有问题。当使用下面语句:

let item = this.data.items.splice(0, 1)

时,实际上它它返回的item是是被删除的那一条,不是返回的删除后剩下的数组。NND!

.

QQ20221006-135627@2x.png

二、演示一下正确的用法:

js代码:

Page({
    data: {
        godness: [
            {name: "张三"}, 
            {name: "李四"}, 
            {name: "王五"}, 
            {name: "赵六"}
        ]
    },
    onLoad: function(options) {},
    deleteBtn: function(event) {
        let index = event.currentTarget.dataset.index
        this.data.godness.splice(index, 1)
        this.setData({
            godness: this.data.godness //这里很重要
        })
    }
})





PHP,JAVA,NET 开发比较

一、语言


PHP:PHP产生与1994年,其语法混合了C、Java、Perl 和他自创的一些编程语法;PHP是嵌入在HTML中执行的;它也是一种解释性语言。早期的PHP并非完全的面向对象编程语言,到了PHP4以后的版本才开始有了面向对象的概念。

JAVA:JAVA产生与1995年,JAVA语言和JAVA平台统称为JAVA;它语法与C语言和C++语言很接近,并且JAVA是面向对象编程语言,JAVA是编译性语言,可以先将JAVA源码编译成.class文件后,在JAVA虚拟机上解释执行。

.NET:在.NET中,多种编程语言支持开发如:VB、C#、F#等等,通常我们都在使用C#编程,C#是为.NET平台专们打造的一种编程语言,产生与2000年。其语言语法和JAVA、C、C++相近,同样也是一种面向对象编程语言。C#同样需要编译为.dll文件,然后由.net框架中CLR编译执行。

语言区分:PHP、JAVA、C#这几天语言最大的区别就是执行方式的不同。其中还有一些语言本身的区别,比如是否为强类型、是否能动态编译、是否为多线程、是否为分布式、是否可移值等等。至于很多人说的性能上的问题,我认为语言本身上的性能问题差异并不大,关建在于写程序的人如何编写的代码。另外,在关于与语言结和的数据库方面也有一定的区别,PHP通常使用MySQL数据库,JAVA通常使用MySQL或Oracle,而C#因为是微软的产物,通常使用与微软相关的数据库Sql Server或Access等,有时候也会用Sqllite数据库。

二、平台:

PHP:一般人在称呼PHP的时候,本身并没有平台和语言的区别。我们用PHP往往只做WEB应用开发,至于桌面应用程序的开发,近年好像PHP出了这种开发平台,但现实应用中几乎看不到。但是不得不说,PHP在WEB的表现层应用中,有很好的表现,不论从处理界面布局,或是性能上都有着不错的优势。

JAVA:我们在称呼JAVA的时候,往往说的并不一定是语言本身,而是指JAVA平台。在JAVA平台中,可以使用JAVA语言去开发各种不同的应用开发,比如说:Java SE、Java EE和Java ME,分别用于开发JAVA桌面应用、WEB应用、移动应用等等。

.NET:在.NET这个体系中,语言和平台是有明显区别的,而且一个平台上可以应用多种语言开发,这样就满足了掌握不同语言的程序员可以开发同一个应用程序。在.NET平台中,也像JAVA一样,可以开发不同的应用,比如:WinForm(桌面应用)、控制台应用、ASP.NET(WEB应用)、WPF(新的桌面应用)、WCF(网络通信基础应用)、WEB服务(面向服务编程应用)、ASP.NET MVC3.0(新的WEB应用)、XNA(桌面及手机游戏应用)等等。

平台区分:三种技术平台都可以做我们常用的WEB应用。对于桌面应用来说,PHP并不太适用,JAVA则没有较好的桌面应用的开发工具,这方面.NET平台有较好的优势,不论是Winform还是WPF,都非常适合做桌面应用程序。至于实现一些底层的复杂业务,PHP则不如JAVA和.NET,但是在做前端表现层的时候有着较好的优势。所以很多复杂的大型综合应用,可能会有.NET或者JAVA做数据访问层及业务逻辑层,PHP则用来做表现层。据所说淘宝就是基于这种方式开发的。同时,JAVA与.NET(mono)都是可以跨平台的,.NET还能跨语言。

二。学.Net还是学Java

因为.Net和Java是国内市场占有率最高的两门技术,对于准备学习编程语言的初学者来说,.Net和Java是初学者首先考虑的两门技术,因此很多人一遍遍的问“学.Net还是学Java”,社区中也每天都有“.Net控”在唱衰Java,也有“Java控”在唱衰.Net,一时间硝烟四起,让初学者更加迷惑。

     从北京、广州、上海等地区2010年的就业统计数据(由于没有找到更权威的数据,这些数据是我对主流招聘网站和技术网站的相关数据进行的并不是太严谨的分析)来看,.Net和Java的职位数量比例为2:3,从就业网站和主要技术社区数据来看,2010年.Net和Java的学习人员数量比例为1:3。从数据上看,.Net的职位绝对数量比Java低一些,不过Java学习人员数量比.Net学习人员高出3倍,因此.Net职位的竞争激烈程度低于Java。

 

    由于.Net秉承了微软技术的入门简单的特点,经过短时间的学习就可以掌握拖拉控件的快速开发方式,很多人被.Net的快速开发方式所满足,认为自己“学成了”,不再深入研究,因此人才市场上充斥着很多只会拖控件、而不懂.Net更深入一步技术的.Net开发人员,比如很多ASP.Net的书上都是讲ASP.Net服务端控件,很多所谓“精通ASP.Net”的人连什么是Http、HTML、JavaScript、Dom等基本概念都稀里糊涂,实际公司项目中很多功能点的实现不是简单的拖一个ASP.Net服务端控件就能搞定的,因此看似学习.Net的人非常多,但是真正满足企业要求的人则比较少;而Java则入门门槛比较高,如果想要配置一个Hello World级别的学习环境就会涉及到很多技术,开发环境也要学习者自行配置,对于初学者来说可能花费一周时间都无法配置一个最简单的环境出来,Java的开发环境也不像.Net开发环境那么可用性强,Java和.Net的区别就像Windows和Linux的区别,正因为Java学习门槛非常高,很多学习者被淘汰了下来,这样能够撑过一个个难关学习下来的开发人员都是水平比较高的人员。因此.Net初级开发人员的工资平均是比Java初级开发人员的工资平均略低的。但是由于.Net中高级人才非常缺乏,因此掌握.Net深入技术的开发人员在企业内部是非常吃香的,招聘人员经常发出这样的感叹“招合适的Java工程师能招来一堆,招合适的.Net工程师一个月都招不来几个”。

 

    .Net入门快,在.Net中微软为开发人员提供了一套最佳的技术架构搭配、集成的开发环境,用微软的技术架构开发出的系统就可以保证最好的效果,而不用像Java开发人员那样去学很多开源框架再去学习搭建技术架构、开发环境,因此.Net学习周期比Java短,有了语言基础后再进行集训式的就业班学习,那么.Net学习者学习3个月可以进入就业,Java学习者需要5个月可以进入就业。

 

    微软的本地化推广工作做得非常好,因此学习.Net有大量的中文资料可以参考,因此除非研究很高深的领域,否则中文资料基本能满足开发者的需求;而Java由于走的是高端路线,因此除了初学者资料外,大部分Java资料都是英文的,学习Java需要参考很多英文资料。因此如果英文非常好的学员学习Java就会很轻松,而英文不是很好的学员学习.Net会更好。

 

    综上,Java入门门槛比较高,需要有足够的毅力和百折不挠的精神,只要你能坚持下来你就可以将很多人在入门门槛上就将很多竞争者甩在身后。.Net入门门槛比较低,装上VisualStudio就可以马上进行开发,不需要进行太多的配置、不需要学太多基础知识,这样可以很轻松的掌握入门.Net学习,是有很成就感的事情,能让你有兴趣进一步学习,但是你不能止步于此,因此你会发现身边也有无数的人也是“轻松入门”,你就需要继续深入学习,深入学习同样需要毅力和探索的精神,你要在这个阶段上把绝大部分竞争者甩在身后,小吹一把:我教的有个学生面试回来说“在咱班里比我感觉我掌握的不是太好,但是和一起参加面试的北大某鸟的学生比我简直就是高手”,呵呵。在我讲“.Net入门简单”的时候,有学生问“.Net把问题都简化了岂不是.Net程序员都不值钱了?”,我的回答是“微软简化的是重复性的东西和低级的东西,这样我们就能从这些低级的工作中脱身出来研究更深入的东西,因此.Net把问题简化了只是使得那些只沉迷于简单的东西的人不值钱了,会使得研究深入的人更值钱”,这就是“.Net入门容易,深入同样难”这句话的意思。有人会问“哪些知识属于深入的知识呢?”,比如你不仅要会用ADO.Net,还要研究ADO.Net架构中的设计模式,再比如你不仅要会拖拉ASP.Net控件,更要明白ASP.Net控件内部发生了什么。,如果你想从学习一开始就尽快脱离控件型开发人员的行列,你可以每天登陆博客园,csdn等高端.Net社区,你会发现你进步是非常快的。

 

    可能对.Net的描述中有或多或少的偏向,但是抛去个人因素考虑,我没有暗示Java好还是.Net好,请根据自己的情况进行选择。而且.Net和Java并不像360和QQ那样必须二者选其一,并不像很多初学者认为的那样“学一门语言就靠这门语言吃一辈子”,工作中很可能这个项目用Java,那个项目用.Net,因此你可以喜欢某个语言,但是不要抱着一门语言不放,更不用担心“Sun被Oracle收购了,Java是不是完了?”、“我学.Net,如果微软没落了我是不是就失业了”之类的问题,不同语言只是不同的工具,换了一个新的工具可以很快的熟悉新的工具,大部分内容都是相通的,比如java中的web开发很熟悉了,转而用ASP.Net也会发现大部分东西都是和JavaWeb一样的,很快就能上手ASP.Net,难道你现在用的是诺基亚手机,你会害怕诺基亚倒台你就不会用手机了吗?“Java完了、微软死了”这类问题不是开发人员去关心的事情,而是华尔街那些金融大鳄去考虑的问题,咱们只管用技术去赚钱养家就是了。

 

Java、.Net、PHP 市场应用

我们把Java .Net PHP应用方面占有率做个比较,简单的把目前主流应用分成两个大类,一个是企业应用,一个是Web网站应用,下面这个表格是我归纳的,不一定准确,但是能说明一个大概。

应用 / 语言 Java .Net PHP
大型企业应用
中型企业应用
小型企业应用
大型Web应用
中型Web应用
小型Web应用
从表中可以看到,Java和PHP都有各自擅长的领域,但是.Net却没有突出的地方,从占有率来看情况十分尴尬。
我们再来看看技术方面,首先声明,我对其中每种语言技术都不是很熟悉,只能大概分析一下...
先说说Java,在企业级方面,可以说是绝对的老大,许多企业级技术,开发思想都是由Java发展出来的。缺点是Java开发部署比较麻烦 ,不太适合超小型的项目。
再说.Net,在1.x时代,.Net可以说基本上没有多少企业级开发的特性,到了3.0,微软各种框架技术虽然弥补了这些不足,但是相对于Java世界,还是有一定距离。 在Web网站方面,.Net服务器控件的优势,变成了弱势,由于服务器空间产生垃圾代码,并且不方便美工调整,导致在前台界面要求较高的门户站点难以使用(虽然有第三方MVC框架,但是没有IDE支持,体现不出.Net的优势)
再说说PHP,他的定位非常明显,就是Web开发,所以有很多适合Web开发的特性,比如部署十分简单,几个文件随便找个虚拟主机扔上去就能运行。在国内因为Discuz , DedeCMS等著名产品的鼎立推广,PHP在中小型网站开发中有很大的优势.,最近大量的开源框架出现,给PHP企业开发注入了一些生命力,可以说潜力十足。
综合以上我们可以看到,.Net定位不太明确,微软这个想吃那个也想吃,最后没一个能吃饱吃好..
 
 
 
四。创业项目,你选择什么样的开发语言
1、需要尽量节省成本;2、对效率需求很大;3、有扩展性需求;4、需要考虑可移植性;
只选择主流语言:.Net、Java、PHP这类的语言。
.Net 属于微软的“个性”产品,可移植性不够,否掉。
Java语言,太“高端”,开发人员成本相对较高,而开发效率稍差一些。
PHP语言,出现时间比较长,语言相对比较成熟。开发人员比JAVA成本略低一些,开发效率比JAVA快。
PHP与平台无关可移植性比较好,代码几乎可以不用修改的在WINDOWS、LINUX上通用。
PHP的性能比JAVA略差,但是从这个项目对性能的需求来看,在可预期的时间内,还足够应付。

总结:请注意,不论任何编程语言或技术平台,并没有好与不好之分,只有适合与否。在开发不同的项目时需要使用不同的技术。当然做为程序员初学者来说,需要从一种比较容易上手的编程语言及平台学起,培养自己的学习能力、兴趣;基础打扎实,才能在以后日新月异的技术更新中不断成长。

最后代表个人一点小观点:现在开始学it的话,我建议学php(web)或者java(手机)

当然.net开发者就要看微软了,我希望是王者归来雄霸天下,跟着微软走永远有混头!

.net开发的优势在于:快速开发(服务器控件做后台非常好),后期维护成本低,当然在中国它还有一个优势就是开发成本低,你懂得!

.net web开发的模式:webform (中小项目),aspnet mvc(大中项目)

转自:https://blog.csdn.net/liuhhaiffeng/article/details/75453699

全角:是一种电脑字符,是指一个全角字符占用两个标准字符(或两个半角字符)的位置。全角占两个字节。 半角:是指一个字符占用一个标准的字符位置。半角占一个字节。 不管是半角还是全角,汉字都要占两个字节。
&#12288;  == 一个中文宽度

&#32; == 普通的英文半角空格

&#160; == &nbsp; == &#xA0; == no-break space (普通的英文半角空格但不换行)

&#8194; == &ensp; == en空格 (半个中文宽度)

&#8195; == &emsp; == em空格 (一个中文宽度)

&#8197; == 四分之一em空格 (四分之一中文宽度)

相比平时的空格(&#32;),&nbsp拥有不间断(non-breaking)特性。即连续的&nbsp会在同一行内显示。
即使有100个连续的nbsp,浏览器也不会把它们拆成两行。

链接:https://juejin.cn/post/6844904016971825165

语言主要用途
C操作系统、嵌入式、驱动开发
C++图形图像、科研、通信、桌面软件、游戏、游戏服务器
C#window桌面应用、.Net web、服务器
JavaJava SE:跨平台的桌面应用、Android
Java EE:企业级应用、web开发、服务器后端
Java ME:手机应用、流行非智能手机时代
Java Android:用于开发安卓手机应用
Go高性能服务器应用、比较年轻
Erlang高并发服务器应用,多用于游戏服务器
PythonWeb、科学计算、运维
PHPWeb应用、后端服务器开发
RubyWeb
Perl运维、文本处理
Lisp科研、一种逻辑语言,用于人工智能
Node一个 Javascript运行环境
Haskell一种标准化的通用函数式编程语言,用于数学逻辑方面
Scala一种类似Java的编程语言,集成面向对象和函数式编程的各种特性
Javascript前端,在node中可以做后端
TypeScript前端,是javascript的超级,增加了强类型等特性
Html/CSS标记语言,主要是给web前端工程师构建页面

还有一些没考虑到的,望见谅!