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

简介:

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系统调用,可以在linux系统调用实现机制详解(内核4.14.4)

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

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 函数来发送。
目录
打赏
0
0
0
0
78
分享
相关文章
|
12月前
|
【Shell 命令集合 磁盘管理 】⭐⭐ Linux 显示当前shell会话中的目录栈 dirs命令使用教程
【Shell 命令集合 磁盘管理 】⭐⭐ Linux 显示当前shell会话中的目录栈 dirs命令使用教程
85 0
|
12月前
|
【Shell 命令集合 磁盘管理 】Linux 显示当前shell会话中的目录栈 dirs命令使用教程
【Shell 命令集合 磁盘管理 】Linux 显示当前shell会话中的目录栈 dirs命令使用教程
105 1
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
382 2
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
【在Linux世界中追寻伟大的One Piece】HTTPS协议原理
【在Linux世界中追寻伟大的One Piece】HTTPS协议原理
82 2
扩展Linux网络栈
扩展Linux网络栈
143 3
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
111 0
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
在Linux中,我们都知道,dns采用了tcp协议,又采用了udp协议,什么时候采用tcp协议?什么 时候采用udp协议?为什么要这么设计?
在Linux中,我们都知道,dns采用了tcp协议,又采用了udp协议,什么时候采用tcp协议?什么 时候采用udp协议?为什么要这么设计?