1.connect函数响应中断返回后仍然回到函数的调用。
实践证实,对于一个非阻塞的socket,若是在调用connect函数时,若是发生中断,这函数响应中断,但当中断返回时,继续connect函数的调用,直到connect超时失败或接收到错误ICMP包或链接成功服务器
2.accept()
若是侦听进程是非阻塞模式工做,当调用accept()函数接收来自客户端的请求后,返回的socket套接字,默认为阻塞的工做模式。网络
1、阻塞模型
可能发生阻塞的套接口调用分为四种:
1>.输入操做:read、readv、recv、recvfrom和recvmsg函数
2>.输出操做:write、writev、send、sendto和sendmsg函数
3>.接收外来链接:accept()函数
4>.初始化外出的链接:connect()函数数据结构
2、I/O模型
1.阻塞I/O
2.非阻塞I/O
3.I/O复用(select函数)
4.信号驱动I/O(SIGIO)
5.异步I/O异步
3、I/O复用模型的应用场合
1.当客户处理多个描述字时(通常是交互式输入和网络套接口),必须使用I/O复用。
2.一个客户同时处理多个套接口
3.若是一个TCP服务器既要处理侦听套接口,又要处理已链接套接口,通常也要用到I/O复用。
4.若是一个服务器既要处理TCP,又要处理UDP,通常也要使用I/O复用。
5.若是一个服务器要处理多个服务或者多个协议(inetd守护进程)。socket
4、拒绝服务型攻击
服务器某一个时刻阻塞于只处理单个客户,而不能处理其余客户的需求,这就致使了拒绝服务型攻击,可能的解决办法是:(a)使用非阻塞I/O模型;(b)让 每一个客户由单独的控制线程提供服务(例如,建立子进程或线程来为每一个客户提供服务);(c)对I/O操做设置超时。函数
5、connect()函数
1.阻塞模式
客户端调用connect()函数将激发TCP的三路握手过程,但仅在链接创建成功或出错时才返回。返回的错误可能有如下几种状况:
1>.若是TCP客户端没有接收到SYN分节的响应,则返回ETIMEDOUT,阻塞模式的超时时间在75秒(4.4BSD内核)到几分钟之间。
2>.若是对客户的SYN的响应时RST,则代表该服务器主机在咱们指定的端口上没有进程在等待与之链接(例如服务器进程也许没有启动),这称为硬错,客户一接收到RST,立刻就返回错误ECONNREFUSED.
3>.若是某客户发出的SYN在中间的路由器上引起了一个目的地不可达ICMP错误,屡次尝试发送失败后返回错误号为EHOSTUNREACH或ENETUNREACH.spa
附加:产生RST的三种状况,一是SYN到达某端口但此端口上没有正在侦听的服务器、二是TCP想取消一个已有链接、三是TCP接收了一个根本不存在的链接上的分节。线程
2.非阻塞模式
采用非阻塞的工做模式要考虑一下两种状况:
1>.若是是链接本机,则调用connect()函数会马上创建。
2>.若是服务器是网络中的用户,则调用connect()函数须要从几个毫秒的局域网到几百毫秒或几秒的广域网。而且函数会马上返回EINPROCESS错误,但TCP通讯的三路握手过程正在进行,因此可使用select函数来检查这个链接是否创建成功。
源自Berkeley的实现有两条与select函数和非阻塞相关的规则:
1>.当链接成功创建时,描述字变成可写。
2>.当链接创建出错时,描述字变成便可读又可写。code
6、accept()函数
1.阻塞模式
若是在一个阻塞套接口上调用accept()函数,并且没有新的链接,进程会进入睡眠状态。orm
2.非阻塞模式
若是在一个非阻塞套接口上调用accept()函数,并且没有新的链接,将返回EWOULDBLOCK错误。
3.一种非阻塞模式例子的问题及解决办法
问题描述:在服务器端侦听套接口采用阻塞的方式工做,而且使用select检测是否有已经创建起的链接,若是有则调用accept()函数接收该链接,问 题是若是客户端首先调用connect()函数链接服务器后马上又调用close()函数关闭该链接,而在服务器端,在select()函数返回和调用 accept()函数之间,接收到客户端的断开,则会删除该套接口在已链接套接口中的内容,因此服务器将会阻塞在accept()函数,直到有客户链接才 返回。
解决办法:(1).若是用select来获知什么时候有链接已就绪能够accept时,老是把侦听套接口置为非阻塞,同时(2).在后面的accept调用中 忽略如下错误:EWOULDBLOCK(Berkeley的实如今客户放弃链接时出现的错误)、ECONNABORTED(Posix.1g的实如今客户 放弃链接时出现的错误)、EPROTO(SVR4的实如今客户放弃链接时出现的错误)和EINTR(若是信号被捕获)。
7、select()函数
select()函数准备好读的条件:
1>.套接口有数据可读
2>.该链接的读这一半关闭(也就是接收了FIN的TCP链接)。对这样的套接口进行读操做将不阻塞并返回0(也就是返回EOF)。
3>.该套接口是一个侦听套接口且已完成的链接数不为0。
4>.其上有一个套接口错误待处理,对这样的套接口的读操做将不阻塞并返回-1,并设置errno,能够经过设置SO_ERROR选项调用getsockopt函数得到。
select()函数准备好写的条件:
1>.套接口有可用于写的空间。
2>.该链接的写这一半关闭,对这样的套接口进行写操做将产生SIGPIPE信号。
3>.该套接口使用非阻塞的方式connect创建链接,而且链接已经异步创建,或则connect已经以失败了结。
4>.其上有一个套接口错误待处理。
8、read()函数和recv函数
read()函数返回值表明的意义:
1>.若是对方TCP发送数据,则套接口就变为可读且read返回大于0的值(即数据的字节数)。
2>.若是对方TCP发送一个FIN(对方进程终止),套接口就变为可读且read返回0(文件结束)。
3>.若是对方TCP发送一个RST(对方主机崩溃并从新启动),套接口就变成可读且read返回-1,返回的错误号errno为ECONNRESET。
9、write()函数和send函数
若是向一个接收了FIN的套接字进行写操做是可行的,但若是向一个接受了RST的套接字进行写操做则是致命的,内核会向该进程发送一个SIGPIPE信号,返回EPIPO,该错误类型默认为终止进程。
SIGPIPE信号
向一个接受了RST的套接字进行写操做时,内核会向该进程发送一个SIGPIPE信号,该信号的缺省行为是终止进程,所以进程必须捕获它以避免被不情愿的终止。
五、 Linux中Socket的数据结构
(1)
struct sockaddr { //用于存储套接字地址 unsigned short sa_family;//地址类型 char sa_data[14]; //14字节的协议地址 };
(2)
struct sockaddr_in{ //in 表明internet short int sin_family; //internet协议族 unsigned short int sin_port;//端口号,必须是网络字节顺序 struct in_addr sin_addr;//internet地址,必须是网络字节顺序 unsigned char sin_zero;//添0(和struct sockaddr同样大小 };
(3)
struct in_addr{ unsigned long s_addr; };