Linux網路程式設計之connect建立

2021-08-15 00:11:14 字數 3340 閱讀 9207

在說connect呼叫之前,先簡單看下

kernel\net\socket.c

syscall_define3(connect, int, fd, struct sockaddr __user *, uservaddr,

int, addrlen)

繼續分析

inet_stream_ops函式

kernel\net\ipv4\af_inet.c

const struct proto_ops inet_stream_ops =
inet_stream_connect

__inet_stream_connect(sock, uaddr, addr_len, flags);

switch (sock->state)

sock->state =

ss_connected;

針對我們目前的tcp協議而言,這裡的sk->sk_prot指向是tcp_prot,所以其connect函式就是

tcp_v4_connect

struct proto tcp_prot =

對於 tcp 協議來說,其連線實際上就是傳送乙個 syn 報文,在伺服器的應答到來時,回答它一

個 ack 報文,也就是完成三次握手中的第一和第三次。 

態提交,但是問題是沒有自己的位址和埠,因為並沒有呼叫過 bind(2),一台主機,對於埠,

可以像 sys_bind()那樣,從本地未用埠中動態分配乙個,那位址呢?因為一台主機可能會存在多

個 ip位址,如果隨機動態選擇,那麼有可能選擇乙個錯誤的**位址,將不能正確地到達目的地

址。換句話說,**位址的選擇,是與路由相關的。 

呼叫路由查詢的核心函式 ip_route_output_flow(),在沒有提供**位址的情況下,會根據實際情況,

呼叫 inet_select_addr()函式來選擇乙個合適的。同時,如果路由查詢命中,會生成乙個相應的路由

快取項,這個快取項,不但對當前傳送syn報文有意義,對於後續的所有資料報,都可以起到一

個加速路由查詢的作用。這一任務,是通過 ip_route_connect()函式完成的,它返回相應的路由快取

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

orig_sport = inet->inet_sport;

//使用者設定的目的ip的埠

orig_dport = usin->sin_port;

fl4 = &inet->cork.fl.u.ip4;

inet->inet_saddr這個引數同樣為0,也就是說當前源位址和源埠都是為0的

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, true);

if (rt->rt_flags & (rtcf_multicast | rtcf_broadcast))

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

daddr = fl4->daddr;

if (!inet->inet_saddr)

inet->inet_saddr = fl4->saddr;

inet->inet_rcv_saddr = inet->inet_saddr;

if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr)

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;

inet->inet_daddr = 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_set_state(sk, tcp_syn_sent);

err = inet_hash_connect(&tcp_death_row, sk);

if (err)

goto failure;

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

inet->inet_sport, inet->inet_dport, sk);

if (is_err(rt))

/* ok, now commit destination to socket. */

sk->sk_gso_type = skb_gso_tcpv4;

sk_setup_caps(sk, &rt->dst);

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)

goto failure;

return 0;

}

Linux網路程式設計之廣播

1.概念 前面介紹的tcp,udp都是單播方式,即一對一.而廣播是一台主機向區域網內的所有主機傳送資料。這時,同一網段的所有主機都能接收到資料。傳送廣播包的步驟大致如下 1 確定乙個傳送廣播的介面,如eth0 2 確定廣播的位址,通過ioctl函式,請求碼設定為siocgifbrdaddr得到廣播的...

Linux網路程式設計之廣播

1.概念 前面介紹的tcp,udp都是單播方式,即一對一.而廣播是一台主機向區域網內的所有主機傳送資料。這時,同一網段的所有主機都能接收到資料。傳送廣播包的步驟大致如下 1 確定乙個傳送廣播的介面,如eth0 2 確定廣播的位址,通過ioctl函式,請求碼設定為siocgifbrdaddr得到廣播的...

linux網路程式設計之Socket

一.socket socket可看作是使用者程序與核心網路協議的程式設計介面.socket可用於本機程序間的通訊,也可用於網路上不同主機間的程序通訊.下圖顯示的是各種網路協議的位址格式 1.struct socketaddr 通用位址結構 通過獲取某種socketaddr結構體的首位址,不需要知道具...