linux 伺服器端listen 函式使用分析

2021-12-30 10:31:21 字數 2695 閱讀 1590

功能:監聽來自客戶端的tcp socket的連線請求

listen函式在一般在呼叫bind之後-呼叫accept之前呼叫,它的函式原型是:

#include

int listen(int sockfd, int backlog)

引數sockfd是被listen函式作用的套接字,引數backlog是偵聽佇列的長度。在程序正在處理乙個連線請求的時候,可能還存在其它的連線請求。因為tcp連線是乙個過程,所以可能存在一種半連線的狀態,有時由於同時嘗試連線的使用者過多,使得伺服器程序無法快速地完成連線請求。如果這個情況出現了,伺服器程序希望核心如何處理呢?核心會在自己的程序空間裡維護乙個佇列以跟蹤這些完成的連線但伺服器程序還沒有接手處理的連線(還沒有呼叫accept函式的連線),這樣的乙個佇列核心不可能讓其任意大,所以必須有乙個大小的上限。這個backlog告訴核心使用這個數值作為上限。

返回值

成功 失敗

是否設定errno

是 錯誤資訊:

eaddrinuse:另乙個socket也在監聽同乙個埠。

ebadf:引數sockfd為非法的檔案描述符。

enotsock:引數sockfd不是檔案描述符。

eopnotsupp:套接字型別不支援listen操作。

syscall_define2(listen, int, fd, int, backlog)

return err;

}該函式內部最關鍵的部分如下

err = sock->ops->listen(sock, backlog); //對應結構體inet_stream_ops中的成員 inet_listen()/*

* move a socket into listening state.

*/int inet_listen(struct socket *sock, int backlog)

err = inet_csk_listen_start(sk, backlog);

if (err)

goto out;

} // 4 設定sock的最大併發連線請求數

sk->sk_max_ack_backlog = backlog;

err = 0;

out:

release_sock(sk);

return err;

}export_symbol(inet_listen);

在該函式內部主要完成如下部分

a. 初始化listen監聽客戶端的佇列個數及空間

err = fastopen_init_queue(sk, backlog);static inline int fastopen_init_queue(struct sock *sk, int backlog)

queue->fastopenq->max_qlen = backlog; //監聽的客戶端個數

return 0;

}b. socket listen()狀態啟動

err = inet_csk_listen_start(sk, backlog);int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)

sk->sk_state = tcp_close;

__reqsk_queue_destroy(&icsk->icsk_accept_queue);

return -eaddrinuse;

}export_symbol_gpl(inet_csk_listen_start);

在該函式內部主要完成如下部分

b.1初始化連線等待佇列,icsk->icsk_accept_queue表示當前listen監聽的併發個數記憶體空間

int rc = reqsk_queue_alloc(&icsk->icsk_accept_queue, nr_table_entries);int reqsk_queue_alloc(struct request_sock_queue *queue,

unsigned int nr_table_entries)

b.2 獲取伺服器(本地)的埠

if (!sk->sk_prot->get_port(sk, inet->inet_num))

}export_symbol_gpl(inet_hash);

static void __inet_hash(struct sock *sk)

warn_on(!sk_unhashed(sk));

/*根據監聽的埠號,查詢相對應的listen hash*/

ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];

spin_lock(&ilb->lock);

/*把sock新增到監聽hash桶的頭部,連線到sk->sk_nulls_node */

__sk_nulls_add_node_rcu(sk, &ilb->head);

sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);

spin_unlock(&ilb->lock);

}關於該函式內部的鍊錶關係見下流程圖

其實listen函式內部只是純粹的將埠新增道hash鍊錶上,並沒有啟動監聽客戶端的連線,關於連線其實是在accept函式內部。

socket伺服器端

伺服器 include winsock2.h include string.h include stdio.h include time.h include stdarg.h include stdlib.h pragma comment lib,ws2 32 void errexit const ...

kerberos伺服器端

1.安裝tcl wget tar zvxf tcl8.5.12 src.tar.gz cd tcl8.5.12 cd unix configure make make install 3.解壓 tar xvf krb5 1.10.3 signed.tar tar zvxf krb5 1.10.3.t...

C tcp伺服器端

伺服器端 include stdafx.h include winsock2.h pragma comment lib,ws2 32.lib include using namespace std int tmain int argc,char ar 建立套接字 sserver socket af ...