TinyHttp前置知识
(一)CGI
CGI相关概念
CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。
组成CGI通信系统的是两部分:一部分是html页面,就是在用户端浏览器上显示的页面。另一部分则是运行在服务器上的cgi程序。
对于CGI程序来说,它继承了系统的环境变量。CGI环境变量在CGI程序启动时初始化,在结束时销毁。
get方法
当使用这种方法时,CGI程序从环境变量QUERY_STRING获取数据。
QUERY_STRING 被称为环境变量,就是这种环境变量把客户端的数据传给服务器。为了解释和执行程序,CGI必须要分析(处理)此字符串。当你想从服务器获得数据并且不改变服务 器上的数据时,你应该选用GET。
post方法
客户端来的用户数据将存放在CGI进程的标准输入中,同时将用户数据的长度赋予环境变量中的CONTENT_LENGTH。
(二)pipe管道
管道概念
一种基本的IPC(Inter-Process Communication 进程间通信)机制。作用于有亲缘关系的进程之间,完成数据传递。
1.实质是一个缓冲区。
2.两个文件描述符引用,一个表示读端,一个表示写端。数据从管道的写端流入管道,从读端流出。
图源:https://blog.csdn.net/qq_34144916/article/details/81184434
若要数据流从父进程流向子进程,则关闭父进程的读端(fd[0])与子进程的写端(fd[1]);反之,则可以使数据流从子进程流向父进程。
调用pipe系统函数即可创建一个管道。
补充:进程间通信方式
-
管道pipe(也有叫做匿名管道):是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
-
命名管道FIFO:也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
-
高级管道popen:将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
-
消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
-
共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
-
信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
-
套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
-
信号sinal: 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
pipe()函数
int pipe(int fd[2]);
函数说明:创建一个管道,以实现进程间的通信。
参数:数组包含pipe使用的两个文件的描述符。(一个大小为2的一个数组类型的指针)fd[0]:读管道,fd[1]:写管道。往 fd[1] 写入的数据可以从 fd[0] 读出。并且 fd[1] 一端只能进行写操作,fd[0] 一端只能进行读操作,不能反过来使用。要实现双向数据传输,可以使用两个管道。
返回值:成功时返回0,并将一对打开的文件描述符值填入fd参数指向的数组。失败时返回 -1并设置errno。
注意:必须在fork()中调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
(三)一些概念以及函数解释
stdin,stdout和stderr
这3个可以称为终端(Terminal)的标准输入(standard input),标准输出( standard out)和标准错误输出(standard error)。
输入重定向:关闭标准输入设备,打开(或复制)某普通文件,使其文件描述符为0。
输出重定向:关闭标准输出设备,打开(或复制)某普通文件,使其文件描述符为1。
错误输出重定向:关闭标准错误输入设备,打开(或复制)某普通文件,使其文件描述符为2。
getenv()函数
char *getenv(char *envvar);
函数说明:getenv()用来取得参数envvar环境变量的内容。
参数:envvar为环境变量的名称,如果该变量存在则会返回指向该内容的指针。环境变量的格式为envvar=value。getenv函数的返回值存储在一个全局二维数组里,当你再次使用getenv函数时不用担心会覆盖上次的调用结果。
返回值: 执行成功则返回指向该内容的指针,找不到符合的环境变量名称则返回NULL。如果变量存在但无关联值,它将运行成功并返回一个空字符串,即该字符的第一个字节是null。
atoi()函数
int atoi(const char *str)
函数说明:把字符串转换成整型数。
参数:str为要转换为整数的字符串。
返回值:该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。
dup()和dup2()函数
int dup(int oldfd);
函数说明:dup()用来复制参数oldfd 所指的文件描述符, 并将它返回. 此新的文件描述词和参数oldfd 指的是同一个文件, 共享所有的锁定、读写位置和各项权限或旗标。例如, 当利用lseek()对某个文件描述符作用时, 另一个文件描述符的读写位置也会随着改变. 不过, 文件描述符之间并不共享close-on-exec 旗标。
返回值:当复制成功时, 则返回最小并且尚未使用的文件描述符.。若有错误则返回-1, errno 会存放错误代码。
int dup2(int oldfd,int newfd);
dup2()用来复制参数oldfd 所指的文件描述符, 并将它拷贝至参数newfd 后一块返回。 若参数newfd为一已打开的文件描述符, 则newfd 所指的文件会先被关闭。dup2()所复制的文件描述符, 与原来的文件描述符共享各种文件状态, 详情可参考dup()。
返回值:当复制成功时, 则返回最小并且尚未使用的文件描述符。若有错误则返回-1, errno 会存放错误代码。
sprintf()函数
int sprintf(char *str, const char *format, ...);
函数说明:发送格式化输出到 str 所指向的字符串。
参数:str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写入到字符串 str 的文本。
返回值:如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。
wait()和waitpid()函数
pid_t wait (int * status);
函数说明:暂时停止目前进程的执行, 直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束, 则wait()会立即返回子进程结束状态值。
参数:输出型参数,获取子进程退出状态,不关心则可以设置为NULL。
返回值:成功返回被等待进程(子进程)pid,失败返回-1。
pid_t waitpid(pid_t pid, int * status, int options);
函数说明:waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能。wait()可以看作waitpid()的一个特例。
参数:
pid -- 欲等待的子进程识别码。pid<-1 等待进程组识别码为pid绝对值的任何子进程。pid=-1,等待任一个子进程,与wait()等效。id=0 等待进程组识别码与目前进程相同的任何子进程。pid>0,等待其进程ID与pid相等的子进程。
status -- 调用 waitpid()时子进程已经结束,则 waitpid()会立即
返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回,
而子进程的进程识别码也会一起返回。如果不在意结束状态值,则
参数 status 可以设成 NULL。
options -- 提供了一些额外的选项来控制waitpid。不想使用可以设为0。
WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。
WUNTRACED 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。WIFSTOPPED(status)宏确定返回值是否对应与一个暂停子进程。
返回值:成功则返回子进程pid, 失败则返回-1. 失败原因存于errno 中。
execl()函数
int execl(const char * path, const char * arg, ...);
函数说明及参数:execl()用来执行参数path 字符串所代表的文件路径, 接下来的参数代表执行该文件时传递过去的argv(0),argv[1], ..., 最后一个参数必须用空指针(NULL)作结束。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1, 失败原因存于errno 中。
(四)参考博文
CGI详解:http://www.360doc.com/content/18/0327/17/51484742_740649523.shtml
linux管道pipe详解:https://blog.csdn.net/oguro/article/details/53841949
pipe函数详解:https://blog.csdn.net/judgejames/article/details/84256340
重定向编程 dup和dup2函数:https://blog.csdn.net/u010006102/article/details/39667875/
进程间通信的方式——信号、管道、消息队列、共享内存:https://www.cnblogs.com/LUO77/p/5816326.html
进程等待之wait() & waitpid():https://blog.csdn.net/dangzhangjing97/article/details/79745880