代码改变世界

unix网络编程之基本套接口编程

2012-08-16 21:30  javaspring  阅读(204)  评论(0编辑  收藏  举报

第一章  套接口编程简介

IPv4套接口地址:“网际套接口地址结构”

通用套接口地址结构:

套接口函数被定义为采用指向通用套接口地址结构的指针,这要求对这些函数的任何调用都必须将指向特定于协议的套接口地址结构的指针类型转换成指向通用套接口地址结构的指针:

套接口地址结构的比较:

值-结果参数:

当把套接口地址结构传递给套接口函数时,总是通过指针来传递的,即传递的是一个指向结构的指针。

1, 从进程到内核传递套接口地址结构有3个函数:bind、connect、sendto,这3个函数的一个参数时指向套接口地址结构的指针,另一个参数是结构的整数大小,例如:

2,与前面的传递方向相反,从内核到进程的传递套接口地址结构有4个函数:accept、recvfrom、getsockname和getpeername。这4个函数的两个参数是:指向套接口地址借口的指针和指向表示结构大小的整数的指针,例如:

这样len不仅作为值传递也作为结构返回,引用参数你懂的。被称为值-结果参数。

字节排序函数:

小端字节序:将低序字节储存在起始地址;

大端字节序:将高序字节储存在起始地址;

主机字节序和网络字节序间要相互转换:

字节操纵函数:

bzero将目标中指定数目的字节置为0,

 

 

 

第二章  基本套接口编程

TCP客户与服务器间发生的一些典型事件的时间表:

Socket函数:

int socket(int domain , int type , int protocol)

socket函数在成功时返回一个小的非负整数值,它与文件描述字类似,我们把它称为套接口描述字,简称套接字。

Connect函数:

int connect (int sockfd, struct sockaddr*serv_addr, int addrlen);

TCP客户用connect函数来建立一个与TCP服务器的连接。

如果是tcp套接口的话,函数connect激发TCP的三路握手过程。

bind函数:

int bind (int sockfd , struct sockaddr *my_addr ,int addrlen) ;

函数bind给套接口分配一个本地协议地址。其中套接口是捆绑的主体,地址和端口则是捆绑在套接口上的客体。

对于IPV4来说,通配地址由常值INADDR_ANY来指定,其值一般为0,它通知内核选择IP地址。

listen函数

int listen(int sockfd, int backlog);

第二个参数规定了内核为此套接口排队的最大连接个数。

对于给定的监听套接口,内核要维护两个队列:

accept函数:

int accept(int sockfd, void *addr, int *addrlen);

accept由TCP服务器调用,从已完成连接队列头返回下一个已完成连接。若已完成连接队列为空,则进程睡眠。

参数addr和addrlen用来返回对方进程(客户)的协议地址,addrlen是值-结构参数:调用前,我们将由*addrlen所指的整数值置为由addr所指的套接口地址结构的长度,返回时,此整数值即为有内核存在此套接口地址结构内的准确字节数。

如果函数执行成功,则返回值是由内核自动生成的一个全新描述字,代表与客户的TCP连接。

并发服务器:具体的例子请参见本博客中的unix网络编程实例9种TCP客户-服务器程序设计附环境搭建和编译方法

不可能让一个服务器尝试间地位某一个客户服务,而是同时为多个客户服务。

当父进程close关闭connfd子进程关闭listerfd后:

如果父进程不对每个由accept返回的已连接套接口调用close,并发服务器会发生什么。

首先,父进程最终将耗尽可用描述字,因为任何进程…

第三章  TCP客户-服务器程序例子

回射服务器:

1, 客户从标准输入读一行文本,写到服务器上;

2, 服务器从网络输入读此行,并回射给客户;

3, 客户度此回射行并写到标准输出;

Posix信号:

信号时发生某事件时对进程的通知,有时称为软中断。它一般是异步的,这就是说,进程不可能提前知道信号发生的时间。

信号可以:

由一进程发往另一进程(或本身);

由内核发往某进程;

SIGSTOP 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:

该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略

对于SIGKILL信号,进程是不能忽略的。这是一个 “我不管您在做什么,立刻停止”的信号。假如您发送SIGKILL信号给进程,Linux就将进程停止在那里。

这两个进程都不能被捕捉;

处理SIGCHLD信号:

设置僵尸状态的目的就是维护子进程的信息,以便父进程在稍后的某个时候取回。如果进程将SIGCHLD的处理方法置为SIG_IGN,它的子进程就不会成为僵尸进程。另一个处理僵尸进程的方法就是捕捉SIGCHLD,并调用wait或waitpid;

僵尸进程:

由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 那么会不会因为父进程太忙来不及wait子进程,或者说不知道 子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。因为UNIX提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

在这段代码中,我们所做的事情就是自己重启被中断的系统调用: