网络 Socket 编程
Socket 定义
socket 即套接字,是一个双向通信通道,两端为两个process或者两个机器
- socket是对网络通信的一种抽象
- 提供了数据交换的 api
- 去处了一些网卡交互的细节
服务器工作流 server flow

用户工作流 client flow

工作流解读
SC 交互

socket() 构造
参数为 socket(int domain, int type, int protocol, 都使用宏定义进行输入的
domain表示交流的范围,对于 IPv4 使用宏AF_NETtype定义了交流的semantics, 对于双向交流的 socket,使用宏SOCK_STREAMprotocol定义了协议,使用宏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
发送示例代码

recv() 接收类
函数 ssize_t recv(int sockfd, void *buf, size_t len, int flags)
其中 void* 是通用类型指针,可以指向任意类型的变量
buf表示接受保存的地址len表示接受的最大长度 byteflags可以用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> 库函数进行加工
ntohlnetwork 2 host longntohsnet 2 host shorthtonlhost 2 network longhtonshost 2 network short
一般常常用在地址的解析过程
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
