Haskell趣学指南
很久之前看到朋友们讨论: 函数式编程,柯里函数,类型类,函子,Monoid…一堆酷炫的东西,心神往之,早已埋下了好奇的种子,所以趁着国庆假期就买了本《Haskell趣学指南》,试图一窥函数式编程的面貌。写这篇博客一方面是让我自己对Haskell 更熟练,另一方面是希望能够分享我的学习经验,帮助初学者更快进入状况。 如果你也想简单的了解一下Haskell,这里还有该书的web版本《Haskell趣学指南》(我还是喜欢纸质书的写写画画~)。 从零开始通过apt-get install Haskell-platform命令即可在Ubuntu下安装Haskell的GHC版本编译器。GHC可以解释执行.hs结尾的Haskell Script,ghci命令进行交互试模式,输入:l myfunctions.hs即可执行对应的myfunctions.hs文件。 12GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for helpPrelude> haskell会按照运算中优先级执行计算,也支持使用括号改变计算的优...
APUE(七)网络IPC:套接字
OSI模型在这里不详细展开tcp/ip计算机网络相关知识,可能会专门写一篇这方面文章吧。 详细了解可看程皓的博客文章:TCP的那些事(上)与TCP的那些事(下)。 传输层:TCP/UDP原理简介用户数据报协议(UDP)UDP提供无连接的服务,是一个简单的传输协议,应用程序往一个UDP套接字写入一个消息,该消息随后被封装到一个UDP数据报,该UDP数据报进而又被封装到一个IP数据报,然后发往目的地。 UDP不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证 每个数据报只到达一次。 传输控制协议(TCP)TCP提供有连接服务,先建立连接,在交换数据,最终关闭连接。 TCP还提供可靠性(reliability)。当TCP向另一端发送数据时,它要求对端返回一个确认。如果没有收到确认,TCP就自动重传数据并等待更长时间。在数次重传失败后,TCP才放弃。 TCP含有用于动态估算客户和服务器之间的往返时间(round-trip time, RTT)的算法,以便它知道等待一个确认需要多少时间。 TCP通过给其中每个字节关联一个序列...
APUE(六)高级IO
IO模型 阻塞IO 非阻塞IO I/O复用 信号驱动IO(SIGIO) 异步IO(POSIX的aio_系列函数) 一个输入输出通常包含两个不同阶段: 等待数据准备好。 从内核向进程复制数据。 对于一个套接字上的输入输出操作: 第一步通常涉及等待数据从网络中到达。当所等待分组到达时,它被复制到内核中的某个缓冲区。 第二步就是把数据从内核缓冲区复制到应用进程缓冲区。 五种IO模型阻塞式IO模型 如图所示,进程调用recvfrom,其系统调用直到数据报到达且被复制到应用进程的缓冲区中或者发生错误时才返回。(从调用recvfrom开始到它返回的整段时间内是被阻塞的) 非阻塞式IO模型进程把一个套接字设置成非阻塞的是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是返回一个错误。 当一个进程像上图这样对一个非阻塞描述符循环调用时,称这种行为为:轮询(polling)。 I/O复用IO复用模型指,可以调用IO复用函数,进程阻塞在IO复用函数上,而不是阻塞在I/O系统调用上,当等待事件发生后,在调用对应...
APUE(五)线程
线程线程创建线程ID只有在它所属的进程上下文中才有意义。 123456#include<pthread.h>int pthread_equal(pthread_t tid1, pthread_t tid2);int pthread_self(void); //调用线程获取自身的线程IDint pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg); 新创建的线程ID会被设置为tidp指向的内存单元。attr参数用于定制各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。 每个线程都提供errno的副本。 1234567891011121314151617181920212223242526272829303132#include "apue.h"#include <pthread.h...
APUE(四)进程间通信(IPC)
进程间通信(InterProcess Communication, IPC) 匿名管道 有名管道 信号 消息队列 共享内存 信号量 套接字 管道匿名管道 历史上,管道是半双工的(即数据只能在一个方向上流动)。现在某些系统提供全双工管道,但是为了最佳可移植性,不应预先假定系统支持全双工管道。 匿名管道只能在具有公共祖先的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父进程和子进程之间使用了。 pipe函数创建管道,fd[0]为读而打开,fd[1]为写而打开。 12#include<unsitd.h>int pipe(int fd[2]); 通常,进程会先调用pipe,接着调用fork,从而创建从父进程到子进程的IPC通道。 fork之后做什么取决于我们想要的数据流的方向。对于从父进程到子进程的管道,父进程关闭管道的读端(fd[0]),子进程关闭写端(fd[1])。状态结构如下图所示。 当读(read)一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,表示文件结束。 如果写(write)一个读端已被关闭的管道,...
APUE(三)信号
信号都以SIG开头,信号名都被定义为正整数常量,不存在编号为0的信号,kill函数对信号编号0有特殊的应用,这种信号称为空信号。 很多条件可以产生信号: 当用户按某些终端键,引发终端产生的信号 硬件产生的信号:除数为0,无效内存引用 进程调用kill函数可将任意信号发送给另一个进程或进程组 用户可调用kill命令将信号发送给其他进程 当检测到某种软件条件已经发生,并将其通知有关的进程时也产生信号 在某个信号出现时,可以告诉内核按照下列三种方式之一处理 忽略,大多数信号可以使用这种方式进行处理,但时SIGKILL和SIGSTOP不能被忽略,因为他们向内核和超级用户提供了使进程终止的可靠方法。 捕捉,做到这一点的前提是要通知内核在某种信号发生时,调用一个用户函数,在用户函数中对这种事件进行处理 执行系统默认动作,大多数信号的系统默认动作是终止进程 在系统默认动作中,有的默认动作会在进程当前工作目录中生成core文件(中间复制了该进程的内存映像)下面几种条件不产生core文件: 进程是设置用户id的,而且当前用户并非程序文件的所有者 进程是设置组id的 用户没有写当前工作目录...
APUE(二) 进程
进程1int main(int argc, char *argv[]); 当内核执行c程序时(使用一个exec函数),在调用main前先调用一个特殊的启动例程。可执行文件将此启动例程指定为程序的起始地址。启动例程从内核取得命令行参数和环境变量的值。然后为调用main函数做好准备。 进程终止有八种方式,其中五种为正常终止: 正常终止 从main返回 调用exit 调用_exit或_Exit 最后一个线程从其启动例程返回 最后一个线程调用pthread_exit 异常终止: 调用abort 接到一个信号 最后一个线程对取消请求作出响应 12345#include<stdlib.h>void exit(int status);void _Exit(int status);#include<unsitd.h>void _exit(int status); 这三个函数用于正常终止一个程序:_exit和_Exit立即进入内核,exit先执行一些清理处理,然后返回内核。 exit函数总是执行一个标准I/O库的清理关闭操作(对所有打开流调用fclose函...
APUE(一) IO与文件操作
文件IO不带缓冲的io(unix系统在内核中设有缓冲区,这个不带缓冲意思是用户不自己缓冲),每个read和write都调用内核中的一个系统调用。 文件描述符对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。 Unix系统shell把文件描述符0与进程的标准输入关联,文件描述符1与标准输出关联,文件描述符2与标准错误关联。在符合POSIX.1的程序中,幻数0,1,2已被标准化为符号常量STDIN_FILENO, STDOUT_FILENO和STDERR_FILENO。这些常量定义在<unistd.h>文件中。文件描述符的变化范围是0~OPEN_MAX-1。 文件IO函数1234567#include<fcntl.h>//open函数成功返回文件描述符,出错返回-1int open(const char *path, int oflag,... /* mode_t mode */);int openat(int fd, const char *path, int of...
Use GPG to whisper
GnuPG(GNU Privacy Guard,GPG)是一种加密软件,它是PGP加密软件的开源替代物。GnuPG依照由IETF制定的OpenPGP技术标准设计。GnuPG是用于加密、数字签章及产生非对称匙对的软件。GPG兼容PGP(Pretty Good Privacy)的功能。 安装一般like uinx下会都包含GPG软件包。gpg --version查看是否安装与版本。 同样gpg --help获取命令帮助。 生成密钥1234567# 生成新的密钥对gpg --gen-keygpg --generate-key## 更多密钥配置选项生成新的密钥对gpg --full-generate-keygpg --full-gen-key 生成密钥时,会要求做一些随机的举动(敲打键盘、移动鼠标、读写硬盘之类),以生成一个随机数。生成过程需要一段时间。 显示密钥生成的密钥一般存在与~/.gnupg目录下。可以通过如下命令查看: 123456gpg -kgpg --list-keys# 显示某个用户的密钥信息gpg --list-key [用户id]# 显示私钥信息gpg --l...
程序员的自我修养--链接,装载与库
编译器把c语言编程成可执行的机器码之间发生了什么? 编译出来的可执行文件里是什么? 程序是怎么运行起来的? 真正了不起的程序员对自己的程序的每一个字节都了如指掌。 当我们将一段代码编译成可执行文件时,可分解为四个步骤:预处理(Prepressing), 编译(Compilation), 汇编(Assembly), 链接(Linking)。 预处理阶段123gcc -E hello.c -o hello.icpp hello.c > hello.i 预处理过程主要处理那些源代码文件中的以”#”开始的预编译指令。比如: #include, #define等,主要处理规则如下: 将所有的#define删除,并且展开所有的宏定义。 处理所有条件预编译指令,比如#if, #ifdef, #elif, #else, #endif。 处理#include预编译指令, 将被包含的文件插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。 删除所有的注释”//“和”/**/“。 添加行号和文件名标识,以便...
