ysbbs

Let's start BB !


  • 首页

  • 归档

  • 关于

  • 标签

字节序

发表于 2019-05-22 | | 阅读次数

对于字符串来说,是没有字节序的差别的,就像我们写字,内存就像是纸,字符串就从左向右依次写:

内存地址:00000000 00000001 00000002 00000003 …

内存数据: ‘A’ ‘B’ ‘C’ ‘D’

而任何cpu读取的时候,也都是从左向右依次读取。

对于多字节数据(比如short、int、long…),不同字节序是有差别的。

所有x86架构cpu(包括x64)都是用的小端字节序,网络字节序是大端序:

int a = 0x01020304;

内存地址:00000000 00000001 00000002 00000003 …

大端序a : 0x01 0x02 0x03 0x04 即cpu读出的数据从高向低位写入变量

小端序a : 0x04 0x03 0x02 0x01 即cpu读出的数据从低向高位写入变量

如果我们写的程序不进行字节序转换会怎么样呢:

int a = 0x01020304;

在我们x86架构机器的内存里,它是这样写的0x04030201(注意,这是它在内存里的真实写法,当我们的程序以int型读取的时候才会转化成0x01020304),此时进行网络发送,send程序会以字节的方式(可以把它想象成字符串),一字节一字节的发送,到了网络上,它的顺序仍然是0x04030201(此时它的顺序已经错了)。当数据到达对端机器的时候,对端机器也是一字节一字节的收入内存,它的顺序仍然是0x04030201。如果对端仍是x86架构,那么数据读出来的时候它又被转化成了0x01020304,这看起来像是对的。但是如果对端是大端序的架构,那么它的int型数据就变成了0x04030201。

字节序转换:

linux里提供了现成的函数:htonl, ntohl … 这是一系列函数,却只提供了2字节和4字节的转换。

阅读全文 »

sed&awk

发表于 2019-05-22 | | 阅读次数

sed

  • sed
    • stream editer
    • 流编辑器
  • 主要是以行对数据进行处理
  • 基本使用格式:
    • sed 参数 '脚本语句' 待操作文件
    • sed 参数 -f '脚本文件' 待操作的文件
    • 双引号也可以
  • 替换
    • sed 's/echo/printf/g' ./test.txt
    • 一行有多个都进行替换加g
    • sed 默认操作只会打印到屏幕上,-i 参数会直接修改源文件(慎用)
  • 脚本语句格式
    • /pattern/action

awk

  • awk是创始的三个人名字首字母缩写
    • 就读作A W K
  • 默认是以 空格 和 制表符 来区分对象的列
    • 如果想让其区分以冒号或其他分割的列需要加参数,以冒号举例:
      • awk -F: '{print $1}' /etc/passwd
  • $0 表示所有
  • $1 表示第一列
  • $2表示第二列,以此类推
  • 使用格式
    • awk option '{script}' file1 file2
  • 按条件
    • awk ' $3==0 && $6=="LISTEN" ' netstat.txt
  • awk实用教程:https://coolshell.cn/articles/9070.html

常用的g++编译FLAG总结

发表于 2019-04-24 | | 阅读次数
  • -m32

    • 指定编译为32位应用程序
  • -m64

    • m64指定编译为64位应用程序
  • -ggdb

    • 产生GDB可调试的信息
  • -fPIC

    • 生成位置无关的代码
    • 这份代码如果未来要用在动态库上,就需要生成与位置无关的代码
  • -D

    • 1
      2
      3
      4
      -Dmacro
      相当于C语言中的#define macro。
      -Dmacro=defn
      相当于C语言中的#define macro=defn。
  • -Wall

    • 1
      一般使用该选项,允许发出GCC能够提供的所有有用的警告。也可以用-W{warning}来标记指定的警告。
  • -pipe

    • 使用管道代替编译中临时文档,增加编译效率,在使用非gnu汇编工具的时候,可能有些问题
    • https://blog.51cto.com/elephantliu/684257
  • -O2

    • 1
      2
      3
      4
      5
      -O0
      -O1
      -O2
      -O3
      编译器优化选项分为4个级别,-O0表示没有优化,-O1为缺省值,建议使用-O2,-O3优化级别最高。
  • -funroll-loops

    • gcc来检查代码,进行循环展开,减少循环次数提高性能
  • -fstack-protector-all

    • 启用堆栈保护,为所有函数插入保护代码。
  • -rdynamic

    • 相比-g选项, -rdynamic 却是一个 连接选项 ,它将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号)都添加到动态符号表(即.dynsym表)里,以便那些通过 dlopen() 或 backtrace() (这一系列函数使用.dynsym表内符号)这样的函数使用。
  • -shared

    • 1
      此选项将尽量使用动态库,为默认选项。优点:生成文件比较小。缺点:运行时需要系统提供动态库。
  • 错误不提示(忽略警告)

    • -Wno-write-strings
      • 应为你写的char* 是具有c风格的字符串,所以g++不识别
阅读全文 »

虚拟地址空间

发表于 2019-04-23 | | 阅读次数

利用U盘安装Linux镜像

发表于 2019-04-20 | | 阅读次数
  • 使用老毛桃制作ubuntu镜像U盘
    • ISO模式
    • 普通模式
    • 刻录映像时写入方式选择”RAW”
  • 还是ubuntu对用户比较友好,无论是安装速度还是兼容程度都满分
    • 大大降低了安装心智负担
    • 省时间

epoll的边缘触发和水平触发模式解析

发表于 2019-04-13 | | 阅读次数

在学习epoll的时候,一般都会学习到epoll的水平触发和边缘触发模式。

很多地方都有提到一个结论:边缘触发(ET)模式+将监听的socket的fd设置为non_blocking,可以提高效率,但对于这个增加了多少效率,并没有相关的benchmark可以看到,故整理转载了两种模式对于性能的影响分析。

以下:

转自:dong

epoll的帮助中指出,使用ET模式,可以便捷的处理EPOLLOUT事件,省去打开与关闭EPOLLOUT的epoll_ctl(EPOLL_CTL_MOD)调用。从而有可能让你的性能得到一定的提升。

例如你需要写出1M的数据,写出到socket 256k时,返回了EAGAIN,ET模式下,当再次返回EPOLLOUT时,继续写出待写出的数据,当没有数据需要写出时,不处理直接略过即可。而LT模式则需要先打开EPOLLOUT,当没有数据需要写出时,再关闭EPOLLOUT(否则会一直会返回EPOLLOUT事件)
总体来说,ET处理EPOLLOUT方便高效些,LT不容易遗漏事件、不易产生bug

ET理论上可以比LT少带来一些系统调用,所以更省一些。具体的性能提高有多少,要看应用场景。不过绝大部分场景下,LT是足够的。

但是使用水平触发,可能会导致:

使用了epoll,且你的fd是阻塞的。
如果epoll通知你fd可以写数据了。然后你啦啦啦的打算写100B数据,但是内核buf只有50B的可用空间,这时候,你的进程就被阻塞了。
所以说,用了epoll不能保证你的进程在读写的时候不会阻塞,在这种极端情况下,用边缘触发会带来更好的性能。

但是对于现代CPU来说, IO总是能先满的, 相对于龟速的网络, 多几个system call无所谓吧

比如,以单线程速度见长的Redis使用的是水平触发。

阅读全文 »

高并发服务器学习笔记

发表于 2019-04-11 | | 阅读次数

总结学习了并发服务器的几种模式,总结为笔记,相应代码在github上,以demo的形式实现了以下服务器模型。

项目地址:https://github.com/ysbbswork/SimpleMultSocket

  • 多进程并发服务器
  • 多线程并发服务器
  • IO复用
    • select
    • poll
    • epoll
  • 注意事项
阅读全文 »

Linux下的printf输出不显示问题

发表于 2019-04-09 | | 阅读次数

今天写了个服务器的demo,但是中间的printf都没有显示出来,测试了一波,都没有找到明显的原因。

查了一下,原来是输出缓冲的问题,所以单独的程序,执行结束即刷新缓冲区,带死循环的程序,陷入循环中,迟迟不刷新缓冲区,所以printf的内容不会显示到控制台。

阅读全文 »

NGINX模型和实现高并发的架构思想

发表于 2019-03-31 | | 阅读次数

转载自作者:黄泽武

链接:https://www.jianshu.com/p/ae35deebd9d0

来源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧。

NGINX进程模型

nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。我们也可以手动地关掉后台模式,让nginx在前台运行,并且通过配置让nginx取消master进程,从而可以使nginx以单进程方式运行。很显然,生产环境下我们肯定不会这么做,所以关闭后台模式,一般是用来调试用的。所以,我们可以看到,nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式。

nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。nginx的进程模型,可以由下图来表示:

img

nginx启动后,如果我们要操作nginx,要怎么做呢?从上文中我们可以看到,master来管理worker进程,所以我们只需要与master进程通信就行了。master进程会接收来自外界发来的信号,再根据信号做不同的事情。所以我们要控制nginx,只需要通过kill向master进程发送信号就行了。比如kill -HUP pid,则是告诉nginx,从容地重启nginx,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。master进程在接收到HUP信号后是怎么做的呢?首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以光荣退休了。新的worker在启动后,就开始接收新的请求,而老的worker在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。当然,直接给master进程发送信号,这是比较老的操作方式,nginx在0.8版本之后,引入了一系列命令行参数,来方便我们管理。比如,./nginx -s reload,就是来重启nginx,./nginx -s stop,就是来停止nginx的运行。如何做到的呢?我们还是拿reload来说,我们看到,执行命令时,我们是启动一个新的nginx进程,而新的nginx进程在解析到reload参数后,就知道我们的目的是控制nginx来重新加载配置文件了,它会向master进程发送信号,然后接下来的动作,就和我们直接向master进程发送信号一样了。

现在,我们知道了当我们在操作nginx的时候,nginx内部做了些什么事情,那么,worker进程又是如何处理请求的呢?我们前面有提到,worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

那么,nginx采用这种进程模型有什么好处呢?当然,好处肯定会很多了。首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。当然,好处还有很多,大家可以慢慢体会。众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。

NGINX事件模型

阅读全文 »

异步、并发、协程原理

发表于 2019-03-31 | | 阅读次数

原文:http://wiki.phpboy.net/doku.php?id=2017-07:55-异步并发协程原理.md

Linux 操作系统在设计上将虚拟空间划分为用户空间和内核空间,两者做了隔离是相互独立的,用户空间给应用程序使用,内核空间给内核使用。

阅读全文 »
1234…11
Yang Shuai

Yang Shuai

105 日志
89 标签
© 2021 Yang Shuai
由 Hexo 强力驱动
主题 - NexT.Mist