本文创建于 2024-12-12;修改于 2024-12-13;

一、Linux 网络IO API

Posix API 网络通信相关函数:

image

TCP 状态迁移图:

image

二、用于建立连接的API

socket

# man socket

# desc:  socket - create an endpoint for communication

       #include <sys/types.h>
       #include <sys/socket.h>

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

一个 socket 套接字由两部分组成,分别是 文件描述符 fd 和 TCP控制块 tcp control block;理所应当的,socket 函数就是负责处理这两部分的。

  • fd: 文件描述符,int 类型,系统递增分配,底层为 bitmap(位图),通过置0置1来判断某个fd是否已经分配了;

bind

# man bind:

# desc: bind - bind a name to a socket

       #include <sys/types.h>
       #include <sys/socket.h>

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

bind 函数用于将我们设置的 ip地址 和 port端口设置进 socket 分配的 tcb(TCP控制块)内,以备后续连接。

注:对于 client 来说,bind 不是必须的,如果没有主动绑定到端口的话,后期系统会自动为其分配随机端口。

listern

# man listen

# desc: listen - listen for connections on a socket

       #include <sys/types.h>
       #include <sys/socket.h>

       int listen(int sockfd, int backlog);

listen 函数主要职责就是,将套接字中tcb内的状态设置为监听状态;为 tcb 分配一个全连接队列,以及一个半连接队列;

  • tcb -> status = TCP_STATUS_LISTEN
  • tcb -> syn_queue
  • tcb -> qccept_queue

listen状态后,才能够建立TCP连接,接下来就是TCP建立一个连接的流程;

image

accept

# man accept

# desc: accept, accept4 - accept a connection on a socket

       #include <sys/types.h>
       #include <sys/socket.h>

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

accept 函数的工作分为两部分,分配fd给对应的client,把 fd 和 tcb 做映射;

三、用于传输数据的API

recv

# man recv

desc: recv, recvfrom, recvmsg - receive a message from a socket

       #include <sys/types.h>
       #include <sys/socket.h>

       ssize_t recv(int sockfd, void *buf, size_t len, int flags);

send

# man send

desc: send, sendto, sendmsg - send a message on a socket

       #include <sys/types.h>
       #include <sys/socket.h>

       ssize_t send(int sockfd, const void *buf, size_t len, int flags);

四、断开连接

close

# man close

desc: close - close a file descriptor

       #include <unistd.h>

       int close(int fd);

close 函数的工作大概是:

  1. 关闭一个fd;
  2. 之后向被动方发送一个 fin 字段置1; 数据长度为0 的tcp报文
  3. 被动发 recv 该报文后发现数据段长度为0,得知这是要求关闭的一个tcp报文,会回发 ack 字段置1 的tcp报文

TCP 四次挥手流程:

image

注意:在断开连接时没有客户端与服务端的概念,只有主动方与被动方;