本文迁移并整理自个人之前在博客园的博客。
什么是网络套接字(Socket)?一时还真不好回答,而且网络上也有各种解释,莫衷一是。下文将以本人所查阅到的资料来说明一下什么是Socket。
Socket 定义
Socket在维基百科的定义:
A network socket is an endpoint of an inter-process communication across a computer network. Today, most communication between computers is based on the Internet Protocol; therefore most network sockets are Internet sockets.
而在 Oracle 官网上的定义是:
A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.
其实他们想表达的都是这个意思:Socket是网络上两个程序双向通讯连接的端点。
那我们又该如何理解端点(Endpoint)
一词呢?
在 Unix/Linux 中,一切皆文件。那对于这两个操作系统而言,端点
就是一个特殊的文件,也就是说 Socket 实际上就是文件
。既然 Socket 是文件,那就可以用“打开open –> 读写write/read –> 关闭close”模式来操作它。一些 Socket 函数就是对其进行的操作(读/写IO、打开、关闭)。更加详细的介绍特摘录自 Tutorialspoint:
Sockets allow communication between two different processes on the same or different machines. To be more precise, it’s a way to talk to other computers using standard Unix file descriptors. In Unix, every I/O action is done by writing or reading a file descriptor. A file descriptor is just an integer associated with an open file and it can be a network connection, a text file, a terminal,or something else. To a programmer,
a socket looks and behaves much like a low-level file descriptor
. This is because commands such as read() and write() work with sockets in the same way they do with files and pipes.
对于一个Socket而言,它至少需要3个参数来指定:
1)通信的目的地址;
2)使用的传输层协议(如TCP、UDP);
3)使用的端口号。
Socket 类型
套接字类型是指创建套接字的应用程序要使用的通信服务类型。Linux 系统支持多种套接字类型,最常用的有以下三种:
1)SOCK_STREAM:流式套接字,提供面向连接、可靠的数据传输服务,数据按字节流、按顺序收发,保证在传输过程中无丢失、无冗余。TCP 协议支持该套接字。
2)SOCK_DGRAM:数据报套接字,提供面向无连接的服务,数据收发无序,不能保证数据的准确到达。UDP 协议支持该套接字。
3)SOCK_RAW:原始套接字。允许对低于传输层的协议或物理网络直接访问,例如可以接收和发送 ICMP 报文。常用于检测新的协议。
详细可参考 Tutorialspoint。
Socket 网络层次
这部分主要参考自《深入浅出 Linux 工具与编程》(余国平著)。
下图画出了 Socket 位于网络中的层次,它位于传输层以上、应用层以下(注意它并不属于 OSI 中的一层
)。Socket 编程正是通过一系列系统调用(Socket API)来完成应用层协议(如 FTP、HTTP)
。
图:套接字层次图
Socket 是对网络中应用层进程之间的通信进行了抽象,提供了应用层进程利用网络协议栈交换数据的机制。
除了可与传输层交互,Socket 还可以与网络层交互
:
图片来源
Socket 工作流
典型的 Socket 工作流(服务端 <-> 客户端)如下图所示:
图片来源
步骤描述就直接摘自博文 How sockets work 了(结合上图容易看懂,就不作翻译了):
- The socket() API creates an endpoint for communications and returns a socket descriptor that represents the endpoint.
- When an application has a socket descriptor, it can bind a unique name to the socket. Servers must bind a name to be accessible from the network.
- The listen() API indicates a willingness to accept client connection requests. When a listen() API is issued for a socket, that socket cannot actively initiate connection requests. The listen() API is issued after a socket is allocated with a socket() API and the bind() API binds a name to the socket. A listen() API must be issued before an accept() API is issued.
- The client application uses a connect() API on a stream socket to establish a connection to the server.
- The server application uses the accept() API to accept a client connection request. The server must issue the bind() and listen() APIs successfully before it can issue an accept() API.
- When a connection is established between stream sockets (between client and server), you can use any of the socket API data transfer APIs. Clients and servers have many data transfer APIs from which to choose, such as send(), recv(), read(), write(), and others.
- When a server or client wants to stop operations, it issues a close() API to release any system resources acquired by the socket.