套接字socket
前面的文章中,我们讲了TCP/IP、TCP和UDP的一些基本知识,但是协议只有一套,而我们系统多个TCP连接或多个应用程序进程必须通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接 ,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为 套接字(Socket)的接口。
套接字就是支持TCP/IP网络通信的基本操作单元,是我们进行TCP/IP进行通信的接口。
linux以文件的形式实现套接口,与套接口相应的文件属于sockfs特殊文件系统,创建一个套接口就是在sockfs中创建一个特殊文件,并建立起为实现套接口功能的相关数据结构。换句话说,对每一个新创建的套接字,linux内核都将在sockfs特殊文件系统中创建一个新的inode。
套接字Socket看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。套接字Socket是连接应用程序和网络驱动程序的桥梁,套接字Socket在应用程序中创建,通过绑定与网络驱动建立关系。此后,应用程序送给套接字Socket的数据,由套接字Socket交给网络驱动程序向网络上发送出去。计算机从网络上收到与该套接字Socket绑定IP地址和端口号相关的数据后,由网络驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据,网络应用程序就是这样通过Socket进行数据的发送与接收的。
操作系统区分不同应用程序进程间的网络通信和连接,主要有3个参数:通信的目的IP地址、使用的传输层协议(TCP或UDP)和使用的端口号。
*Socket=Ipaddress+TCP/UDP+port*
通过将这3个参数结合起来,与一个Socket绑定,应用层就可以和传输层通过套接字接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
套接字连接的过程如同(客户)打一个电话到一个大公司,接线员(服务器进程)接听电话并把它转接到你要找的部门,然后再从那里转到你要找的人(服务器套接字),然后接线员(服务器进程)再继续转接其它(客户)的电话。
套接字有本地套接字和网络套接字两种。
- 本地套接字的名字是Linux文件系统中的文件名,一般放在
/tmp
或/usr/tmp
目录中; - 网络套接字的名字是与客户连接的特定网络有关的服务标识符(端口号或访问点)。这个标识符允许Linux将进入的针对特定端口号的连接转到正确的服务器进程。
套接字类型
TCP/IP中有三种常用的套接字
流式套接字(SOCK_STREAM)
流式套接字提供可靠的、面向连接的通信流,保证数据传输的可靠性和按序收发。TCP通信的使用的就是流式套接字。
数据报套接字(SOCK_DGRAM)
数据包套接字实现了一种不可靠、无连接的服务。数据通过相互独立的报文进行传输,是无序的,并且不保证可靠的传输。UDP受用的就是数据报套接字。
原始套接字(SOCK_RAW)
原始套接字允许对底层(如IP或ICMP)进行直接访问,它功能强大但使用较为不便,主要用于一些协议的开发。
原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。
网络编程中几个重要的数据结构
表示套接口的数据结构struct socket
用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符。在系统调用 的实现函数里,这个数字就会被映射成一个表示socket的结构体,该结构体保存了该socket的所有属性和数据。
套接口是由socket数据结构代表的,形式如下
struct socket {
socket_state state; /*指明套接口的连接状态,一个套接口的连接状态可以有以下几种
套接口是空闲的,还没有进行相应的端口及地址的绑定;还没有连接;正在连接中;已经连接;正在解除连接。*/
unsignedlong flags;
structproto_ops ops; /*指明可对套接口进行的各种操作*/
structinode inode; /*指向sockfs文件系统中的相应inode*/
structfasync_struct *fasync_list; /* Asynchronous wake up list */
structfile *file; /*指向sockfs文件系统中的相应文件 */
structsock sk; /*任何协议族都有其特定的套接口特性,该域就指向特定协议族的套接口对
象*/
wait_queue_head_t wait;
short type;
unsignedchar passcred;
};
-
state
用于表示socket所处的状态,是一个枚举变量,该成员只对TCP socket有用,因为只有TCP是面向连接的协议,UDP跟raw不需要维护socket状态。
其类型定义如下:typedef enum { SS_FREE = 0, //该socket还未分配 SS_UNCONNECTED, //未连向任何socket SS_CONNECTING, //正在连接过程中 SS_CONNECTED, //已连向一个socket SS_DISCONNECTING //正在断开连接的过程中 }socket_state;
-
flags
是一组标志位,在内核中并没有发现被使用。 -
ops
是协议相关的一组操作集,结构体struct proto_ops的定义如下:struct proto_ops { int family; struct module *owner; int (*release)(struct socket *sock); int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);