1.建立套接字

Linux在利用socket()系统调用建立新的套接字时,需要传递套接字的地址族标识符、套接字类型以及协议,其函数定义于net/socket.c中:

asmlinkage long sys_socket(int family, int type, int protocol)

{

int retval;

struct socket *sock;

retval = sock_create(family, type, protocol, &sock);

if (retval < 0)

goto out;

retval = sock_map_fd(sock);

if (retval < 0)

goto out_release;

out:

/* It may be already another descriptor 8) Not kernel problem. */

return retval;

out_release:

sock_release(sock);

return retval;

}

实际上,套接字对于用户程序而言就是特殊的已打开的文件。内核中为套接字定义了一种特殊的文件类型,形成一种特殊的文件系统sockfs,其定义于net/socket.c:

static struct vfsmount *sock_mnt;

static DECLARE_FSTYPE(sock_fs_type, "sockfs", sockfs_read_super, FS_NOMOUNT);

在系统初始化时,要通过kern_mount()安装这个文件系统。安装时有个作为连接件的vfsmount数据结构,这个结构的地址就保存在一个全局的指针sock_mnt中。所谓创建一个套接字,就是在sockfs文件系统中创建一个特殊文件,或者说一个节点,并建立起为实现套接字功能所需的一整套数据结构。所以,函数sock_create()首先是建立一个socket数据结构,然后将其“映射”到一个已打开的文件中,进行socket结构和sock结构的分配和初始化。

新创建的 BSD socket 数据结构包含有指向地址族专有的套接字例程的指针,这一指针实际就是 proto_ops 数据结构的地址。

BSD 套接字的套接字类型设置为所请求的 SOCK_STREAM 或 SOCK_DGRAM 等。然后,内核利用 proto_ops 数据结构中的信息调用地址族专有的创建例程。

之后,内核从当前进程的 fd 向量中分配空闲的文件描述符,该描述符指向的 file 数据结构被初始化。初始化过程包括将文件操作集指针指向由 BSD 套接字接口支持的 BSD 文件操作集。所有随后的套接字(文件)操作都将定向到该套接字接口,而套接字接口则会进一步调用地址族的操作例程,从而将操作传递到底层地址族
实际上,socket结构与sock结构是同一事物的两个方面。如果说socket结构是面向进程和系统调用界面的,那么sock结构就是面向底层驱动程序的。可是,为什么不把这两个数据结构合并成一个呢?

我们说套接字是一种特殊的文件系统,因此,inode结构内部的union的一个成分就用作socket结构,其定义如下:

struct inode {

union {

struct socket             socket_i;

}

}

由于套接字操作的特殊性,这个结构中需要大量的结构成分。可是,如果把这些结构成分全都放在socket结构中,则inode结构中的这个union就会变得很大,从而inode结构也会变得很大,而对于其他文件系统,这个union成分并不需要那么庞大。因此,就把套接字所需的这些结构成分拆成两部分,把与文件系统关系比较密切的那一部分放在socket结构中,把与通信关系比较密切的那一部分则单独组成一个数据结构,即sock结构。由于这两部分数据在逻辑上本来就是一体的,所以要通过指针互相指向对方,形成一对一的关系。

2.在 INET BSD 套接字上绑定(bind)地址

为了监听传入的 Internet 连接请求,每个服务器都需要建立一个 INET BSD 套接字,并且将自己的地址绑定到该套接字。绑定操作主要在 INET 套接字层中进行,还需要底层 TCP 层和 IP 层的某些支持。将地址绑定到某个套接字上之后,该套接字就不能用来进行任何其他的通讯,因此,该 socket数据结构的状态必须为 TCP_CLOSE。传递到绑定操作的 sockaddr 数据结构中包含要绑定的 IP地址,以及一个可选的端口地址。通常而言,要绑定的地址应该是赋予某个网络设备的 IP 地址,而该网络设备应该支持 INET 地址族,并且该设备是可用的。利用 ifconfig 命令可查看当前活动的网络接口。被绑定的 IP 地址保存在 sock 数据结构的rcv_saddr 和 saddr 域中,这两个域分别用于哈希查找和发送用的 IP 地址。端口地址是可选的,如果没有指定,底层的支持网络会选择一个空闲的端口。

当底层网络设备接受到数据包时,它必须将数据包传递到正确的 INET 和 BSD 套接字以便进行处理,因此,TCP维护多个哈希表,用来查找传入 IP 消息的地址,并将它们定向到正确的socket/sock 对。TCP 并不在绑定过程中将绑定的 sock 数据结构添加到哈希表中,在这一过程中,它仅仅判断所请求的端口号当前是否正在使用。在监听操作中,该 sock 结构才被添加到 TCP 的哈希表中。

3.在 INET BSD 套接字上建立连接(connect)

创建一个套接字之后,该套接字不仅可以用于监听入站的连接请求,也可以用于建立出站的连接请求。不论怎样都涉及到一个重要的过程:建立两个应用程序之间的虚拟电路。出站连接只能建立在处于正确状态的 INET BSD 套接字上,因此,不能建立于已建立连接的套接字,也不能建立于用于监听入站连接的套接字。也就是说,该 BSD socket 数据结构的状态必须为 SS_UNCONNECTED。

在建立连接过程中,双方 TCP 要进行三次“握手”,具体过程在 本章第二节——网络协议一文中有详细介绍。如果 TCP sock 正在等待传入消息,则该 sock 结构添加到 tcp_listening_hash 表中,这样,传入的 TCP 消息就可以定向到该 sock 数据结构。

4.监听(listen) INET BSD 套接字

当某个套接字被绑定了地址之后,该套接字就可以用来监听专属于该绑定地址的传入连接。网络应用程序也可以在未绑定地址之前监听套接字,这时,INET 套接字层将利用空闲的端口编号并自动绑定到该套接字。套接字的监听函数将 socket 的状态改变为 TCP_LISTEN。

当接收到某个传入的 TCP 连接请求时,TCP 建立一个新的 sock 数据结构来描述该连接。当该连接最终被接受时,新的 sock 数据结构将变成该 TCP 连接的内核bottom_half部分,这时,它要克隆包含连接请求的传入 sk_buff 中的信息,并在监听 sock 数据结构的 receive_queue 队列中将克隆的信息排队。克隆的 sk_buff 中包含有指向新 sock 数据结构的指针。

5.接受连接请求 (accept)

接受操作在监听套接字上进行,从监听 socket 中克隆一个新的 socket 数据结构。其过程如下:接受操作首先传递到支持协议层,即 INET 中,以便接受任何传入的连接请求。相反,接受操作进一步传递到实际的协议,例如 TCP 上。接受操作可以是阻塞的,也可以是非阻塞的。接受操作为非阻塞的情况下,如果没有可接受的传入连接,则接受操作将失败,而新建立的 socket 数据结构被抛弃。接受操作为阻塞的情况下,执行阻塞操作的网络应用程序将添加到等待队列中,并保持挂起直到接收到一个 TCP 连接请求为至。当连接请求到达之后,包含连接请求的 sk_buff 被丢弃,而由 TCP 建立的新 sock 数据结构返回到 INET 套接字层,在这里,sock 数据结构和先前建立的新 socket 数据结构建立链接。而新 socket 的文件描述符(fd)被返回到网络应用程序,此后,应用程序就可以利用该文件描述符在新建立的 INET BSD 套接字上进行套接字操作。

https://www.cnblogs.com/SophiaTang/archive/2012/02/05/2339365.html

socket 的通信过程的更多相关文章

  1. OpenFlow protocol version 1.0 通信过程

    参考 李呈:[原创]OpenFlow通信流程解读 OpenFlow protocol version 1.0 通信过程 通信双方: OpenFlow控制器,OpenFlow交换机. 通信模块: Sec ...

  2. Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...

  3. 【转】wpa_supplicant与wpa_cli之间通信过程

    [转]wpa_supplicant与wpa_cli之间通信过程 转自:http://blog.chinaunix.net/uid-26585427-id-4051479.html wpa_suppli ...

  4. ZLL本地局域网通信过程

    Interface_srpcserver -----以灯的状态操作位例 网关与客户端通过Socket API通信,Socket API在socket_server.c中实现,socket_server ...

  5. SSL、TLS协议格式、HTTPS通信过程、RDP SSL通信过程

    相关学习资料 http://www.360doc.com/content/10/0602/08/1466362_30787868.shtml http://www.gxu.edu.cn/college ...

  6. Dubbo底层采用Socket进行通信详解

    由于Dubbo底层采用Socket进行通信,自己对通信理理论也不是很清楚,所以顺便把通信的知识也学习一下. n  通信理论 计算机与外界的信息交换称为通信.基本的通信方法有并行通信和串行通信两种. 1 ...

  7. Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信

    Android BLE与终端通信(三)--客户端与服务端通信过程以及实现数据通信 前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主 ...

  8. SSL、TLS协议格式、HTTPS通信过程、RDP SSL通信过程(缺heartbeat)

    SSL.TLS协议格式.HTTPS通信过程.RDP SSL通信过程   相关学习资料 http://www.360doc.com/content/10/0602/08/1466362_30787868 ...

  9. SSL及其加密通信过程

    SSL及其加密通信过程 什么是SSL SSL英文全称Secure Socket Layer,安全套接层,是一种为网络通信提供安全以及数据完整性的安全协议,它在传输层对网络进行加密.它主要是分为两层: ...

随机推荐

  1. jquery判断字符串中是否存在某个的字符串

    有两种方式: 1)test 2)indexOf $(function(){ var str="sunny,woo"; var sear=new RegExp(','); if(se ...

  2. cnblogs正式启用

    额,因为最近发现CSDN越来越过分了...现在连数学公式都显示错字体了--于是决定把博客搬至cnblogs. Markdown 测试 \(\frac{-b\pm \sqrt{b^2-4ac}}{2a} ...

  3. MySQL主要命令(4)

    显示数据, 给列区别名: select coL_name as 别名     from table_name;

  4. DNS绑定多个IP地址

    DNS轮循技术 首先介绍一个DNS系统:传统的DNS解析都是一个域名对应一个IP地址,但是通过DNS轮循技术(负载平衡技术)可以做到一个域名对应到多个IP 上. 这样大家难免就会问,这个技术有什么用呢 ...

  5. Maven错误:XXX时出错; invalid LOC header (bad signature)的解决方法

    错误原因是该包没下载成功,比如网络问题等因素. 解决方法:进入本地仓库删除该包,然后再执行打包或部署等操作即可.

  6. With Storm Spouts, when is declareOutputFields( ) called?

    The method IComponent.declareOutputFields(...) is called on the client machine when the client code ...

  7. Python:利用 selenium 库抓取动态网页示例

    前言 在抓取常规的静态网页时,我们直接请求对应的 url 就可以获取到完整的 HTML 页面,但是对于动态页面,网页显示的内容往往是通过 ajax 动态去生成的,所以如果是用 urllib.reque ...

  8. 【cl】子查询应用场景

    有推荐人/没有推荐人的 recommender_id is null / is not null 谁是推荐人=他的id是别人的recommender_id=某个人的recommender_id是他的i ...

  9. [ajax 学习笔记] ajax初试

    ajax全称是:asynchronous javasctipt and xml. 1.为什么须要ajax? 一般web程序与server的交互是:页面发送请求等待server处理,server处理数据 ...

  10. iOS总结(自己定义button)

    1.首先新建一个类该类继承UIButton 2.实现几个方法 1).改动字体的一些属性 -(instancetype)initWithFrame:(CGRect)frame{ self = [supe ...