2018年12月

Python下自带的Socket的模块是阻塞型的,每次只能处理一个连接,给应用造成了极大的不便,幸好有Gevent这个基于 协程的网络库,来使默认的Socket支持并发。

代码如下:

#coding=utf-8
from gevent import monkey; monkey.patch_all() //猴子魔法[1]
import socket
import gevent

def server_req(conn):
        while True:
                data = conn.recv(1024) #等待传入数据
                if not data:
                        conn.close() #关闭连接
                        break
                print('recv:%s'%data)
                conn.send(data) #发送数据

def server_mian(s_addr,s_port):
        s = socket.socket()
        s.bind((s_addr,s_port)) #绑定端口
        s.listen(500) #最大连接数
        while True:
                cli,addr = s.accept() #等待一个客户
                gevent.spawn(server_req,cli) #创建一个协程,将客户传入server_req函数

if __name__ == '__main__':
    server_mian('0.0.0.0',3000)

[1]猴子魔法(Monkey Patch):https://www.gevent.org/api/gevent.monkey.html

条件语句

if 语句

用法

if 条件 {
     //当条件为真时执行
}

if 条件 {
     //当条件为真时执行
} else {
     //当条件为假时执行
}

if 条件 {
     //当条件为真时执行
} else if 条件2 {
     //当条件2为真时执行
} else {
     //全部不满足时执行
}

特点

  1. if后的条件不需要用小括号括起来
  2. {必须放在行末,与if或if else放在一行
  3. if后可带一个简单的初始化语句,并以分号分割,所声明变量的作用域为整个if语句块(包括后面的分支)
  4. Go语言没有条件运算符
  5. 遇到return后直接返回,遇到break则跳过break下方的if语句块

编程哲学

  1. 尽量减少条件语句的复杂度,如果条件语句太多,太复杂,则建议放到函数里封装起来
  2. 尽量减少if语句的嵌套层次,通过重构代码来使代码变得扁平,便于阅读

switch 语句

用法

switch {
     case 条件:
         //执行语句
     case 条件:
         //执行语句
     default:
         //所有条件不满足时执行
}

特点

  1. 同if一样,switch后可带一个简单的初始化语句
  2. switch后的表达式也是可选的,如果没有表达式,则case的子句是一个布尔表达式,而不是一个值,就像多重if...else...语句
  3. switch可以任意支持相等比较运算的类型变量
  4. 通过fallthough来强制执行下一个case子句(不判断下一case分支的条件)
  5. switch支持default语句,当所有条件不支持时执行default中的语句,default的位置不影响switch的判断逻辑
  6. switch和.(type)结合可以进行类型的查询(这个以后会学到)

循环语句

for 语句

Go语言只有一个循环语句——for

用法

//1.类似C中的for语句
for init;condition;post { }
//2.类似C中的while语句
for condition { }
//3.死循环
for { }
//for也可以对数组,切片,字符串,map和通道的访问

标签与跳转

Go使用标签来标识一个语句的位置,用于goto,break,continue语句的跳转。

标签

Lable: Statement

goto

goto用来跳转到函数内指定的标签

goto Lable

特点

  1. 只能在函数内跳转
  2. goto不能跳过内部变量声明语句
  3. goto只能跳转到同级作用域或上层作用域内,不能跳转到内部作用域

break

break用于函数内跳出for,switch,select语句的执行,有两种使用格式:

  1. 单独使用,用于跳出break当前所在的for,switch,select语句的执行
  2. 和标签一起使用,用于跳出标签所标识的for,switch,select语句的执行,可用于跳出多重循环,但标签与break必须在同一个函数内

continue

continue用于跳出for循环的本次迭代,跳到for循环下一次迭代的post语句执行,也有两种使用格式:

  1. 单独使用,用于跳出continue当前所在的for循环的本次迭代
  2. 和标签一起使用,用于跳出标签所标识的for语句的本次迭代,但标签与continue必须在同一个函数内

Nginx做文件服务器时,需要显示目录结构,由于安全性的原因,Nginx默认是不开启的,所以下面来人工打开它。

配置

打开你的站点配置文件加入(一般在/etc/nginx/sites-enabled中):

autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
\autoindex_exact_sizeautoindex_localtime
on显示出文件的确切大小,单位为bytes显示的文件时间为文件的服务器时间
off显示出文件的大概大小,单位为kB或MB或GB显示的文件时间为GMT时间

乱码解决

配置完成后我们打开站点,发现中文显示乱码,在配置文件中加入一行即可:

charset utf-8,gbk;

指定目录显示

很多时候我们只需要某个目录暴露出来,这时我们需要定义一个段,下面以站点目录的video为例:

location /video {
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
        charset utf-8,gbk;
}

切片

在Go中由于数组的定长性和值拷贝的特性限制了数组的使用场景,使用Go提供了另外一种数据类型slice(切片),这是一种变长数组。

声明

//由make创建
SliceName := make([]Type,Len,Cap)  //可不填写Cap,但会使Cap=Len
//由数组创建
ArrayName := [...]Type{value1,value2,value3}
SliceName := Array[b,e]  //b:开始索引 e:结束索引 都可不指定
//直接声明切片类型变量是没有意义的
var a []int  //打印结果:[]
//此时array=nil,len=0,cap=0

切片的操作

操作

//长度
len(Slice)
//底层数组容量
cap(Slice)
//添加元素
append(Slice,Value)
//复制切片
copy(Slice1,Slice2)

例子

package main
import "fmt"

func PrintSliceInfo(s1,s2 []int){
        fmt.Println("--------------")
        fmt.Println("s1:",s1)
        fmt.Println("s2:",s2)
        fmt.Println("s1 cap:",cap(s1))
        fmt.Println("s2 cap:",cap(s2))
        fmt.Println("s1 len:",len(s1))
        fmt.Println("s2 len:",len(s2))
        fmt.Println("--------------")
}
func main(){
        a := [...]int{0,1,2,3,4,5}
        s1 := make([]int,3,6)
        s2 := a[3:]
        PrintSliceInfo(s1,s2)
        s1 = append(s1,23)
        s2 = append(s2,233)
        PrintSliceInfo(s1,s2)
        s3 := make([]int,3,4)
        copy(s3,s2)
        fmt.Println("--------------")
        fmt.Println("s3:",s3)
        fmt.Println("s3 len:",len(s3))
        fmt.Println("s3 cap:",cap(s3))
        fmt.Println("--------------")
}
//打印结果
--------------
s1: [0 0 0]
s2: [3 4 5]
s1 cap: 6
s2 cap: 3
s1 len: 3
s2 len: 3
--------------
--------------
s1: [0 0 0 23]
s2: [3 4 5 233]
s1 cap: 6
s2 cap: 8
s1 len: 4
s2 len: 4
--------------
--------------
s3: [3 4 5]
s3 len: 3
s3 cap: 4
--------------

字典

声明

//通过字面量创建
MapName := map[Type1]Type2{"key":value,"key2",value2}
//通过Make创建
MapName := make(map[Type1]Type2)

用法

//添加与更新,访问一个键
MapName[key] = value
value := MapName[key]
//删除
delete(MapName,key)
//长度
len(MapName)
//迭代
for key,value := range MapName{
    //code
    fmt.Println("key=",key,"value=",value)
}

注意

  1. Go内置的Map不是并发安全的,并发安全可以使用标准包sync中的map
  2. 不要直接修改map value中的某个元素的的值,如果需要修改,则必须整体重新赋值
  3. 可以使用range迭代,但不保证每次的迭代顺序相同

结构

Go中的struct(结构)与C类似。

声明

//通过字面量,这种方法用的较少
struct{
FeildName  FeildType
FeildName  FeildType
FeildName  FeildType
}
//通过自定义类型
type TypeName struct{
FeildName  FeildType
FeildName  FeildType
FeildName  FeildType
}

示例

type test struct{
Name String
Age int
}
//不推荐下面的方式来初始化
a := test{"test",23}
//建议使用下面的方法,避免新增字段导致报错,没有赋值的字段默认为零值
c := test{
Name:"test",
Age:23,
}

访问

Value := TypeName.FeildName

注意

  1. struct中的类型可以是任意类型
  2. struct的存储空间是连续的,其字段按照声明时的顺序存放(注意字段之间对齐!)

其他要说的

切片的原理

请务必看一下,了解切片的工作原理!
https://www.cnblogs.com/hutusheng/p/5492418.html