Socket 定义

socket 即套接字,是一个双向通信通道,两端为两个process或者两个机器

  • socket是对网络通信的一种抽象
  • 提供了数据交换的 api
  • 去处了一些网卡交互的细节

服务器工作流 server flow

server_socket_flow.png

用户工作流 client flow

client_socket_flow.png

工作流解读

SC 交互

sc_interact.png

socket() 构造

参数为 socket(int domain, int type, int protocol, 都使用宏定义进行输入的

  • domain 表示交流的范围,对于 IPv4 使用宏 AF_NET
  • type 定义了交流的semantics, 对于双向交流的 socket,使用宏 SOCK_STREAM
  • protocol 定义了协议,使用宏 IPPROTO_tCP 即可
    整个函数定义在 <sys/socket.h>

bind() 绑定

参数为 bind(int sockfd, const struct sockaddr_in * addr, socklen_t addrlen);

  • sockfd: 上文构造的 socket 对象
  • addr 定义了一些参数包括 port 编号等
    • 如果 addr 设置为 0 那 OS 会选择一个 port
  • addrlen: sizeof(addr)
    整个函数返回一个 int 表示状态,0 为成功,-1 为失败

port 的定义

是一种逻辑通道,与 IP 地址绑定一同用于寻路来完成一定的服务或者应用

Errors and errno

定义在 <cerrno> 或者 <errno.h>
在输入的时候为一个数字,使用 strerror 函数使之变成一个有效错误码

listen() 监听类

参数为 listen(int sockfd, int backlog)

  • backlog 表示等待queue可以长到的最大长度
    返回 0 表示成功 -1 表示失败

accept() 接收类 (server 端用)

参数为 accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
用于服务器端进行接受client的请求连接
sockfd:这是监听socket的文件描述符,即你之前调用socket创建,然后用bind和listen设置好的socket。
addr:这是一个指向sockaddr结构的指针,该结构用于接收连接方的协议地址。当连接建立时,这个结构将被填充。
addrlen:这是一个指向socklen_t变量的指针,该变量在调用时表示addr的大小,调用返回时表示实际存储在addr中的地址的大小。
返回值:
成功:返回一个新的socket文件描述符,一般命名为 client_fd,用于与新连接的客户端通信。这个新的文件描述符与监听socket是分开的,后者继续监听其他的连接请求。
失败:返回-1,并设置errno以指示错误发生的原因。
至此之后使用 fd 相关的地方都用 client_fd 而不再是 sockfd

connect() 连接类 (client 端用)

参数为 connect(int sockfd, const struct sockaddr_in * addr, socklen_t addrlen)
用于客户端连接服务器进行的处理
成功返回 0 失败返回 -1

send() 发送类

函数 ssize_t send(int sockfd, const void *buf, size_t len, int flags)
其中数据类型 ssize_t 表示 signed size_t 即数值可以为 <0 的数值

  • buf 指向数据的一个 指针
  • len 传输数据的长度 (byte)
  • flags 额外发送选项,一般 0 就是标准发送流程
    返回数值为发送的 byte 数量,返回 -1 表示发生 error

发送示例代码

socket_send_exp.png

recv() 接收类

函数 ssize_t recv(int sockfd, void *buf, size_t len, int flags)
其中 void* 是通用类型指针,可以指向任意类型的变量

  • buf 表示接受保存的地址
  • len 表示接受的最大长度 byte
  • flags 可以用 MSG_WAITALL 来等待接受长度为 len byte 的数据包之后再返回
    注意这里的 MSG_WAITALL 的目的是填满 buffer,因此buffer的大小应当和发送包的大小对齐
    返回数值为 接受到byte的数量,0表示end-of-stream (connection closed) 或者 -1 表示 error

常见错误

由于使用 std::vector<> 的时候其单个内存很难用 sizeof() 正确识别,所以不建议使用这个函数进行识别

close() 关闭类

参数为 close(int sockfd);
成功 0 失败 -1

不同端存储结构的通信

本地端需要将数据统一转换成 network-order (big-endian) 也就是使用 <arpa/inet.h> 库函数进行加工

  • ntohl network 2 host long
  • ntohs net 2 host short
  • htonl host 2 network long
  • htons host 2 network short
    一般常常用在地址的解析过程
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);