百度空间 | 百度首页 
 
文章列表
 
您正在查看 "socket及其编程" 分类下的文章

2007年03月07日 星期三 上午 07:50

       首先以socket和send两个系统调用为例,来回顾一下协议栈是如何工作的,在这过程中可以找到如何在协议栈中增加对UDP协议的支持。socket系统调用的原型是
       int socket(int domain, int type, int protocol);
domain是协议域,对于ipv4协议来说,其值是PF_INET(ipv4因特网协议),对于我们自己实现的ipv4协议模块,我们为其新增MY_PF_INET。所有的协议域在include/linux/socket.h被定义,如下:
#

类别:socket及其编程 | 评论(7) | 浏览()
 
2006年11月25日 星期六 上午 08:16
    前面讲到,在数组inetsw_array中有INET域支持的全部套接字类型和协议类型,在一个结构体struct inet_protosw中,记录了一个套接字类型,该类型下的一种协议类型,以及该类型套接字的操作集和该类型协议的操作集,对于原始套接字,其协议类型为通配类型,通配所有网络层附属协议,其协议操作集为所有网络层附属协议的通过协议操作集,即struct proto raw_prot。在INET域进行初始化的时候,其要做的第一件事情就是通过函数proto_register注册协议操作集。
    struct proto的成员slab是一个后备高速缓冲区,所有该类型下的网络层套接字struct sock都是从该后备高速缓冲区分配内存,struct proto的成员obj_size记录的是单个网络层套接字的空间大小,供分配slab时使用,其值是sizeof(struct raw_sock),raw_sock是对inet_sock的一个扩充(inet_sock是对sock的扩充)。在inet_create创建套接字的时候,调用sk_alloc创建struct sock,该函数直接从slab中分配内存。proto_register要做的第一件事情就是创建slab,struct proto还有成员rsk_prot和twsk_prot需要分配内存,也要在proto_register函数中完成,它是TCP协议相关的,暂时不关注。
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年11月24日 星期五 下午 07:04
    变量inetsw_array是inet域的一个全局数组,其类型是struct inet_protosw,该结构体的定义如下:
    struct inet_protosw {
        struct list_head    list;
        unsigned short      type;
        int                 protocol;
        struct proto        *prot;
        const struct proto_ops *ops;
        int              capability;
        char             no_check;
   
类别:socket及其编程 | 评论(2) | 浏览()
 
2006年08月11日 星期五 下午 02:37
  一般,用户在shell中使用ifconfig命令对网络接口进行参数配置,及接口的打开,关闭等操作。ifconfig实现网络接口配置的原理在于代表网络接口的结构体struct net_device的成员ip_ptr。前文已经讲过,ip_ptr实际指向的是一个结构体struct in_device,in_device有一个成员struct in_ifaddr *ifa_list,它指向一个链表,链表的每一项代表一个IP地址。对这个链表操作即可实现对网络接口的配置。
    网络接口的操作命令按功能可以分为两组,第一组为查询命令:SIOCGIFADDR,SIOCGIFBRDADDR,SIOCGIFDSTADDR, SIOCGIFNETMASK。分别用于查询网络接口的IP地址,广播地址,目的地址,子网掩码。第二组为设置命令:SIOCSIFADDR, SIOCSIFFLAGS,SIOCSIFBRDADDR,SIOCSIFNETMASK,SIOCSIFDSTADDR。分别用于设置网络接口的IP地址,标志位,广播地址,子网掩码,目的地址。这些命令所要查询和设置的信息全部在结构体struct in_ifaddr中。
    用户空间的应用程序通过系统调用ioctl使用这些命令,ioctl的函数原型如下:
        #include <sys/ioctl.h>
    
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:26
   套接字写有多个实现接口,我们只以其中一个接口write为线索,对套接字写(网络数据发送)的流程进行分析。系统调用write会调用内核函数sys_write,sys_write调用vfs_write完成实际的写操作。
    vfs_write会先调用file->f_op->write(file从套接字描述符获得)。如果file->f_op-> write不存在,则调用do_sync_write。该函数会调用sock_aio_write,sock_aio_write又会调用 __sock_sendmsg,然后到myinet_sendmsg,最后才到sk->sk_prot->sendmsg,对于RAW协议来讲,即myraw_sendmsg。
    sock_aio_write的函数原型如下:
        static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
                      size_t size, loff_t pos)
ubuf是用户待发送数据,size是数据长度,pos是文件位置(永远为零)。在这个函数里,会把用户待发送数据封装成一个struct msghdr结构:
    
类别:socket及其编程 | 评论(3) | 浏览()
 
2006年08月11日 星期五 下午 02:26
    继续讲关于myraw_setsockopt的实现,如果level是SOL_IP,则调用myip_setsockopt函数。 myip_setsockopt的操作对像是struct socket sock的成员struct sock sk。并把sk强制转化为struct inet_sock: inet = inet_sk(sk)。
    如果option_name在MRT_BASE和MRT_BASE+10之间,则调用myip_mroute_setsockopt函数,关于mroute,后面再给出分析。
    IP_OPTIONS:设置将由该套接字发送的每个包的IP选项。
    其option_value是一个结构体struct ip_options。该选项首先分配一个这样的结构体,然后用这个结构体替代inet->opt指向的结构体。如果协议类型是 SOCK_STREAM的话,从struct tcp_sock *tp中,tp->ext_header_len减去旧的inet->opt->optlen, 再加上新的opt->optlen。最后调用tcp_sync_mss进行同步,有关TCP的一些细节,我们在实现TCP协议时再分析。
    IP_PKTINFO:传递一条包含pktinfo结构(该结构提供一些来访包的相关信息)的IP_PKTINFO辅助信息。
    这个选项只对数据报类的套接字有效。
    struct in_pkt
类别:socket及其编程 | 评论(46) | 浏览()
 
2006年08月11日 星期五 下午 02:25
    如果不在套接字级别上设置选项,即setsockopt系统调用的参数level不设为SOL_SOCKET,那么sys_setsockopt的实现会直接调用sock->ops->setsockopt。对MY_PF_INET域的RAW协议来讲,sock->ops = myinet_sockraw_ops,而myinet_sockraw_ops.setsockopt = sock_common_setsockopt。
    而sock_common_setsockopt直接调用sock->sk->sk_prot->setsockopt。对于RAW协议来讲,即myraw_setsockopt。
    下面关注myraw_setsockopt的实现。对于RAW协议来讲,level还可以有两种取值:SOL_IP和SOL_RAW。 myraw_setsockopt首先检查level是否为SOL_IP,如果是,调用myip_setsockopt函数,该函数实现IP级别上的选项,否则,为SOL_RAW级别上的选项,SOL_RAW级别上只有一个选项,即ICMP_FILTER,在MY_IPPROTO_ICMP协议下有效。它激活绑定到MY_IPPROTO_ICMP协议的一个用于myraw socket特殊的过滤器。该值对每种ICMP消息都有一个位(掩码),可以把那种ICMP消息过滤掉,缺省时是不过滤ICMP消息。
    对于ICMP_FILTER选项,myraw_setsockopt调用myraw_seticmpfilter函数,它把option_value赋
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:24
    (接上文)
    SO_KEEPALIVE,套接字保活。
    如果协议是TCP,并且当前的套接字状态不是侦听(listen)或关闭(close),那么,当option_value不是零时,启用TCP保活定时器,否则关闭保活定时器。对于所有协议,该操作都会根据option_value置或清sock->sk->sk_flag中的 SOCK_KEEPOPEN位。
    SO_OOBINLINE,紧急数据放入普通数据流。
    该操作根据option_value的值置或清sock->sk->sk_flag中的SOCK_URGINLINE位。
    SO_NO_CHECK,打开或关闭校验和。
    该操作根据option_value的值,设置sock->sk->sk_no_check。
    SO_PRIORITY,设置在套接字发送的所有包的协议定义优先权。Linux通过这一值来排列网络队列。
    这个值在0到6之间(包括0和6),由option_value指定。赋给sock->sk->sk_priority。
    SO_LINGER,如果选择此选项, close或 shutdown将等到所有套接字里排队的消息成功发送或到达延迟时间后>才会返回. 否则, 调用
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:24
    套接字选项这个话题在socket编程里,可能已经属于中高级话题了,之所以在一开始就把这个话题提上来讲,是因为我们的一个近阶段目标是能够把 MY_PF_INET域的RAW协议走通,并在上面跑起一个ping程序,所以,按照ping程序的要求,接下来,我们必须实现套接字选项系统调用 setsockopt在MY_PF_INET中RAW协议中的相关实现。
    下面是该系统调用函数的原型:
    #include <sys/socket.h>
    int setsockopt( int socket, int level, int option_name,
                        const void *option_value, size_t option_len);
    第一个参数socket是套接字描述符。第二个参数level是被设置的选项的级别,如果想要在套接字级别上设置选项,就必须把level设置为 SOL_SOCKET。option_name指定准备设置的选项,option_name可以有哪些取值,这取决于level,以linux 2.6内核为例(在不同的平台上,这种关系可能会有不同),在套接字级别上(SO
类别:socket及其编程 | 评论(1) | 浏览()
 
2006年08月11日 星期五 下午 02:23
    我们先来简单看一下系统调用close(int fd)的流程。该系统调用会调用到内核中的函数:
        asmlinkage long sys_close(unsigned int fd)
参数fd给我们一个很好的线索,我们可以很方便地找到相应的struct file结构:file = current->files->fd[fd]。取出了这个至关重要的数据结构后,我们归还fd给系统,同时,设current-> file->fd[fd]=NULL。使我们创建的socket完全跟系统和进程分离。最后再销毁struct file结构。
    销毁struct file的很多细节我们不关注,但在某一步,一个叫__fput(struct file *file)的函数中,有这样一个调用:
        file->f_op->release(inode, file);
它实际调用到了sock_close函数,该函数又会调用到sock_release函数。sock_release函数又调用我们my_inet模块提供的myinet_release函数完成实际的socket销毁工作,同时,释放inode。
    上面讲述的是一个大致的流程,我们重点关注的还是如何在我们的my_inet模块中实现套接字的销毁。下面先看一下myinet_release函
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:22
   要使我们的工作得以顺利进行,我们必须把建立与销毁,注册与注销等配对的工作放在一起完成,才能使模块始终处于一个可使用的状态。所以,完成了套接字的创建,我们下一步紧接着面临的工作就是套接字的销毁。
    在系统调用层,套接字也是一个文件描述符来表示,所以,关闭套接字跟关闭打开着的文件并没有区别,都是使用close(fd),但同样一个操作,在内核中却发生着很不一样的操作。
    我们还需要从socket系统调用创建套接字讲起,当代表套接字的一个struct socket结构被完整创建出来以后,它被映射到一个文件描述符,并且系统把这个文件描述符返回给用户。现在,我们就需要简单了解这个映射过程是怎么样的。
    因为我们的目标是重新建立一个INET域的代码,所以不想在关于文件系统的方面走太远,所以只进行简单介绍。我们首先要从系统获取一个未使用的文件描述符,并创建一个struct file结构。同时,我们初始化这个struct file结构,整个初始化过程我们只需要关注其中两步:
            sock->file = file;
 
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:22
    我们已经完成了MY_PF_INET域的初始化,虽然留了很多空,但我们至少已经具备了:TCP, UDP, RAW三种协议;TCP, UDP, ICMP, IGMP四种基本协议;inetsw数组。有了这些,我们可以尝试着创建一个套接字试试。
    关于套接字创建的执行流程,前文已有描述,其最终会进入我们的family中的创建函数:
            static int myinet_create(struct socket *sock, int protocol);
套接字类型已经包含在sock结构中。MY_PF_INET域中有效的类型是SOCK_STREAM, SOCK_DGRAM和SOCK_RAW。据此,我们定位到inetsw数组的某一项(一个链表的链表头),然后在这个链表中匹配protocol。
    MY_PF_INET域中的常用的protocol是:IPPROTO_IP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_TCP, IPPROTO_UDP。其中IPPROTO_IP比较特殊,是一个通配符。链表中的protocol匹配可以是严格匹配,也可以是通配符匹配,但最终 protocol必须有一个确定的值,而不能是IPPROTO_IP。因为MY_PF_INET域中inetsw数组只有三项(SOCK_STREAM, IPPROTO_TCP), (SOCK_DGRAM, IPPROTO_UDP), (SOCK_
类别:socket及其编程 | 评论(2) | 浏览()
 
2006年08月11日 星期五 下午 02:18
   前面讲到在sys_socket函数中,有一步是调用net_families[family]->create完成最后的创建工作,下面就以inet域的创建来解释这最后一步的创建工作:
    1、设socket->state = SS_UNCONNECTED。
    2、从数组inetsw中匹配套接字类型和协议类型。inetsw是一个链表数组,也就是说数组的每一项是一个链表,同套接字类型的在同一个链表中。比如,用户这样创建一个TCP协议的套接字:
    socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )
    最终,内核在inetsw中匹配到的是这样一个结构体:
    static struct inet_protosw inetsw_array[] =
    {
        {
            .type =       SOCK_STREAM,
            .protocol =   IPPROTO_TCP,
          
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:17
    结构体sock是套接口在网络层的表示,在代码include/net/sock.h 174行定义,下面是其内容:
    struct sock {
        struct sock_common  __sk_common;
#define sk_family       __sk_common.skc_family
#define sk_state        __sk_common.skc_state
#define sk_reuse        __sk_common.skc_reuse
#define sk_bound_dev_if     __sk_common.skc_bound_dev_if
#define sk_node         __sk_common.skc_node
#define sk_bind_node        __sk_common.skc_bind_node
#define sk_refcnt       __sk_common.skc_refcnt
        unsigned char       sk_shutdown : 2,
        
类别:socket及其编程 | 评论(0) | 浏览()
 
2006年08月11日 星期五 下午 02:16
     一个socket代表了通信链路的一端,存储或指向与链路有关的所有信息。Linux提供了创建socket的一个系统调用,通过该系统调用,能够得到一个用来访问套接字的描述符:
         #include <sys/types.h>
         #include <sys/socket.h>
         int socket( int domain, int type, int protocol );
      内核中的系统调用函数原型是在net/socket.c 1180行:
         asmlinkage long sys_socket( int family, int type, int protocol );
      该函数主要做了两件事情:创建一个代表通讯端点的结构体struct socket,将这个结构映射到一个文件描述符上,最后将这个描述符返回,也就是我们调用socket得到的套接字描述符。
 下面是Linux内核中对结构socket的定义(不同操作系统间,对该结构的定义会有差异):
 struct socket {
  
类别:socket及其编程 | 评论(0) | 浏览()
 
     
 
 
文章存档
 
 
 
 
 
 
 
 
 
 
 
 
     
 
最新文章评论
   
 

我想请问:最大报文段长度(MSS)是最大的数据发送长度还是最大的数据接收长度?在书...
 

非常感谢!
 

不错不错,牛人啊
 

真棒...
 
     


©2009 Baidu