实现将系统中所有状态的tcp打印出来,代码如下:
char* GetConnState(unsigned char state)
{
char* p = "";
switch (state)
{
case TCP_ESTABLISHED:
p = "TCP_ESTABLISHED";
break;
case TCP_LISTEN:
p = "TCP_LISTEN";
break;
case TCP_SYN_SENT:
p = "TCP_SYN_SENT";
break;
case TCP_CLOSE:
p = "TCP_CLOSE";
break;
case TCP_SYN_RECV:
p = "TCP_SYN_RECV";
break;
case TCP_LAST_ACK:
p = "TCP_LAST_ACK";
break;
case TCP_CLOSING:
p = "TCP_CLOSING";
break;
case TCP_NEW_SYN_RECV:
p = "TCP_NEW_SYN_RECV";
break;
case TCP_TIME_WAIT:
p = "TCP_TIME_WAIT";
break;
}
return p;
}
static int hello_open(struct inode* inode, struct file*filep)
{
struct task_struct *tsk = current;
struct inet_bind_hashbucket *head;
int i;
struct inet_bind_bucket *tb;
struct sock* sk;
// 获取hinfo方法1
//struct inet_hashinfo *hinfo = tcp_prot.h.hashinfo;
// 获取hinfo方法2
struct net *net = tsk->nsproxy->net_ns;
struct inet_timewait_death_row *tcp_death_row = &net->ipv4.tcp_death_row;
struct inet_hashinfo *hinfo = tcp_death_row->hashinfo;
// 获取hinfo方法3,如果函数有struct sock类型的入参时,可使用此方法。
// sk->sk_prot实际为tcp_prot
//struct inet_hashinfo *hinfo = sk->sk_prot->h.hashinfo;
// 32768
printk("inet_hashinfo.bhash_size = %d\n", hinfo->bhash_size);
// 获取head方法1,判断本地某个端口是否被占用时可使用此方法
//head = &hinfo->bhash[inet_bhashfn(net, port,
// hinfo->bhash_size)];
for (i = 0; i < hinfo->bhash_size; ++i)
{
// 获取head方法2,因为要获取所有的tcp,所以用此方法
head = &hinfo->bhash[i];
spin_lock_bh(&head->lock);
inet_bind_bucket_for_each(tb, &head->chain) {
printk("port = %d\n", tb->port);
sk_for_each_bound(sk, &tb->owners) {
printk("saddr = %x\n", sk->sk_rcv_saddr);
printk("daddr = %x\n", sk->sk_daddr);
printk("sk_dport = %d\n", ntohs(sk->sk_dport)); // 转为主机序
// 状态
printk("sk_state = %s\n", GetConnState(sk->sk_state));
}
printk("\n");
}
spin_unlock_bh(&head->lock);
}
return 0;
}
// 用netstat查看的网络连接
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 关闭 (0.00/0/0)
tcp 0 0 192.168.0.106:22 192.168.0.109:55859 ESTABLISHED 保持连接 (6040.63/0/0)
tcp6 0 0 :::22 :::* LISTEN 关闭 (0.00/0/0)
// 内核打印的日志
[14221.754364] inet_hashinfo.bhash_size = 32768
[14221.754531] port = 22
[14221.754532] saddr = 6a00a8c0
[14221.754533] daddr = 6d00a8c0
[14221.754533] sk_dport = 55859
[14221.754534] sk_state = TCP_ESTABLISHED
[14221.754535] saddr = 0
[14221.754535] daddr = 0
[14221.754536] sk_dport = 0
[14221.754537] sk_state = TCP_LISTEN
[14221.754537] saddr = 0
[14221.754538] daddr = 0
[14221.754538] sk_dport = 0
[14221.754539] sk_state = TCP_LISTEN
弄懂了上面的代码,可有助于理解内核中新建tcp连接时,获取本地端口部分的逻辑。