LinuxUnix网络编程复习资料.docx
- 文档编号:15860224
- 上传时间:2023-07-08
- 格式:DOCX
- 页数:36
- 大小:737.11KB
LinuxUnix网络编程复习资料.docx
《LinuxUnix网络编程复习资料.docx》由会员分享,可在线阅读,更多相关《LinuxUnix网络编程复习资料.docx(36页珍藏版)》请在冰点文库上搜索。
LinuxUnix网络编程复习资料
第一章TCP/IP简介
1.OSI模型和TCP/IP模型
2.TCP连接的建立
TCP连接的建立需要经过3次数据传输(三次握手),步骤如下:
(1)服务器必须已经准备好接收客户的连接请求,这通过调用socket、bind和listen函数来完成。
客户通过调用connect函数进行主动打开,这引起客户端发送一个SYN分节到服务器端。
(2)服务器收到客户端发来的SYN分节后,必须发送ACK对其进行确认,同时发送一个自己的SYN分节给客户端,表示接受客户端建立连接的请求。
(3)客户端发送ACK确认服务器SYN,建立连接成功。
3.TCP连接的终止
当数据传输完毕后,TCP需要发送4个分节终止该连接,释放TCP连接的步骤如下:
(1)客户端应用进程调用close,调用close的结果就是发送一个FIN分节主动关闭连接。
(2)服务器收到FIN后执行被动关闭,发送ACK对客户端的FIN分节进行确认。
(3)当服务器将待发的数据发送完后,调用close关闭它的套接字,这导致它的TCP发送一个FIN分节给客户端。
(4)接收到服务器的FIN分节后,对其发送一个ACK确认分节,当前的连接被彻底关闭。
第二章套接字编程简介
1.套接字的类型
套接字支持各种通信协议,目前Linux系统常用的协议有以下两种:
(1)INET:
IP版本4。
(2)INET6:
IP版本6。
套接字类型是指创建套接字的应用程序要使用的通信服务的类型。
Linux系统支持多种套接字类型,最常用的有以下几种:
(1)SOCK_STREAM:
流式套接字,提供面向连接、可靠的数据传输服务,数据按字节流、按顺序收发,保证数据在传输过程中无丢失、无冗余。
TCP协议支持该套接字。
(2)SOCK_DGRAM:
数据报套接字,提供面向无连接的服务,数据收发无序,不能保证数据的准确到达。
UDP协议支持该套接字。
(3)SOCK_RAW:
原始套接字。
允许对低于传输层的协议或物理网络直接访问例如可以接收和发送ICMP报。
常用于检测新的协议。
第三章基本TCP套接字编程
1.TCP套接字编程
TCP套接字编程中,服务器端实现的步骤如下:
(1)使用socket()函数创建套接字。
(2)将创建的套接字绑定到指定的地址结构。
(3)Listen()函数设置套接字为监听模式,使服务器进入被动打开的状态。
(4)接受客户端的连接请求,建立连接。
(5)接收、应答客户端的数据请求。
(6)终止连接。
客户端实现的步骤相对比较简单:
(1)使用socket()函数创建套接字。
(2)调用connect()函数建立一个与TCP服务器的连接。
(3)发送数据请求,接收服务器的数据应答。
(4)终止连接。
2.socket()函数
客户端服务器端都存在,产生TCP套接字,作为TCP通信的传输端点
#include
intsocket(intfamily,inttype,intprotocol)
返回:
非负套接字(sockfd)【0,1】-成功;-1-出错。
family:
协议族;type:
套接字类型;protocol:
一般为0,除原始套接字外。
Family(确定协议类型)type(指明产生套接字类型)
AF_INETIPv4协议SOCK_STREAM字节流套接口
AF_INET6IPv6协议SOCK_DGRAM数据报套接口
【AF_LOCALunix域协议】SOCK_RAW原始套接口
AF_ROUTE路由套接口
【AF_KEY密钥套接口】
3.bind()绑定函数
绑定函数的作用就是为调用socket()函数产生的套接字分配一个本地协议地址,建立地址与套接字的对应关系。
#include
intbind(intsockfd,conststructsockaddr*addr,socklen_lenlen)
返回:
0-成功;-1-出错并置errno
Sockfd:
套接字函数返回的套接字描述符server:
指向特定协议的地址结构的指针
addrlen:
套接字地址结构的长度
⏹该函数指明套接字将使用本地的哪一个协议端口进行数据传送(IP地址和端口号),注意:
协议地址addr是通用地址。
⏹一般而言,服务器调用此函数,而客户则很少调用它。
⏹绑定地址时,可以指定地址和端口号,也可以指定其中之一,甚至一个也不指定。
通配地址:
INADDR_ANY,其值一般为0,它通知内核选择IP地址。
IP地址端口结果
⏹通配地址0内核选择IP地址和端口号
⏹通配地址非0内核选择IP地址,进程指定端口
⏹本地IP0进程指定IP地址,内核选择端口
⏹本地IP非0进程指定IP地址和端口号
⏹若指定端口号为0,调用函数bind时,内核选择一个临时端口(在实际中,端口号都要指定);但若指定一个通配IP地址,则直到套接字已连接(TCP)或数据报已在套接字上发出(UDP),内核才选择一个本地IP地址。
strictsockaddr_inaddr;
intport=1234;
intopt=SO_REUSEADDR;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
bzero(&server,sizeof(server));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(port);
if(bind(fd,(structsockaddr*)&addr,sizeof(addr))==-1)
{
/*错误处理*/
}
4.listen()监听函数
#include
intlisten(intsockfd,intbacklog)
返回:
0-成功;-1-出错并置errno值;
Sockfd:
要设置的描述符
backlog:
规定请求队列中的最大连续数,对队列中等待服务请求的数目进行了限制
⏹函数listen仅被服务器调用,它完成两件事情:
⏹函数listen将未连接的套接字转化成被动套接字,指示内核应接受指向此套接字的连接请求;
⏹函数的第二个参数规定了内核为此套接字排队的最大连接个数;
⏹对于给定的监听套接字,内核要维护两个队列
⏹未完成连接队列
⏹已完成连接队列
⏹两个队列之和不超过backlog;
在TCP三次握手中监听套接字两个队列的位置如下图所示
5.connect()连接函数
#include
intconnect(intsockfd,conststructsockaddr*addr,socklen_taddrlen);
返回:
0-成功;-1-出错;
Sockfd:
套接字描述符addr:
指向服务器套接字地址结构的指针
addrlen:
套接字地址结构的大小
⏹函数connect激发TCP的三路握手过程;仅在成功或出错返回;错误有以下几种情况:
(1)如果客户没有收到SYN分节的响应,则返回ETIMEDOUT。
(2)如果对客户的SYN的响应是RST,则表明该服务器主机在指定的端口上没有进程在等待与之相连。
函数返回错误ECONNREFUSED;
(3)如果客户发出的SYN在中间路由器上引发一个目的地不可达ICMP错误,客户上的内核保存此消息,并按第一种情况,连续发送SYN,直到规定时间,返回保存的消息(即ICMP错误)作为EHOSTUNREACH或ENETUNREACH错误返回给进程
6.accept()
#include
intaccept(intsockfd,structsockaddr*cliaddr,socklen_t*addrlen);
返回:
[非负描述字(connfd)]1,0-OK;-1-出错;
Listenfd:
套接字描述符cliaddr:
套接字地址结构addrlen:
套接字地址结构长度
⏹accept函数由TCP服务器调用;从已完成连接队列头返回下一个已完成连接;如果该队列空,则进程进入睡眠状态。
⏹函数返回的套接字为已连接套接字,应与监听套接字区分开来
⏹【该函数最多返回三个值:
一个既可能是新套接字也可能是错误指示的整数,一个客户进程的协议地址(由cliaddr所指),以及该地址的大小(这后两个参数是值-结果参数);也就是说,】服务器可以通过参数cliaddr来得到请求连接并获得成功的客户的地址和端口号;
7.close()
#include
intclose(intsockfd);
返回:
0-OK;-1-出错;
Sockfd:
要关闭的描述符
⏹close函数缺省功能是将套接字做上“已关闭”标记,并立即返回到进程。
这个套接字不能再为该进程所用。
⏹正常情况下,close将引发向TCP的四分节终止序列,但在终止前将发送已排队的数据;
如果套接字描述符访问计数在调用close后大于0(在多个进程共享同一个套接字的情况下),则不会引发TCP终止序列(即不会发送FIN分节);
8.Shutdown()
#include
intshutdown(intsockfd,inthowto);
返回:
0-OK;-1-出错,并置相应的errno的值;
Sockfd:
要关闭的套接字描述符
该函数立即发送FIN分节。
shutdown根据参数howto关闭指定方向的数据传输;
⏹SHUT_RD:
关闭连接的读这一半,不再接收套接字中的数据且现留在接收缓冲区的数据作废;
⏹SHUT_WD:
关闭连接的写这一半(半关闭),当留在套接字发送缓冲区中的数据都被发送,后跟tcp连接终止序列,不管访问计数是否大于0;此后将不能在执行对套接字的任何写操作;
⏹SHUT_RDWR:
连接的读、写都关闭,这等效于调用shutdown两次,一次调用是用SHUT_RD,第二次用SHUT_WR。
9.Read()函数
#include
intread(intfd,char*buf,intlen);
返回:
大于0-读写字节大小;-1-出错;
调用函数read时,有如下几种情况:
⏹套接字接收缓冲区接收数据,返回接收到的字节数;
⏹tcp协议收到FIN数据,返回0;
⏹tcp协议收到RST数据,返回-1,同时errno为ECONNRESET;
⏹进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。
read(connfd,buff,strlen(buff));
10.write()函数
#include
intwrite(intfd,char*buf,intlen);
返回:
大于0-读写字节大小;-1-出错;
Buf:
用于发送信息的缓冲区len:
缓冲区大小
调用函数write,有如下几种情况:
⏹套接字发送缓冲区有足够空间,返回发送的字节数;
⏹tcp协议接收到RST数据,返回-1,同时errno为ECONNRESET;;
⏹进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。
write(connfd,buff,strlen(buff));
11.send()发送函数
#include
#include
ssize_tsend(intfd,constvoid*msg,size_tlen,intflags);
返回:
非0-发送成功的数据长度;-1-出错;
flags是传输控制标志,其值定义如下:
⏹0:
常规操作,如同write()函数
⏹MSG_OOB,发送带外数据(TCP紧急数据)。
⏹MSG_DONTROUTE:
忽略底层协议的路由设置,只能将数据发送给与发送机处在同一个网络中的机器上。
12.recv()接收函数
#include
#include
ssize_trecv(intfd,void*buf,size_tlen,intflags);
返回:
大于0表示成功接收的数据长度;0:
对方已关闭,-1:
出错。
⏹flags是传输控制标志,其值定义如下:
⏹0:
常规操作,如同read()函数;
⏹MSG_PEEK:
只查看数据而不读出数据,后续读操作仍然能读出所查看的该数据;
⏹MSG_OOB:
忽略常规数据,而只读带外数据;
⏹MSG_WAITALL:
recv函数只有在将接收缓冲区填满后才返回。
13.服务器的三种异常情况(选)
(1)服务器主机崩溃时,已有的网络连接上发不出任何东西。
⏹同时假设应用程序发出数据后,然后阻塞于从套接字读取响应。
⏹由于服务器主机崩溃,因此客户tcp会持续重传数据分节,试图从服务器接收一个ACK:
源自Berkeley的实现将重传12次。
当客户tcp最终放弃时,返回给客户一个错误,此时错误是ETIMEDOUT,或者是因为中间路由器判定服务器主机不可达,且以一个目的地不可达的ICMP消息响应,则错误是EHOSTUNREACH或ENETUNREACH。
⏹通过设置套接字选项可以更改tcp持续重传等待的超时时间。
(2)服务器主机崩溃后重启
在这种情况下,如果客户在主机崩溃重启前不主动发送数据,那么客户是不会知道服务器已崩溃的。
在服务器重启后,客户向服务器发送一个数据分节;
由于服务器重启后丢失了以前的连接信息,因此导致服务器主机的tcp响应RST;
当客户tcp收到RST,向客户返回错误,ECONNRESET
如果客户对服务器的崩溃情况很关心,即使客户不主动发送数据也这样,就需要其他技术支持
(3)服务器主机关机
当Linux主机关机时,由init进程给所有运行的进程发信号SIGTERM
⏹如果服务器程序忽略了SIGTERM信号,则init进程会等待一段固定的时间,然后给所有还在运行的程序发信号SIGKILL;服务器将由信号SIGKILL终止,其终止时,所有打开的描述字被关闭,这导致向客户发送FIN分节;客户收到FIN分节后,能推断出服务器将终止服务。
第四章基本UDP套接口编程
1.UDP套接字编程
使用UDP套接字编程可以实现基于TCP/IP协议的面向无连接的通信,它分为服务器端和客户端两部分,其实现过程如下图所示。
在UDP套接字编程中,服务器端实现的步骤如下:
(1)使用socket90函数创建套接字。
【socket()→int()】
(2)将创建的套接字绑定到指定的地址结构。
【bind()】
(3)等待接收客户端的数据请求。
【recvfrom()】
(4)处理客户端请求。
(5)向客户端发送应答数据。
【sendto()】
(6)关闭套接字。
【close()】
客户端实现的步骤如下(没有监听,没有接收):
(1)使用socket()函数创建套接字。
(2)发送数据请求给服务器。
(3)等待接收服务器的数据应答。
(4)关闭套接字。
2.recvfrom()函数
#include
#include
ssize_trecvfrom(intsockfd,void*buf,size_tlen,intflags,structsockaddr*from,int*fromlen);
返回:
大于0-成功接收数据长度;-1-出错;
Sockfdbuflen:
调用socket()函数生成的描述符,指向缓冲区的指针,读入的字节数
from:
与之通信的套接字地址结构
addrlen:
指向整数值的指针,发送者的套接字地址结构的长度
⏹UDP套接字使用无连接协议,因此必须使用recvfrom函数,指明源地址;
⏹flags是传输控制标志,其值定义如下:
⏹0:
常规操作,如同read()函数;
⏹MSG_PEEK:
只察看数据而不读出数据;
⏹MSG_OOB:
忽略常规数据,而只读取带外数据;
⏹from和fromlen是“值-结果”参数。
3.sendto函数
#include
#include
ssize_tsendto(intsockfd,constvoid*msg,size_tlen,intflags,conststructsockaddr*to,inttolen);
返回:
大于0-成功发送数据长度;-1-出错;
Sockfd:
调用socket函数生成的描述符msg:
缓冲区指针len:
发送的字节数
to:
数据将发送的协议地址tolen:
一个整数值,协议地址大小
⏹UDP套接字使用无连接协议,因此必须使用sendto函数,指明目的地址;
⏹flags是传输控制标志,其值定义如下:
⏹0:
常规操作,如同write()函数;
⏹MSG_OOB:
发送带外数据;
⏹MSG_DONTROUTE:
忽略底层路由协议,直接发送。
第五章并发服务器
1.进程的基本概念
进程定义了一个计算的基本单元,可以认为是一个程序的一次运行。
它是一个动态实体,是独立的任务。
它拥有独立的地址空间、执行堆栈、文件描述符等。
一个进程不能访问另一个进程的资源,一个进程的崩溃不会造成其他进程的崩溃;进程又是互相影响的,进程之间可以通过IPC机制相互通信。
当进程间共享某一资源时,需注意两个问题:
同步问题和通信问题。
2.fork函数
#include
#include
pid_tfork(void)
返回:
父进程中返回子进程的进程ID,子进程返回0,
-1-出错
fork后,子进程和父进程继续执行fork()函数后的指令。
子进程是父进程的副本。
子进程拥有父进程的数据空间、堆栈的副本。
但父、子进程并不共享这些存储空间部分。
如果代码段是只读的,则父子进程共享代码段。
如果父子进程同时对同一文件描述字操作,而又没有任何形式的同步,则会出现混乱的状况;
父进程中调用fork之前打开的所有描述字在函数fork返回之后子进程会得到一个副本。
fork后,父子进程均需要将自己不使用的描述字关闭。
3.进程终止
进程的终止存在两个可能:
父进程先于子进程终止(init进程领养)
子进程先于主进程终止
对于后者,系统内核为子进程保留一定的状态信息:
进程ID、终止状态、CPU时间等;当父进程调用wait或waitpid函数时,获取这些信息;
当子进程正常或异常终止时,系统内核向其父进程发送SIGCHLD信号;缺省情况下,父进程忽略该信号,或者提供一个该信号发生时即被调用的函数。
什么叫“僵尸进程”?
一个已经终止但是其父进程尚未对其进行善后处理的进程
如何避免“僵尸进程的产生”:
(原因在于主进程未对子进程进行资源回收)父进程调用SIGCHLD和wait(),waitpid()来对子进程进行资源回收。
4.wait函数
#include
#include
pid_twait(int*stat_loc);
返回:
终止子进程的ID-成功;-1-出错;
stat_loc存储子进程的终止状态(一个整数);
如果没有终止的子进程,但是有一个或多个正在执行的子进程,则该函数将堵塞,直到有一个子进程终止或者wait被信号中断时,wait返回。
当调用该系统调用时,如果有一个子进程已经终止,则该系统调用立即返回,并释放子进程所有资源。
5.waitpid函数
pitywaitpid(pid_tpid,int*stat_loc,intoptions);
返回:
终止子进程的ID-成功;-1-出错;stat_loc存储子进程的终止状态;
当pid=-1,option=0时,该函数等同于wait,否则由参数pid和option共同决定函数行为,其中pid参数意义如下:
-1:
要求知道任何一个子进程的返回状态(等待第一个终止的子进程);
>0:
要求知道进程号为pid的子进程的状态;
<-1:
要求知道进程号为pid的绝对值的子进程的终止状态
Options最常用的选项是WNOHANG,它通知内核在没有已终止进程时不要堵塞。
6.exit函数
#include
voidexit(intstatus);
本函数终止调用进程。
关闭所有子进程打开的描述符,向父进程发送SIGCHLD信号,并返回状态。
7.多进程并发服务器
下面用图例说明父进程调用fork生成子进程后,父、子进程对描述符的操作过程。
当服务器调用accept()函数时,连接请求从客户到达服务器时双方的状态如图5-3所示。
客户的连接请求被服务器接收后,新的已连接套接字即connfd被创建,可通过此描述符读、写数据,此时双方的状态如图5-4所示。
服务器的下一步就是调用fork函数,如图5-5所示,给出了从fork()函数返回后的状态。
此时的描述符listenfd和connfd在父、子进程间共享。
接下来就由父进程关闭已连接描述符,由子进程关闭监听描述符,当前双方的状态如图5-6所示。
8.线程
线程是进程内的独立执行实体和调度单元,①又称为“轻量级”进程(lightwightprocess);②创建线程比进程快10~100倍。
③一个进程内的所有线程共享相同的内存空间、全局变量等信息(这种机制又带来了同步问题),所以一个线程崩溃时,它会影响同一进程中的其他线程。
9.pthread_create()函数
pthread_create()函数用于创建新进程,系统产生一个称为初始线程或主线程的单个线程,额外的线程需要由pthread_create()函数创建。
#include
intpthread_create(pthread_t*tid,constpthread_attr_t*attr,void*(*func)(void*),void*arg);
返回:
成功时为0;出错时为正的Exxx值
新线程由线程id标识:
tid,新线程的属性attr包括:
优先级、初始栈大小、是否应该是守护线程等等。
线程的执行函数和调用参数分别是:
func和arg;
由于线程的执行函数的参数和返回值类型均为void*,因此可传递和返回指向任何类型的指针;
常见的返回错误值:
EAGAIN:
超过了系统线程数目的限制。
ENOMEN:
没有足够的内存产生新的线程。
EINVAL:
无效的属性attr值。
10.pthread_join()函数
pthread_join()函数与进程的waitpid()函数功能类似,等待
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- LinuxUnix 网络 编程 复习资料
![提示](https://static.bingdoc.com/images/bang_tan.gif)