7. 网络通信
简介
主要对socket套接字进行详细的分析,包括连接的建立、数据的发送与接收等等。
连接的建立socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
第1个参数domain:用于表示协议族,如AF_INET为IPv4
第2个参数type: 用于指示类型,如基于流通信的SOCK_STREAM
第3个参数protocal: 对应这种socket的具体协议类型。
成功创建socket后,会返回一个套接字文件描述符。失败时,接口返回-1。
绑定IP地址bind
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
第1个参数sockfd:表示要绑定地址的套接字描述符
第2个参数addr:表示绑定到套接字的地址
struct sockadd {
sa_family_t sa_family;
char sa_data[14];
}
第3个参数addrlen: 表示绑定的地址长度
成功返回0,错误返回-1。
成功创建套接字后,该套接字仅仅是一个文件描述符,并没有任何地址与之关联,使用socket发送数据包时,由于该socket没有任何ip地址,内核会自动选择一个地址。一般对于服务端需要通过bind手动指定地址。
客户端连接connect
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
第1个参数 sockfd:套接字描述符
第2个参数 addr:要连接的地址
第3个参数addrlen:要连接的地址长度
对于TCP套接字来说,connect是3次握手,所以其默认是一个阻塞操作。也可以成为一个非阻塞的过程。
服务器监听listen
#include <sys/socket.h>
int listen(int sockfd, int backlog);
第1个参数sockfd:成功创建的TCP套接字
第2个参数backlog:定义TCP未处理连接的队列长度,该队列已经完成三次握手,但服务器端还没有执行accept的连接。
成功返回0,失败返回-1。
服务器连接accept
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
第1个参数sockfd:处于监听状态的套接字
第2个参数addr:保存客户端的地址信息
第3个参数addrlen:是一个输入输出值,调用者将其初始化为addr缓存的大小,accept返回时,设置为addr的大小。
第4个参数flags:accept4的标志,目前支持SOCK_NONBLOCK、SOCK_CLOEXEC。
成功返回一个非负的文件描述符,失败返回-1。
accept用于从指定套接字的连接队列中取出第一个连接,并返回一个新的套接字用于与客户端通信。
发送相关接口send
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
send只能用于处理已经连接的套接字。
sendto可以在调用时指定目的地址,如果套接字已经是连接状态,那么目的地址的dest_addr与addrlen应该是NULL和0。
sendmsg无论要发送的数据还是目的地址都保存在msg中,msg.msg_name和msg.msg_len用于指明目的地址,而msg.msg_iov用于保存要发送的数据。
flags只是标志位(稍现代的系统调用,一般都会有一个标志参数,可以从容的为系统调用增加新功能,并同时兼容老版本)
由于socket同时还是文件描述符,所以为文件提供的读写函数,也可以被socket直接调用
接收相关接口recv
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
与send对称的接口
recv也是处理已连接的套接字。
recvfrom通过额外的参数 src_addr与addrlen来获得发送方的地址,addrlen也是输入输出值。
recvmsg与sengmsg相同,把接受的数据都保存在msg中。
都支持设置标志位flags