您的位置:首页 > 其它

socket accept后的fd是否占用新端口

2016-07-21 20:24 537 查看
今天小组讨论了下自动化部署的架构与实现。在讨论推送配置的时候,我发现了一个问题,这也让我知道了我以前一直忽略的一个东西。

很多人socket编程很熟悉,但是能知道下面细节的人就不是那么多了。以前就想读tcp ip协议详解,可惜那时候的功力还没到,看来等有时间还是得细细品读。

大家都很熟悉,在server端编程,首先得创建一个socket并bind一个地址,然后进行listen和accept,当客户端有连接的时候,accept会返回一个fd,代表了与客户端的连接,我们可以通过这个fd来跟对应的client端进行io通讯,也可以捕捉到断开的事件。

问题就在上面accept的fd上面。我以前的理解一直以为这个fd占用了一个新的端口号,并且这个占用的端口号与client一致,通过相同的端口号进行传输。当时也没有怀疑正确与否,现在想来,真是错误百出。

首先,socketlisten后,是肯定占用了对应的端口号的,任何别的尝试使用该端口的操作肯定会报错,这是毋庸置疑的。accept的新的fd,占不占用新的端口号呢?看到这里大家肯定也都明白了,是不占用的。那不占用,肯定和listen的端口一样啊?不是上面说了一个端口只能使用一次吗?

这里就引出了socket的底层结构。区别两个socket是否一致,需要5元组来区别,分别是本机的ip 本机的端口 目标机的ip 目标机的端口 还有一个是协议。通过这些可以唯一的区别socket,当这些一致,那么这两个socket是一样的。系统提供的api,比如bind listen connect,其实都隐藏了对socket元组信息的写入。

再谈谈上述的问题,在accept一个新的连接后,其实fd的确是新的fd,但是它的本机ip port是和listen的一样的,而不同的client的fd之间的区别,就是不同的目标机的ip port信息。

这个问题解决了,那么我们再梳理一下结构。为何系统要划分端口号?其实端口这个概念,是在tcp这一层,即传输层实现的东西,为上层应用层提供支持。当应用层通过socket send数据的时候,tcp层会根据目标主机的ip port等信息进行数据包的进一步封装,然后将其交给ip层来进行网络传输,ip层则根据目标ip地址来将其再次封装然后最终交给物理层进行传输。

而对于client来说,首先ip层会收到这个数据,然后根据头部信息中的协议来交给不同的协议来进行处理。向上交给tcp层之后,tcp层会从头部数据中获取到端口号信息,到这一步其实已经可以唯一确定是哪个进程的数据了,通过端口号查到进程,并通知进程进行处理。这样整个通讯就走通了。

上面也谈到了,每一个socket都有一个local address和remote address,而对应的远程client的socket,也有一个local address和remote address,有意思的是,他们是互相相反的关系。其实想想也是,tcp向下传输的时候,需要给ip层传入remote ip,用于路由传输,而remote port,则会附加到数据头部中,因为这个remote port是需要给client来区分进程的。client收到了这个数据包后,根据server传入的port,则可以唯一的区分是哪个进程的数据包。而client发送的数据,则会带入client这个socket的remote
port,然后最终数据会传输给server listen 的那个socket。tcp数据头中还会有client的local address的信息,所以发送到server监听的socket上后,可以通过client的ip port来区分是哪一个client发送的数据,之后的就交由应用程序来处理了。

上面的总结也就是每个socket都是有着通过local address来与remote address相连的意思,也就是两个端口号是可以不一样的。

当然上面的只是记录下今天的想法,只是感觉有必要去读下tcp ip协议了,以前读着摸不着头脑,现在读着却有着原来是这样啊的感慨。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: