int clientSocket;
if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
// 創建socket失敗失敗
return -1;
}
.
if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
// connect 失敗
return -1;
}
..
https://my.oschina.net/alchemystar/blog/1791017
sock_map_fd
|->get_unused_fd_flags
|->alloc_fd
|->expand_files (ulimit)
|->sock_alloc_file
|->alloc_file
|->get_empty_filp (/proc/sys/fs/max_files)
int expand_files(struct files_struct *files, int nr
{
.
if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
return -EMFILE;
.
}
struct file *get_empty_filp(void)
{
.
/*
* 由此可見,特權用戶可以無視文件數最大大小的限制!
*/
if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) {
/*
* percpu_counters are inaccurate. Do an expensive check before
* we go and fail.
*/
if (percpu_counter_sum_positive(&nr_files) >= files_stat.max_files)
goto over;
}
.
}
int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen)
SYSCALL_DEFINE3(connect, .
socket.c
SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
int, addrlen)
{
.
err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
sock->file->f_flags);
.
}
SYSCALL_DEFINE3(connect
|->inet_stream_ops
|->inet_stream_connect
|->tcp_v4_connect
|->tcp_set_state(sk, TCP_SYN_SENT);設置狀態為TCP_SYN_SENT
|->inet_hash_connect
|->tcp_connect
void inet_get_local_port_range(int *low, int *high)
{
unsigned int seq;
do {
// 順序鎖
seq = read_seqbegin(&sysctl_local_ports.lock);
*low = sysctl_local_ports.range[0];
*high = sysctl_local_ports.range[1];
} while (read_seqretry(&sysctl_local_ports.lock, seq));
}
cat /proc/sys/net/ipv4/ip_local_port_range
32768 61000
int __inet_hash_connect(...)
{
// 注意,這邊是static變量
static u32 hint;
// 這邊的port_offset是用對端ip:port hash的一個值
// 也就是說對端ip:port固定,port_offset固定
u32 offset = hint + port_offset;
for (i = 1; i <= remaining; i++) {
port = low + (i + offset) % remaining;
/* port是否佔用check */
....
goto ok;
}
..
ok:
hint += i;
.
}
C語言connect返回錯誤碼為
-EADDRNOTAVAIL,對應描述為Cannot assign requested address
對應Java的異常為
java.net.NoRouteToHostException: Cannot assign requested address (Address not available)
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
__inet_hash_connect
|->__inet_check_established
static int __inet_check_established(.)
{
.
/* Check TIME-WAIT sockets first. */
sk_nulls_for_each(sk2, node, &head->twchain) {
tw = inet_twsk(sk2);
// 如果在time_wait中找到一個match的port,就判斷是否可重用
if (INET_TW_MATCH(sk2, net, hash, acookie,
saddr, daddr, ports, dif)) {
if (twsk_unique(sk, sk2, twp))
goto unique;
else
goto not_unique;
}
}
.
}
int tcp_twsk_unique(.)
{
.
if (tcptw->tw_ts_recent_stamp &&
(twp == NULL || (sysctl_tcp_tw_reuse &&
get_seconds() - tcptw->tw_ts_recent_stamp > 1))) {
tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2
.
return 1;
}
return 0;
}
echo '1' > /proc/sys/net/ipv4/tcp_tw_reuse
/* And established part... */
sk_nulls_for_each(sk2, node, &head->chain) {
if (INET_MATCH(sk2, net, hash, acookie,
saddr, daddr, ports, dif))
goto not_unique;
}
__inet_hash_connect(.)
{
.
if (tw) {
inet_twsk_deschedule(tw, death_row);
inet_twsk_put(tw);
}
.
}
ip_route_newports
|->ip_route_output_flow
|->__ip_route_output_key
|->ip_route_output_slow
|->fib_lookup
-ENETUNREACH,對應描述為Network is unreachable
tcp_connect
|->tcp_connect_init 初始化tcp socket
|->tcp_transmit_skb 發送SYN包
|->inet_csk_reset_xmit_timer 設置SYN重傳定時器
tcp_connect_init
|->tcp_select_initial_window
int tcp_select_initial_window(...)
{
.
(*rcv_wscale) = 0;
if (wscale_ok) {
/* Set window scaling on max possible window
* See RFC1323 for an explanation of the limit to 14
*/
space = max_t(u32, sysctl_tcp_rmem[2], sysctl_rmem_max);
space = min_t(u32, space, *window_clamp);
while (space > 65535 && (*rcv_wscale) < 14) {
space >>= 1;
(*rcv_wscale)++;
}
}
.
}
/proc/sys/net/ipv4/tcp_syn_retries
int __inet_stream_connect(struct socket *sock,...,)
{
// 如果設置了O_NONBLOCK則timeo為0
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
.
// 如果timeo=0即O_NONBLOCK會立刻返回
// 否則等待timeo時間
if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))
goto out;
}
tcp_v4_rcv
|->tcp_v4_do_rcv
|->tcp_rcv_state_process
|->tcp_rcv_synsent_state_process
|->tcp_finish_connect
|->tcp_init_metrics 初始化度量統計
|->tcp_init_congestion_control 初始化擁塞控制
|->tcp_init_buffer_space 初始化buffer空間
|->inet_csk_reset_keepalive_timer 開啟包活定時器
|->sk_state_change(sock_def_wakeup) 喚醒用戶態進程
|->tcp_send_ack 發送三次握手的最後一次握手給Server端
|->tcp_set_state(sk, TCP_ESTABLISHED) 設置為ESTABLISHED狀態
覺得不錯,請點個在看呀