TCP socket上的connect

mytcp_v4_connect是IPv4相关的一个tcp协议连接函数,在myinet_stream_connect中,检查到struct socket->state状态为SS_UNCONNECTED后,调用该函数。该函数首先调用myip_route_connect确定到连接对端的路由,根据路由查询的结果,填充inet_sock->saddr, inet_sock->rcv_saddr, inet_sock->daddr的值。     接下来是一些tcp socket相关的参数的设置,我们暂时先略过。在mytcp_v4_connect中把struct sock->sk_state的状态改为TCP_SYN_SENT,这是建立TCP连接的三次握手协议的第一步的状态。     接下来调用函数myinet_hash_connect,为tcp socket绑定一个本地端口。mytcp_hashinfo是一个全局变量,它管理很多tcp协议中需要用到的哈希表,其类型是一个结构体struct inet_hashinfo,定义如下:     struct inet_hashinfo {         struct inet_ehash_bucket    *ehash;         struct inet_bind_hashbucket *bhash;         int             bhash_size;         unsigned int    ehash_size;         struct hlist_head       listening_hash[INET_LHTABLE_SIZE];         rwlock_t            lhash_lock ____cacheline_aligned;         atomic_t            lhash_users;         wait_queue_head_t   lhash_wait;         kmem_cache_t        *bind_bucket_cachep;     };     bind_bucket_cachep是一块后备高速缓存,其单位内存大小为一个结构体struct inet_bind_bucket的大小,插入哈希表bhash中的结构体struct inet_bind_bucket都是从这块后备高速缓存中进行分配。该结构体是一个关于本地端口信息的结构体,其完整定义如下:     struct inet_bind_bucket {         unsigned short      port;       //端口         signed short        fastreuse;  //重用。         struct hlist_node   node;       //作为bhash链表的节点。         struct hlist_head   owners;     //绑定在该端口上的socket的链表。     };     bhash_size是关于哈希表bhash的大小。     myinet_hash_connect首先在范围32768-61000之间为该tcp socket选择一个可以使用的本地端口,然后为该端口建立一个结构体struct inet_bind_bucket,插入到mytcp_hashinfo.bhash中。     接下来,inet_sock->snum = port。套接口struct sock有一个成员sk_bind_node,用于把struct sock放入到一个链表中,在这里,我们把该tcp socket放入到struct inet_bind_bucket->owners的链表中,表示该socket绑定在了该端口上。同时,struct inet_connection_sock是结构体struct inet_sock的一个扩展,它有一个成员icsk_bind_hash,用于指向刚刚创建的struct inet_bind_bucket。这三步操作把一个tcp本地套接口完全绑定到了一个端口上。     接下来,我们还要把struct sock本身放到一个哈希队列中,这跟udp, raw的哈希表功能相似,是为了接收数据时,能够找到这个socket。根据tcp socket本身的工作状态,如果它处于TCP_LISTEN,则把这个socket放入到哈希队列listening_hash中,否则,放入到哈希队列ehash中,ehash实际上是被一分为二的,前半部分放非TIME_WAIT状态的socket,后半部分放TIME_WAIT状态的socket。struct sock的成员sk_node用于把socket放入到队列中。     struct inet_hashinfo的成员lhash_wait中存放的应该是等待连接接收的来自网络中其它主机的连接请求,如果当前有一个tcp socket进入listening_hash哈希队列,则唤醒该等待队列。     如果在myinet_hash_connect函数中,我们发现要绑定的本地端口已经在bhash哈希队列中存在,我们可以选择跳过,取下一个端口继续尝试,也可以重用该端口,这里有一些规则需要遵守。首先,如果结构体的成员fastreuse>=0,则不可重用,直接取下一个。否则,调用__myinet_check_established进行验证,验证的基本原理是绑定在不同网络设备接口上的socket可以共用端口;如果每个socket的sk_reuse被置位,并且都不处于TCP_LISTEN状态,则可以共用端口;如果所有的socket都被绑定到同一个rcv_saddr本地地址,但它们都是不相同的,则可以共用端口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值