tcp当主动发出syn_tcp 客户端 发送syn

/*This will initiate an outgoing connection.

1. 检查socket的地址长度和使用的协议族。

2. 查找路由缓存。

3. 设置本端的IP。

4. 如果传输控制块已经被使用过了,则重新初始化相关变量。

5. 记录服务器端的IP和端口。

6. 把连接的状态更新为TCP_SYN_SENT。

7. 选取本地端口,可以是未被使用过的端口,也可以是允许重用的端口。

8. 把sock链入本地端口的使用者哈希队列,把sock链入ehash哈希表。

9. 如果源端口或者目的端口发生改变,则需要重新查找路由。

10. 根据四元组,设置本端的初始序列号。

11. 根据初始序号和当前时间,设置IP首部ID字段值。

12. 构造一个SYN段,并发送出去。

调用ip_route_connect和ip_route_newports创建或者获取路由缓存,并决定发送地址/设备, 下一跳

更新状态机TCP_CLOSE->TCP_SYN_SENT

inet_hash_connect(&tcp_death_row, sk); 如果socket没有bind到特定端口,这里选择端口进行bind, 如果是reuseport判断能否recycle tw

tp->write_seq = secure_tcp_sequence_number() 生产初始seq序号

tcp_connect()发送握手包*/

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, intaddr_len)

{struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;struct inet_sock *inet =inet_sk(sk);struct tcp_sock *tp =tcp_sk(sk);

__be16 orig_sport, orig_dport;

__be32 daddr, nexthop;struct flowi4 *fl4;struct rtable *rt;interr;struct ip_options_rcu *inet_opt;if (addr_len < sizeof(structsockaddr_in))return -EINVAL;if (usin->sin_family !=AF_INET)return -EAFNOSUPPORT;//connect的时候s_addr里面对应的是目的地址,即对端ip地址

nexthop = daddr = usin->sin_addr.s_addr;

inet_opt= rcu_dereference_protected(inet->inet_opt,

lockdep_sock_is_held(sk));if (inet_opt && inet_opt->opt.srr) {if (!daddr)return -EINVAL;

nexthop= inet_opt->opt.faddr;

}

orig_sport= inet->inet_sport;

orig_dport= usin->sin_port;

fl4= &inet->cork.fl.u.ip4;/*根据fl4,查找或创建路由缓存

* 调用ip_route_connect()根据下一跳地址等信息查找目的路由缓存项,如果路由查找命中,则生成一个相应的路由缓存项,这个缓存项不但

* 可以用于当前待发送SYN段,而且对后续的所有数据包都可以起到一个加速路由查找的作用。*/rt= ip_route_connect(fl4, nexthop, inet->inet_saddr,

RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,

IPPROTO_TCP,

orig_sport, orig_dport, sk);if(IS_ERR(rt)) {

err=PTR_ERR(rt);if (err == -ENETUNREACH)

IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);returnerr;

}/*TCP不能使用类型为组播或多播的路由缓存项。*/

if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { //tcp不支持多播和广播

ip_rt_put(rt);return -ENETUNREACH;

}/*如果没有启用源路由选项,则使用获取到路由缓存项中的目的地址。*/

if (!inet_opt || !inet_opt->opt.srr)

daddr= fl4->daddr;/*如果还未设置传输控制块中的源地址,则使用路由缓存项中的源地址对其进行设置。*/

//这里说明了客户端在连接的时候可以不用指明本地IP地址,由路由缓存找到对应目的IP的时候,就可以确定本地IP地址了。

if (!inet->inet_saddr)

inet->inet_saddr = fl4->saddr;

sk_rcv_saddr_set(sk, inet->inet_saddr);/*如果传输控制块中的时间戳和目的地址已被使用过,则说明该传输控制块之前已建立连接并进行过通信,需重新初始化相关成员。*/

if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr !=daddr) {/*Reset inherited state*/tp->rx_opt.ts_recent = 0;

tp->rx_opt.ts_recent_stamp = 0;if (likely(!tp->repair))

tp->write_seq = 0;

}/*如果启用了sysctl_tw_recycle并接收过时间戳选项,从对端信息块中获取相应的值来初始化ts_recent_stamp和ts_recent。*/

if (tcp_death_row.sysctl_tw_recycle &&

!tp->rx_opt.ts_recent_stamp && fl4->daddr ==daddr)

tcp_fetch_timewait_stamp(sk,&rt->dst);

inet->inet_dport = usin->sin_port;

sk_daddr_set(sk, daddr);

inet_csk(sk)->icsk_ext_hdr_len = 0;if(inet_opt)

inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;

tp->rx_opt.mss_clamp =TCP_MSS_DEFAULT;/*Socket identity is still unknown (sport may be zero).

* However we set state to SYN-SENT and not releasing socket

* lock select source port, enter ourselves into the hash tables and

* complete initialization after this.*/

/*将TCP设置为SYN_SENT,动态绑定一个本地端口,并将传输控制块添加到ehash散列表中。由于在动态分配端口时,如果找到的是已使用的端口,则

* 需在TIME_WAIT状态中进行相应的确认,因此调用inet_hash_connect()时需用timewait传输控制块和参数管理器tcp_death_row作为参数。*/tcp_set_state(sk, TCP_SYN_SENT);//bind local port,tw_recycle

/*/没有bind端口,随机生成一个偏移,随机化端口分配过程*/err= inet_hash_connect(&tcp_death_row, sk);if(err)gotofailure;

sk_set_txhash(sk);

rt=ip_route_newports(fl4, rt, orig_sport, orig_dport,

inet->inet_sport, inet->inet_dport, sk);if(IS_ERR(rt)) {

err=PTR_ERR(rt);

rt=NULL;gotofailure;

}/*OK, now commit destination to socket.*/sk->sk_gso_type =SKB_GSO_TCPV4;

sk_setup_caps(sk,&rt->dst);/** 如果write_seq字段值为零,则说明该传输控制块还

* 未设置初始序号,因此需调用secure_tcp_sequence_number(),

* 根据双方的地址、端口计算初始序列号,同时根据

* 发送需要和当前时间得到用于设置IP首部ID域的值。*/

if (!tp->write_seq && likely(!tp->repair))

tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,

inet->inet_daddr,

inet->inet_sport,

usin->sin_port);

inet->inet_id = tp->write_seq ^jiffies;

err=tcp_connect(sk);

rt=NULL;if(err)gotofailure;return 0;

failure:/** This unhashes the socket and releases the local port,

* if necessary.*/tcp_set_state(sk, TCP_CLOSE);

ip_rt_put(rt);

sk->sk_route_caps = 0;

inet->inet_dport = 0;returnerr;

}

EXPORT_SYMBOL(tcp_v4_connect);

### 回答1: tcp_max_syn_backlog 是一个 TCP 协议的参数,用于控制 TCP SYN 连接请求的最大队列长度。当有大量的客户端同时向服务器发起连接请求时,服务器可能会出现 SYN 队列溢出的情况,导致客户端连接失败。通过调整 tcp_max_syn_backlog 参数,可以增加 TCP SYN 队列的最大长度,从而提高服务器的连接请求处理能力。 在 Linux 系统中,tcp_max_syn_backlog 默认值为 1024。可以通过修改 /proc/sys/net/ipv4/tcp_max_syn_backlog 文件来调整该参数的值。但需要注意的是,过大的 tcp_max_syn_backlog 值会占用过多的系统资源,从而影响系统的性能现。 ### 回答2: tcp_max_syn_backlog是TCP协议中一个参数,用于控制SYN队列的最大长度。SYN队列存储了正在与服务器建立连接的客户端请求,当服务器接收到客户端SYN请求时,会将其放入SYN队列中。tcp_max_syn_backlog参数的作用就是控制SYN队列的最大长度,当SYN队列已满时,服务器将无法接受新的连接请求。 如果tcp_max_syn_backlog值设置过小,当服务器接收到大量的客户端连接请求时,有可能会导致SYN队列溢出,从而导致新的连接请求被丢弃,客户端无法与服务器建立连接。在高并发的网络环境下,适当增大tcp_max_syn_backlog值可以提高服务器的处理能力,减少客户端连接丢失的概率。 然而,设置过大的tcp_max_syn_backlog值也会有一些问题。首先,SYN队列的长度是有限的,如果设置过大,会占用服务器的内存资源。其次,如果服务器无法及时处理SYN队列中的请求,会造成客户端连接的延迟增加。 因此,在调整tcp_max_syn_backlog值时,需要根据服务器的实际情况进行综合考虑。一般来说,如果服务器处于高并发的环境中,可以适当增大tcp_max_syn_backlog值。而对于低并发的场景,则可以适当减小tcp_max_syn_backlog值,以节省服务器资源。为了保证服务器的稳定性和性能,在调整tcp_max_syn_backlog值时,还需要结合服务器的硬件配置、网络带宽以及预计的连接请求负载等因素进行综合评估和测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值