在之前的博客中记录了在Linux文件系统的结构中,socket是怎样与VFS连接起来,并且socket是怎样将各种不同协议族的网络传输协议使用统一的接口。
之前仅仅是大体介绍了一下框架上的东西,在涉及到具体的协议族时,比如我们常用的TCP/IP协议或者是AF_UNIX协议族时,具体的实现方式是不同的。
在TCP/IP与AF_UNIX两种协议中,均支持SOCK_STREAM和SOCK_DGRAM。但是两者在与socket链接的方式上却是不太一样。在AF_INET协议的实现过程中,由于有多种协议需要支持,如TCP协议,UDP协议等等。实现者在这层又抽象出了一层作为INET的统一接口,然后TCP和UDP各自分别实现struct proto中定义的接口以完成相应的操作。而在AF_UNIX的实现方法则是在创建socket的过程中,直接根据不同的SOCK类型将不同的struct proto_ops绑定到对应的socket上,省去了中间又抽象出来的一层。
两者选用的不同的方法同样完成了面向对象中多态的效果。
说了那么多看段代码最清楚了,比如AF_INET的socket中proto_ops中的sendmsg定义,UDP与TCP均使用inet_sendmsg作为自己的接口:inet_sendmsg的代码如下(net/ipv4/af_inet.c)
- int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
- size_t size)
- {
- struct sock *sk = sock->sk;
- sock_rps_record_flow(sk);
- /* We may need to bind the socket. */
- if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
- inet_autobind(sk))
- return -EAGAIN;
- return sk->sk_prot->sendmsg(iocb, sk, msg, size);
- }
很简单的一段代码,完成一个接口功能,根据具体的(sk_prot)协议来完成特定的sendmsg操作。struct sock中sk_prot在创建socket时绑定到特定的协议如TCP或者UDP。由此也就能够大概看到Linux中TCP/IP协议栈通过一层一层的抽象,使得各个协议之间相互解耦,又能够保持同样的接口。
看了AF_INET的实现过程,在看看AF_UNIX的实现过程,来个对比,就会更加明显。看一个创建AF_UNIX的socket时所调用的函数(net/unix/af_unix.c)
- static int unix_create(struct net *net, struct socket *sock, int protocol,
- int kern)
- {
- if (protocol && protocol != PF_UNIX)
- return -EPROTONOSUPPORT;
- sock->state = SS_UNCONNECTED;
- switch (sock->type) {
- case SOCK_STREAM:
- sock->ops = &unix_stream_ops;
- break;
- /*
- * Believe it or not BSD has AF_UNIX, SOCK_RAW though
- * nothing uses it.
- */
- case SOCK_RAW:
- sock->type = SOCK_DGRAM;
- case SOCK_DGRAM:
- sock->ops = &unix_dgram_ops;
- break;
- case SOCK_SEQPACKET:
- sock->ops = &unix_seqpacket_ops;
- break;
- default:
- return -ESOCKTNOSUPPORT;
- }
- return unix_create1(net, sock) ? 0 : -ENOMEM;
- }
通过以上的代码就能很清晰的看到在创建AF_UNIX不同类型的sokcet的时候,为其就绑定了不同的服务类型。比如SOCK_STREAM时unix_stream_ops中的sendmsg就是unix_stream_sendmsg而SOCK_DGRAM时unix_dgram_ops中的sendmsg则是unix_dgram_sendmsg。两者在绑定的时候已经使用了不同的接口,就无需像AF_INET一样又多抽象了一层。
不管采用何种方式,最后实现的结果就是:对于用户来说,使用统一的接口能够对不同类型的协议栈进行无差别访问。
阅读(3140) | 评论(0) | 转发(0) |