Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304044
  • 博文数量: 35
  • 博客积分: 836
  • 博客等级: 准尉
  • 技术积分: 678
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-07 20:11
文章分类

全部博文(35)

文章存档

2013年(1)

2012年(24)

2011年(10)

分类: LINUX

2012-03-10 02:14:11

在之前的博客中记录了在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)

点击(此处)折叠或打开

  1. int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
  2.          size_t size)
  3. {
  4.     struct sock *sk = sock->sk;

  5.     sock_rps_record_flow(sk);

  6.     /* We may need to bind the socket. */
  7.     if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
  8.      inet_autobind(sk))
  9.         return -EAGAIN;

  10.     return sk->sk_prot->sendmsg(iocb, sk, msg, size);
  11. }
很简单的一段代码,完成一个接口功能,根据具体的(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)

点击(此处)折叠或打开

  1. static int unix_create(struct net *net, struct socket *sock, int protocol,
  2.          int kern)
  3. {
  4.     if (protocol && protocol != PF_UNIX)
  5.         return -EPROTONOSUPPORT;

  6.     sock->state = SS_UNCONNECTED;

  7.     switch (sock->type) {
  8.     case SOCK_STREAM:
  9.         sock->ops = &unix_stream_ops;
  10.         break;
  11.         /*
  12.          *    Believe it or not BSD has AF_UNIX, SOCK_RAW though
  13.          *    nothing uses it.
  14.          */
  15.     case SOCK_RAW:
  16.         sock->type = SOCK_DGRAM;
  17.     case SOCK_DGRAM:
  18.         sock->ops = &unix_dgram_ops;
  19.         break;
  20.     case SOCK_SEQPACKET:
  21.         sock->ops = &unix_seqpacket_ops;
  22.         break;
  23.     default:
  24.         return -ESOCKTNOSUPPORT;
  25.     }

  26.     return unix_create1(net, sock) ? 0 : -ENOMEM;
  27. }
通过以上的代码就能很清晰的看到在创建AF_UNIX不同类型的sokcet的时候,为其就绑定了不同的服务类型。比如SOCK_STREAM时unix_stream_ops中的sendmsg就是unix_stream_sendmsg而SOCK_DGRAM时unix_dgram_ops中的sendmsg则是unix_dgram_sendmsg。两者在绑定的时候已经使用了不同的接口,就无需像AF_INET一样又多抽象了一层。

不管采用何种方式,最后实现的结果就是:对于用户来说,使用统一的接口能够对不同类型的协议栈进行无差别访问。
阅读(3145) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~