参考内容:

What is Socket Programming in C?)

Sockets and Network Programming in C

Socket in Computer Network

socket(2)bind(2)listen(2) accept(2)recv(2)send(2)sockaddr(3type)

Socket 是现代网络编程的基石。不论是网页浏览(HTTP)、即时通讯(QQ/微信)还是在线游戏,底层都是通过 Socket 机制来实现跨网络的进程间通信。它将复杂的底层网络协议封装成简单易用的编程接口,让开发者能够专注于应用逻辑,而不必从零开始处理复杂的网络包传输细节。

Socket 让运行在不同机器(或同一台机器)上的两个进程可以相互交换数据。我们可以把 Socket 想象成一个电话机,通话双方都必须各有一个电话(Socket),并通特定的号码(地址)建立连接。

Socket 由 IP 地址和端口号组成,其中 IP 地址标识网络中的具体主机(确定去哪台电脑),端口号用于标识该主机上的具体进程或服务(确定去哪个程序),简单说就是socket = ip + port

通过下面的服务器客户端模型状态图,我们可以理解 Socket 在网络上两个节点之间建立连接的作用,下文将逐一讲解其中的每一个步骤和涉及到的函数原型。

函数原型

#include <sys/socket.h>

int socket(int domain, int type, int protocol);

socket() 用于创建一个用于通信的节点并返回一个指向该节点的文件描述符。需要注意的是 socket() 函数创建的是主动套接字(客户端用于主动发起连接),所以服务端后续需要使用 listen() 将其变为被动套接字。

  • domain 用于指定通信域,说人话就是使用哪个用于通信的协议族,比如 AF_INET 表示 IPv4 互联网协议,AF_INET6 表示 IPv6 互联网协议,AF_UNIX 表示本地通信协议,AF_BLUETOOTH 表示蓝牙底层套接字协议;
  • type 用于指定套接字中使用的通信类型,常用的比如 SOCK_STREAM 提供按顺序、可靠的双向连接字节流传输机制,即 TCP,SOCK_DGRAM 支持数据报(无连接、不可靠的消息),即 UDP;
  • protocol 表示套接字中使用的协议,用一个数字表示。如果协议族中只有一个协议,则协议编号为 0;否则,必须指定协议的具体编号。
#include <sys/socket.h>
#include <netinet/in.h>

// IPv4 only
struct sockaddr_in {
    sa_family_t    sin_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
};
struct in_addr {
    uint32_t       s_addr;
};

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

前面使用 socket() 创建的套接字并没有为其分配地址,bind() 函数则用于给创建的套接字分配地址,它允许我们将套接字连接到本地地址和端口。

  • sockfd 即我们通过调用 socket() 获取的套接字文件描述符;
  • addr 的实际结构取决于所使用的协议,对于 IPv4 它是 sockaddr_in,对于 IPv6 它是 sockaddr_in6
  • addrlen 表示前一个结构体 addr 的大小(以字节为单位)。
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);