博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux协议栈(9)——应用层实现
阅读量:5905 次
发布时间:2019-06-19

本文共 1899 字,大约阅读时间需要 6 分钟。

Linux协议栈(9)——应用层实现

一般Linux开发程序员来看,外部的设备都是普通文件,都可以通过读写访问来实现发送和接收数据包。但是网卡有些意外,因为每个层次使用了不同的通信协议,建立连接需要指定许多选项,不能通过打开设备来完成这些任务。后来就有了套接字的特殊结构,具体怎么来的就不说了就是一个美国政府和伯克利分校的项目中诞生的,现在已经成为了工业标准,在POSIX标准中也定义了套接字,当然linux必然实现了套接字了。

使用套接字的时候需要区分地址和协议族(是ipv4还是ipv6),区分是基于流的还是数据报的(是TCP还是UDP)。

            本章会对基本的套接字数据结构及使用进行说明介绍。

内核与用户空间套接字之间的接口实现在C标准库中,使用socketcall系统,该函数是一个多路分解器。

 

1.1.1.1  socket数据结构

socket 位于传输层协议之上,屏蔽了不同网络协议之间的差异。

socket 是网络编程的入口,它提供了大量的系统调用,构成了网络程序的主体

  在Linux系统中,socket 属于文件系统的一部分,网络通信可以被看作是对文件的读取,使得我们对网络的控制和对文件的控制一样方便。

定义在文件include/linux/net.h中。

struct socket {

        socket_state            state;

 

        short                   type;

 

        unsigned long           flags;

 

        struct socket_wq __rcu  *wq;

 

        struct file             *file;

        struct sock             *sk;

        const struct proto_ops  *ops;

};

其中state表示套接字的链接状态,定义在

include/uapi/linux/net.h文件中

typedef enum {

        SS_FREE = 0,                    /* not allocated                */

        SS_UNCONNECTED,                 /* unconnected to any socket    */

        SS_CONNECTING,                  /* in process of connecting     */

        SS_CONNECTED,                   /* connected to socket          */

        SS_DISCONNECTING                /* in process of disconnecting  */

} socket_state;

            其中proto_ops指针变量指向一个数据结构,定义在文件:

include/linux/net.h.结构中包含的sock指针,指向sock结构。

关于socketcall系统调用,可以在

文章中查看,有描述到该系统调用。该系统调用是网络相关系统调用的入口。

1.1.1.2  接收数据

使用recvfrom和recv以及文件相关的readv和read函数来接收数据。以recvfrom为例,如果调用recvfrom内核中的代码函数是sys_recvfrom。

定义在net/socket.c 文件中。

SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,

                unsigned int, flags, struct sockaddr __user *, addr,

                int __user *, addr_len)

            函数会先调用sockfd_lookup_light函数,从查找对应的sock.没找到则退出。

            然后调用sock_recvmsg(特定于协议,tcp使用tcp_recvmsg,udp使用udp_recvmsg),从队列中获取分组,如果没有就阻塞。

最后调用move_addr_to_user函数,将数据从内核移动到用户空间。

1.1.1.3  发送数据

发送该数据可以使用两个与网络有关的库函数(sendto和send)或文件层的write和writev函数。

            以sys_sendto为例,定义如下:

SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,

                unsigned int, flags, struct sockaddr __user *, addr,

                int, addr_len)   

           
先调用
sockfd_lookup_light
函数获得
sock
,如果不存在则退出接着调用
move_addr_to_kernel
函数,将数据从用户层复制到内核。最后调用(协议相关的)
sock_sendmsg
函数来发送。

转载地址:http://gjjpx.baihongyu.com/

你可能感兴趣的文章
近5年133个Java面试问题列表
查看>>
在开源氛围下,“够用就是最好”
查看>>
mongodb 配置项详解
查看>>
django 常用 模板过滤器
查看>>
eclipse如何把多个项目放在一个文件夹下
查看>>
vc2010混用debug或者release静态库提示error LNK2038的解决办法
查看>>
elasticsearch Java API 之Bulk API(批量操作)
查看>>
好的javascript程序员
查看>>
oracle自动生成uuid
查看>>
Spring Cloud Config采用数据库存储配置内容【Edgware+】
查看>>
[周榜单]极乐小程序榜单(第十三期)
查看>>
[JAVA多线程相关资料]
查看>>
人工智能或许把人类引入灾难的深渊?
查看>>
Linux虚拟机新增加了块100G硬盘后,把空间分配到/opt下
查看>>
linux 禁止普通用户使用su切换到root用户和禁止 root ssh登陆
查看>>
[LeetCode]86. Partition List
查看>>
[C++模板]Clang3.6版本的Checker
查看>>
交换机SPAN功能配置
查看>>
lua的Chunks和block
查看>>
Linux 下 的 cc 和 gcc
查看>>