linux socket编程(udev举例)

来源:互联网 发布:淘宝层级怎么刷 编辑:程序博客网 时间:2024/05/29 16:04



union sockaddr_union {
        struct sockaddr sa; 
        struct sockaddr_in in4;
        struct sockaddr_in6 in6;
        struct sockaddr_un un; 
        struct sockaddr_nl nl; 
        struct sockaddr_storage storage;
};


通常的套接口地址
struct sockaddr {
    sa_family_t sa_family; /* Address Family */
    char        sa_data[14]; /* Address data. */
};


UNIX本地通讯套接口地址
struct sockaddr_un
{
sa_family_t sun_family;
char sun_path[108];         /* Path name.  */
};


NETLINK的套接口地址
struct sockaddr_nl
{
  sa_family_t    nl_family;
  unsigned short nl_pad;
  __u32          nl_pid;
  __u32          nl_groups;
};
  
  


socket编程接口:


socket
udev_device_new_from_device_id
udev_monitor_new_from_netlink_fd
udev_ctrl_new_from_fd
rename_netif

bind
udev_monitor_enable_receiving
udev_ctrl_enable_receiving

sendmsg
udev_monitor_send_device

recvmsg
udev_ctrl_receive_msg

close
udev_monitor_disconnect
udev_monitor_unref
udev_ctrl_unref
udev_ctrl_get_connection
udev_ctrl_connection_unref


总体来看,在udev中创建一个socket服务程序,来接收来自内核的消息。

相当于是udev中的socket为服务器端,内核为客户端。

服务器端调用listen之后,就可以接收客户端的连接请求。

服务器端再调用accept4,来建立同客户端的连接,由此之后,客户端,也即是内核有了新消息的时候,会自动把消息发送到udev的socket服务程序。

 

1.      调用socket函数:创建一个netlink socket

2.      调用bind函数:将netlink socket同netlink源socket地址绑定起来。

3.      调用listen函数:宣告可以开始接收连接请求。

4.      调用accept4函数:获得连接请求并建立连接。

5.      调用getsockopt函数:获取socket的信息

6.      调用setsockopt函数:设置socket的信息

 

 

struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)

{

        struct udev_ctrl *uctrl;

 

        uctrl = calloc(1, sizeof(struct udev_ctrl));

        if (uctrl == NULL)

                return NULL;

        uctrl->refcount = 1;

        uctrl->udev = udev;

 

        if (fd < 0) {

                uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);

                if (uctrl->sock < 0) {

                        log_error("error getting socket: %m\n");

                        udev_ctrl_unref(uctrl);

                        return NULL;

                }

        } else {

                uctrl->bound = true;

                uctrl->sock = fd;

        }

        /* uctrl->saddr 是struct sockaddr_un 类型,un为unix缩写,即为使用unix本地通信协议的socket。下面的操作:

1.       指定通信协议族saddr.sun_family为本地UNIX通信协议(不是网络协议AF_INET为网络协议族)。

2.       指定uctrl的socket需要连接的另一端,即该socket要连接到“/run/udev/control”文件区。

3.       下文bind完成的工作就是将uctrl的socke同目标文件连接。

*/

        uctrl->saddr.sun_family = AF_LOCAL;

        util_strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control");

        uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);

        return uctrl;

}

 

int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)

{

        int err;

 

        if (!uctrl->bound) {

                /* bind:将netlink socket:uctrl->sock同netlink源socket地址绑定起来(上文已经指定)。*/

                err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);

                if (err < 0 && errno == EADDRINUSE) {

                        unlink(uctrl->saddr.sun_path);

                        err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);

                }

 

                if (err < 0) {

                        err = -errno;

                        log_error("bind failed: %m\n");

                        return err;

                }

                /*listen之后,uctrl->sock开始从uctrl->saddr包含的目标处接收连接请求 。*/

                err = listen(uctrl->sock, 0);

                if (err < 0) {

                        err = -errno;

                        log_error("listen failed: %m\n");

                        return err;

                }

 

                uctrl->bound = true;

                uctrl->cleanup_socket = true;

        }

        return 0;

}

 

0 0
原创粉丝点击