本文讲究的就是一个实用,所以不会所有的东西都介绍,只会介绍常用的
注:阅读本文前最好还是有些网络编程的基础概念比如大端小端之类的
结构体
sockaddr_in
sockaddr_in是一个用来存放地址和端口的结构体,一般是IPV4协议使用
sin_family:存放使用的协议,必须是AF_INET(IPV4协议)
sin_port:存放的是端口
sin_addr:存放的是地址
sin_zero:我找到的解释是为了让sockaddr和sockaddr_in的大小一致,方便互相转换来占空间用的
1 | struct sockaddr_in { |
sockaddr_in6
sockaddr_in6和sockaddr_in都是用来存放地址和端口的结构体,不同的地方就是sockaddr_in6是提供给IPV6协议使用的
sin6_family:存放使用的协议,必须是AF_INET6(IPV6协议)
sin6_port:存放的是端口
sin6_flowinfo:流信息,一般情况下不需要显式的设置或使用sin6_flowinfo
sin6_addr:存放的是地址,是一个结构体
sin6_scope_id:地址范围的标识符,只有需要指定特定地址范围标识符时才会去显式设置其值
1 | struct sockaddr_in6 { |
msghdr
msg_name:存放地址结构体(sockaddr、sockaddr_in、sockaddr_in6)
msg_namelen:地址结构体的长度(以字节数表示)
msg_iov:指向iovec结构体的指针,里面存放着消息
msg_iovlen:msg_iov这个数组的长度
msg_control:辅助数据,一般传递其他与消息相关的信息,比如带外数据(Out-of-band-data)
msg_controllen:辅助数据的长度(以字节数表示)
iov_base:存放着数据
iov_len:存放着iov_base指向的数据的长度(以字节数表示)
1 | struct msghdr { |
函数
socket
这个函数是用来创建套接字的,创建成功会返回一个文件描述符,如果创建失败便会返回-1
1 | int socket(int domain, int type, int protocol) |
domain
地址族
AF_INET
:IPV4地址族,用于支持IPV4协议AF_INET6
:IPV6地址族,用于支持IPV6协议AF_UNIX
and AF_LOCAL:Unix域套接字地址族,用于同一台主机上通信
type
套接字的类型
SOCK_STREAM
:面向连接的可靠流式套接字SOCK_DGRAM
:面向消息的报式套接字SOCK_SEQPACKET
:面向连接的有序数据套接字SOCK_RAW
:网络层原始套接字
protocol
传输协议
SOCK_STREAM
IPPROTO_TCP
:TCP协议,一种面向连接的、可靠的、基于字节流的传输协议SOCK_DGRAM
IPPROTO_UDP
:UDP协议,一种无连接的、不可靠的,基于报文的传输协议SOCK_RAW
IPPROTO_RAW
:原始套接字协议,允许应用程序直接访问底层网络协议栈,可以用于构造自定义的网络协议IPPROTO_ICMP
:互联网控制消息协议(ICMP),用于网络设备之间传递错误和控制消息IPPROTO_IP
:IP协议,是基于IP地址的网络层协议,用于在网络中传输数据包SOCK_SEQPACKET
IPPROTO_SCTP
:流控制传输协议(SCTP)提供类似TCP的可靠性和有序性
示例
1 | int sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); |
bind
给套接字绑定地址,如果成功返回0,发生错误就返回-1
1 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
sockfd
套接字的文件描述符
addr
指向sockaddr结构体的指针
addrlen
地址结构体的字节数
示例
1 | sockaddr_in addr = {0}; |
listen
将套接字设置成监听(被动)模式
如果成功返回0,发生错误就返回-1
1 | int listen(int sockfd, int backlog); |
sockfd
套接字的文件描述符
backlog
请求队列的最大数量
示例
1 | listen(sockfd,128); |
connect
流式套接字发送连接请求,连接到服务器就返回0,如果发生错误就返回-1
1 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
sockfd
套接字的文件描述符
addr
指向sockaddr结构体的指针
addrlen
地址结构体的长度(以字节数表示)
示例
1 | sockaddr_in addr = {0}; |
accept
面向连接的套接字用来同意客户端发送的连接请求
会阻塞到有客户端发送连接请求
如果成功便会返回一个与客户端通信的套接字文件描述符,如果失败返回-1
1 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
sockfd
套接字文件描述符
addr
指向sockaddr结构体的指针,客户端的地址和端口会存储在里面
addrlen
指向地址结构体字节数的指针
示例
1 | sockaddr_in clientAddr = {0}; |
send
给面向连接的套接字发送数据的函数
如果不额外设置会阻塞到消息完全发出为止
发送成功返回发送数据的大小(以字节数表示),发生错误返回-1
1 | ssize_t send(int sockfd, const void *buf, size_t len, int flags) |
sockfd
套接字的文件描述符
buf
指向要发送的数据的缓冲区的指针
len
要发送的数据的长度(以字节数表示)
flags
发送数据时标记
MSG_DONTROUTE
:不查找路由表,直接发送数据MSG_OOB
:发送带外数据(Out-of-band data)MSG_NOSIGNAL
:忽略SIGPIPE
信号,如果发送的数据超出接收端的缓冲区大小,不会导致程序终止MSG_MORE
:表示还有更多数据待发送,用于 TCP 的流控制优化
示例
1 | send(clientfd,"Hei Client",sizeof("Hei Client"),MSG_MORE|MSG_OOB); |
sendto
一般给不连接的套接字用来发送报文
默认为阻塞模式
发送成功返回发送数据的大小(以字节数表示),发生错误返回-1
1 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, |
sockfd
套接字的文件描述符
buf
指向要发送的数据的缓冲区指针
len
要发送的数据的长度(以字节数表示)
flags
发送数据时的标记
MSG_DONTROUTE
:不查找路由表,直接发送数据MSG_OOB
:发送带外数据(Out-of-band data)MSG_NOSIGNAL
:忽略SIGPIPE
信号,如果发送的数据超出接收端的缓冲区大小,不会导致程序终止MSG_DONTWAIT
:非阻塞模式发送,函数调用将立即返回,而不管是否能够发送全部数据,如果不能立即发送,则可能会发送部分数据
dest_addr
指向sockaddr结构体的指针,结构体内存放的是数据的目标地址与端口
addrlen
地址结构体的长度(以字节数表示)
示例
1 | sockaddr_in addr = {0}; |
sendmsg
用于套接字发送数据
默认为阻塞模式
发送成功返回发送数据的大小(以字节数表示),发生错误返回-1
1 | ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); |
sockfd
套接字的文件描述符
msg
指向要发送的msghdr结构体的指针
flags
发送数据时的标记
MSG_DONTWAIT
:以非阻塞方式发送消息,即使发送缓冲区已满也立即返回MSG_EOR
:表示消息中的最后一个缓冲区的结束MSG_MORE
:表示消息中还有更多的数据要发送MSG_NOSIGNAL
:禁止在发送失败时产生SIGPIPE
信号,而是返回错误码,以避免由于对端关闭连接而引发的异常信号
示例
1 | msghdr msg = {0}; |
recv
用于套接字接收数据
如果不额外设置会阻塞到接收到数据
成功则返回接收到的数据的字节数(以字节数表示),失败则返回-1
1 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); |
sockfd
套接字的文件描述符
buf
指向用来接收数据的缓冲区指针
len
缓冲区的大小或可接收的最大字节数
flags
指定接收时的额外选项
MSG_DONTWAIT
:非阻塞模式 即使没有可用的数据,也立即返回结果,不会阻塞等待数据到达MSG_PEEK
:表示从接收队列中查看而不移除数据,可以用来检查接收缓冲区中的数据而不实际读取它们MSG_WAITALL
:接收过程中一直等待请求的数据直到满足条件,如果没有足够的数据,则阻塞等待MSG_OOB
:表示接收或发送带外数据(Out-of-Band) 这种数据具有高优先级,通常在正常数据之外进行处理
示例
1 | char buffer[1024] = {0}; |
recvfrom
报式套接字用来接收数据的函数
默认为阻塞模式
成功则返回接收到的数据的字节数(以字节数表示),失败则返回-1
1 | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, |
sockfd
套接字的文件描述符
buf
指向接收数据的缓冲区的指针
len
缓冲区的长度或可接收的最大字节数
flags
指定接收时的额外选项
MSG_TRUNC
:如果接收缓冲区的大小小于接收到的数据报的大小,则截断数据MSG_ERRQUEUE
:从错误队列接收错误消息MSG_CMSG_CLOEXEC
:设置接收的辅助数据(控制消息)以FD_CLOEXEC
标志关闭MSG_DONTWAIT
:非阻塞模式 即使没有可用的数据,也立即返回结果,不会阻塞等待数据到达MSG_PEEK
:表示从接收队列中查看而不移除数据,可以用来检查接收缓冲区中的数据而不实际读取它们MSG_WAITALL
:接收过程中一直等待请求的数据直到满足条件,如果没有足够的数据,则阻塞等待
示例
1 | char buffer[1024] = {0}; |
recvmsg
用于套接字接收数据
默认为阻塞模式
成功返回接收到的数据的长度(以字节数表示),不成功返回-1
1 | ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); |
sockfd
套接字的文件描述符
msg
指向用来接收数据的msghdr结构体的指针
flags
指定接收时的额外选项
MSG_CMSG_CLOEXEC
:在接收到控制消息(cmsg)时自动将其标记为FD_CLOEXEC
,使得接收的文件描述符在执行exec
系列函数时会被关闭MSG_DONTWAIT
:设置非阻塞模式,即使没有可用的数据,也立即返回MSG_ERRQUEUE
:接收错误消息队列中的消息 这个标志通常用于接收一些与套接字操作相关的错误信息,例如 ICMP 错误消息MSG_OOB
:表示接收或发送带外数据(Out-of-Band) 这种数据具有高优先级,通常在正常数据之外进行处理MSG_PEEK
:表示从接收队列中查看而不移除数据,可以用来检查接收缓冲区中的数据而不实际读取它们MSG_TRUNC
:如果接收缓冲区大小小于接收到的消息的大小,则将该标志设置为指示消息被截断MSG_WAITALL
:接收过程中一直等待请求的数据直到满足条件,如果没有足够的数据,则阻塞等待MSG_DONTWAIT
:非阻塞模式 即使没有可用的数据,也立即返回结果,不会阻塞等待数据到达
示例
1 | msghdr msg = {0}; |