connect和bind

来源:互联网 发布:淘宝风水阁真的假的 编辑:程序博客网 时间:2024/05/09 10:40

UDP:

考虑以下情形:我们使用UDP写一个echo程序,客户端模型:

while(fget()){sendto();recvfrom();}

如果服务器进程没有启动会如何?通过截包发现服务器响应一个icmp: port unreachable。不过这个ICMP错误不会返回给客户进程。原因稍后讲述。客户端永远阻塞在recvfrom调用。

我们称这个错误为异步错误。该错误由sendto引起,但是sendto本身却成功返回---因为我们知道UDP输出操作成功返回仅仅表示在接口输出队列中具有存放数据的空间。该ICMP在sendto返回之后才收到,这就是称为异步的原因。

一个基本规则是:对于一个UDP套接口,由他引发的异步错误并不返回给它,除非它已连接。我们后面将讲到如何给UDP套接口调用connect。

除非套接口是已连接的,否则异步错误不会返回到UDP套接口的。我们确实可以给UDP套接口调用connect,然而这样做的结果却与TCP连接大相径庭:没有三次握手。相反,内核只是检测是否存在立即可知的错误(如一个显然不可达的目的地),记录对端的IP地址和端口号,然后理解返回给调用进程。


从上图我们看到,任何来自非绑定的IP地址的数据报(???表示)不投递给这个已连接的套接口,因为他们要么源ip地址要不UDP端口不与该套接口connect到的协议地址相匹配。这些数据报肯能投递给同一个主机上的其他某个UDP的套接口,如果没有匹配的其他套接口,UDP将丢弃他们并生成相应的ICMP端口不可达错误。

小结:我们可以说UDP客户进程或服务器进程仅仅在使用自己的UDP套接口与确定的唯一对端通信时,才可以调用connect。调用connect的通常是UDP客户,不过有些网络应用中的UDP服务器会与单个客户长时间通信(TFTP),这种情况下,客户和服务器可能调用connect。


我们前面讲到,不进行connect的UDP客户端无法找到异步错误,我们如果改成connect的话,服务器进程没有开启,会返回错误。

while(fgets()){//connect的只用read就可以,不需要recvfromwrite();read();}

形式如下:

$hello,world

read error:Connection refused.

注:该ICMP错误由内核映射成ECONNREFUSED错误,相应于由err_sys(自己实现)输出消息串:Connection refused

TCP:

connect函数会激发TCP的三次握手过程,而且仅在连接成功或者出错才返回,其中出错返回可能有如下情况:

1.TCP客户没有收到SYN分节的响应,返回ETIMEDOUT错误。

模拟:比如我们客户连接本地子网一个不存在的IP地址,这样客户机发送ARP请求,永远收不到响应,connect超时。

2.若对客户的SYN响应是RST(表示复位),则表明该服务器主机在我们制定的端口上没有进程在等待与之相连(例如服务器进程没有运行)。这是一种硬错误,客户一接收到RST就马上返回ECONNREFUSE错误。

RST是TCP在发生错误时发送的一种分节。产生的三个条件:目的端口到达SYN,然而该端口没有监听的服务器进程(如前所述);TCP想取消一个已有连接;TCP收到一个根本不存在的连接上的分节。

3.若客户发出的SYN在中间的某个路由器上引发“destination unreachable"ICMP错误,则认为是软错误。客户主机内核保存该消息,并继续发送SYN,若一定时间还没收到响应,则保存的消息(ICMP错误)作为EHOSTUNREACH或者ENETUNREACH错误返回给进程。

模拟:连接一个因特网中不存在IP地址。

注:上面返回XXX错误给进程,其实就是将errno赋值,我们检测該值就可以获取错误类型。



下面稍微讲点Bind

进程可以把一个特定的ip直至捆绑到他的套接口。对于TCP客户,bind操作为该套接口上发送的数据指派源ip地址。不过TCP客户通常不指定捆绑特定ip。因为当连接套接口时,内核将根据所用外出网络接口来选择ip地址,而所用外出接口取决于到达服务器的路径。

对于ipv4来说,统配地址是INADDR_ANY。他告知内核去选择ip地址。

0 0
原创粉丝点击