在說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結構體的首位址,不需要知道具...