unix网络编程
tcp/udp
socket
打开一个网络连接
int socket (int family , int type ,int protocol)
family :协议族 , type : 套接字类型 , protocol :协议类型常值
return :套接字描述符sockfd
famliy : AF_INET(IPv4) AF_INET6(IPv6) AF_LOCAL AF_ROUTE
type : SOCK_STREAM(字节流套接字) SOCK_DGRAM(数据报套接字) SOCK_SEQPACKET(有序分组套接字) SOCK_RAW(原始套接字)
protocol : IPPROTO_TCP(TCP传输协议) IPPROTO_UDP(UDP传输协议) IPPROTO_SCTP(SCTP传输协议)
connect
TCP客户用connect来建立与TCP服务器的链接
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd : 套接字描述符 , addr : 指向套接字地址结构的指针 , addrlen : 该结构的大小
成功为0 , 出错则为-1
bind
把一个本地协议地址赋予一个套接字(协议地址是32位的IPv4地址或128位的IPv6地址与TCP或UDP的端口号的组合等)–>(绑定一个端口到套接字)
服务器在启动时捆绑它众所周知的端口。如果一个TCP客户或服务器未曾调用bind绑定一个端口,当调用connect或listen时,内核就要为相应套接字选一个临时端口。
int bind (int sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
sockfd : 套接字描述符 , myaddr : 指向特定协议地址地址结构的指针 , addrlen : 该结构的大小
输出 成功为0 , 出错则为-1
listen
本函数通常应该在调用socket和bind之后,并且在accept之前
作用 : listen仅由TCP调用
(1)把一个未连接的套接字转换为一个被动套接字
(2)本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数
int listen (int sockfd, int backlog);
sockfd : 套接字描述符 , backlong : 相应套接字排队的最大连接个数
输出 成功为0 , 出错则为-1
accept
由TCP服务器调用,用于从已完成链接队列队头返回下一个已完成的链接
int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
sockfd : 套接字描述符 , cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址
输出 成功为已连接套接字描述符 , 出错则为-1
accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP链接
getsockname getpeername
getsockname 返回与某个套接字关联的本地协议地址
getpeername 返回与某个套接字关联的外地协议地址
int getsockname (int sockfd, struct sockaddr * localaddr, socklen_t addrlen);
int getsockname (int sockfd, struct sockaddr * peerladdr, socklen_t addrlen);
这两个函数都装填由localaddr或peerladdr指针所指的套接字地址结构,协议地址返回到这里
输出 成功为0 , 出错则为-1
shudown
可以半关闭链接
int shutdown(int sockfd , int howto)
getsockopt setsockopt
获取和设置影响套接字的选项
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
sockfd必须指向一个打开的套接字描述符,level(级别)指定系统中解析选项的代码或为通用套接字代码,或为某个特定于协议的代码(例如IPv4、IPv6、TCP或SCTP)
optval是一个指向某个变量(optval)的指针,setsockopt从optval中取得选项代设置的新值,getsockopt则把已获取的选项当前值存放到*optval中。*optval的大小由最后一个参数指定。
recvfrom sendto
读取数据,发送数据类似于read,write
ssize_t recvfrom(int socketfd , void *buff , size_t nbtyes , int flages , struct socaddr * from , socklen_t *addrlen);
ssize_t sendto(int socketfd , void *buff , size_t nbtyes , int flages , struct socaddr * to , socklen_t *addrlen);
前三个参数sockfd , buff , nbytes 等同于read 与 write :
描述符 , 指向读入或者写出区域的指针 , 读写字节数
flag先置0
sendto 的 to 指向 IP地址及端口号的套接字地址结构,大小由addrlen指定
recvfrom 的 from 指向该函数在返回时填写数据发送者的套接字,大小由addrlen指定
输出 成功为读或者写的字节数 , 出错则为-1
sctp系列
sctp_bindx
该函数允许SCTP套接字捆绑一个特定地址子集;
int sctp_bindx(int sockfd, const struct sockaddr *addr, int addrcnt, int flags);
sockfd: socket函数返回的描述符;
addrs: 一个指向紧凑的地址列表的指针;
addrcnt: 指定地址个数;
flags: 指导sctp_bindx调用
输出 成功为0 , 出错则为-1
sctp_bindx调用既可用于已绑定的套接字,也可用于未绑定的套接字
未绑定套接字:sctp_bindx调用将把给定的地址集合捆绑到其上;
已绑定套接字:若指定SCTP_BINDX_ADD_ADDR则把额外的地址加入到套接字描述符,若指定SCTP_BINDX_REM_ADDR则从套接字描述符的已加入地址中移除给定的地址
sctp_connectx
函数用于连接到一个多宿对端主机
int sctp_connectx(int sockfd, const struct sockaddr *addr, int addrcnt);
addrs: 指定addrcnt个全部属于同一对端的地址,是一个紧凑的地址列表,SCTP栈使用其中一个或多个地址建立关联
输出 成功为0 , 出错则为-1
sctp_getpaddrs
获取对端的所有地址
当SCTP使用getpeername时将仅仅返回主目的地址;
若需要直到对端的所有地址,则应该使用sctp_getpaddrs函数
int sctp_getpaddrs(int sockfd, sctp_assoc_t id, struct sockaddr **addrs);
id: 是一到多式套接字的关联标识,而一到一式套接字会忽略该字段
addrs: 地址指针,内容由本函数动态分配并填入的紧凑的地址列表
输出 成功为存放在addrs中的对端地址数 , 出错则为-1
注意: 使用完后,应使用sctp_freepaddrs释放分配的资源
sctp_freepaddrs
函数释放由sctp_getpaddrs函数分配的资源
void sctp_freepaddrs(struct sockaddr *addrs);
addrs: 指向sctp_getpaddrs的返回的数组的指针
sctp_getladdrs
用于获取属于某个关联的本地地址
当需要知道一个本地端点究竟在使用哪些本地地址时,可以调用本函数
int sctp_getladdrs(int sockfd, sctp_addoc_t id, struct sockfaddr **addrs);
id: 一到多式套接字的关联标识,而一到一式套接字则会将其忽略
addrs: 地址指针,内容为本函数动态分配并填入的紧凑的地址列表
输出 成功为存放在addrs中的本端地址数 , 出错则为-1
注意: 使用完后,应使用sctp_freelpaddrs释放分配的资源
sctp_freelpaddrs
释放由sctp_getlpaddrs分配的资源
void sctp_freeladdrs(struct sockaddr *addrs);
addr: sctp_getlpaddrs返回的地址数字的指针
sctp_sendmsg
能够控制SCTP的各种特性
ssize_t sctp_sendmsg(int sockfd, const void *msg, size_t msggz,
const struct sockaddr *to, socklen_t tolen,
uint32_t ppid,
uint32_t flags, uint16_t stream,
uint32_t timetolive, uint32_t context);
msg: 指向一个长度为msgsz字节的缓冲区,将其中的内容发给对端端点to
to: 内容发送的地点
tolen: to中的地址长度
ppid: 将随数据块传递的净荷协议标识符
flags: 传递给SCTP栈,用以标识任何SCTP选项
stream: 指定一个SCTP流号
timetolive: 以毫秒为单位的消息的生命期,0为无限
context: 指定可能有的用户上下文;用户上下文把通过消息通知机制收到的某次失败的消息发送与某个特定于应用的本地上下文关联
输出 成功为写的字节数 , 出错则为-1
sctp_recvmsg
获取对端的地址及获取通常伴随recvmsg调用返回的msg_flags参数,可获取sctp_sndrcvinfo
ssize_t sctp_recvmsg(int sockfd, void *msg, size_t msgsz,
struct sockaddr *from, socklen_t *fromlen,
struct sctp_sndrcvinfo *sinfo,
int *msg_flags);
msg: 指向一个长度为msgsz字节的缓冲区
from: 内容发送的地点
fromlen: to中的地址长度
msg_flags: 存放可能有的消息标志
输出 成功为读的字节数 , 出错则为-1
注意:若应用进程要接收sctp_sndrcbinfo,则要使用SCTP_EVENTS套接字选项预订sctp_data_io_event
sctp_opt_info
是为无法为SCTP使用getsockopt函数的那些实现提供的
允许套接字选项中使用出入变量的系统,将一个参数重新打包到合适的getsockopt调用中的库函数
int sctp_opt_info(int sockfd, sctp_assoc_t assoc_id, int opt,void *arg, socklen_t *siz);
assoc_id: 给出可能存在的关联标识
opt: SCTP的套接字选项
arg: 套接字选项参数
siz: 存放参数的大小
输出 成功为0 , 出错则为-1
sctp_peeloff
从一个一到多时套接字中抽取一个关联,,构成单独一个一到一式套接字
把一到多式套接字的sockfd和待抽取的关联标识id传递给函数调用
int sctp_peeloff(int sockfd, sctp_assoc_t id);
返回: 新的套接字描述符,即一个与所请求关联对应的一到一式套接字描述符
域名
gethostbyname
返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针
struct hostent *gethostbyname(const char * hostname);
返回值的结构体:
struct hostent
{
char FAR * h_name;
char FAR * FAR * h_aliases;
short h_addrtype;
short h_length;
char FAR * FAR * h_addr_list;
};
h_name成员是我们正在查询的主机的官方名字。也就是主机的权威名字。如果我们提供了一个别名,或是不带域名的主机名,那么这个成员就会描述我们要查询的正确名字
h_aliases成员是我们查询的主机名的别名数组。这个列表的结尾被标记为NULL指针
在成员h_addrtype中返回的值为AF_INET。然而,因为IPv6已经完全实现,名字服务器也会返回IPv6地址。当这种情况发生时,h_addrtype就会在合适的时候返回AF_INET6。
h_addrtype值的上的就是表明在列表h_addr_list中的地址格式
h_length成员这个值与h_addrtype成员相关。对于当前的TCP/IP协议版本(IPv4),这个成员的值总是为4,表明4个字节的IP地址。然而,当IPv6实现时,这个值将会是16,并且返回IPv6地址
h_addr_list成员当执行一个名字到IP地址的转换时,这个成员就会成为我们最重要的信息。当h_addrtype成员包含AF_INET时,这个数组中的每一个指针指向一个4字节的IP地址。这个列表的结尾被标记为NULL指针
返回 :成功时为非空指针,出错则为NULL且设置h_errno
gethostbyaddr
由一个二进制的IP地址找到主机名,与gethostbyname恰好相反
struct hostent *gethostbyaddr(const char * addr , socklen_t len , int family);
len为addr大小,family为协议族
返回 :成功时为非空指针,出错则为NULL且设置h_errno
getservbyname getservbyport
如果我们在代码中通过其名字而不是端口号来指代一个服务,而且从名字到端口号的映射关系保存在一个文件中,那么即使端口号发生变动我们修改那个映射文件即可,而不必重新编译程序
getservbyname用于根据给定名字查找相应的端口
getservbyport用于根据端口号和可选协议查找相应服务
struct servent *getservbyname(const char * servname , const char *protoname);
struct servent *getservbyport(int port , const char *protoname)
返回值的结构体:
struct servent{
char *s_name; //正式名称
char **s_aliases; //别名
int s_port; //端口号
char *s_proto; //协议
}
servname服务名
port端口号
protoname为可选协议
返回 :成功时为非空指针,出错则为NULL
getaddrinfo
gethostbyname和getservbyname只适用于IPv4
getaddrinfo可以IPv4和IPv6,能够处理名字到地址以及服务到端口这两种转换
int getaddrinfo(const char *hostname, const char *service,const struct addrinfo *hints, struct addrinfo **result);
通过result指针返回一个指向addrinfo结构链表的指针
struct addrinfo {
int ai_flags; /* 标志位 */
int ai_family; /* 协议族: AF_INET|AF_INET6|AF_UNSPEC... */
int ai_socktype; /* sock类型: SOCK_DGRAM|SOCK_STREAM */
int ai_protocol; /* 协议类型: IPPROTO_TCP|IPPROTO_UDP... */
socklen_t ai_addrlen; /* 地址结构长度 */
char *ai_canonname; /* host的正式名称 */
struct sockaddr *ai_addr; /* 地址结构 */
struct addrinfo *ai_next; /* result是个链表结构,ai_next指向下一个addrinfo */
}
hostname:主机名或IP地址字符串(IPv4的点分十进制/IPv6的16进制数串),如果为NULL,则表示本地主机
service:服务名称或端口号字符串,如果为NULL,则返回所有可用的套接字地址结构
hints:用于指定期望的套接字类型、协议及其他选项的addrinfo结构体指针,也可以为空指针(指定查找要求)
result:用于存储结果的addrinfo结构体指针(返回的结果链表)
成功返回0,出错为非0
freeaddrinfo
释放由getaddrinfo返回的addrinfo结构
void freeaddrinfo(struct addrinfo *ai);
ai应指向第一个addrinfo结构
gai_strerror
由getaddrinfo返回的非0错误值的名字和含义gai_strerror作为它的参数返回一个指向信心串的指针
const char *gai_strerror(int error);
getnameinfo
它是getaddrinfo的互补函数,它以一个套接字地址结构为参数,返回其中的主机的一个字符串和描述其中服务的另一个字符串
int getnamefo(const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen,char *serv, socklen_t servlen, int flags);
成功返回0,出错为非0
host_serv
该函数初始化一个hints结构,可被getaddrinfo调用
struct addrinfo *host_serv(const char *hostname , const char *service , int family , int socktype);
成功返回指向addrinfo结构的指针,出错为NULL
tcp_connect
创建一个TCP套接字并连接到一个服务器
int tcp_connect(const char *hostname , cosnt char*service);
成功则返回连接的套接字描述符,出错则不返回
tcp_listen
创建一个TCP套接字,给它捆绑服务器的众所周知端口,并允许接受外来的链接请求
int tcp_listen(const char *hostname , const char *service ,socklen_t *addrlenp)
addrlenp用于返回套接字地址结构的大小
成功则返回连接的套接字描述符,出错则不返回
udp_client
用于创建一个未连接UDP套接字
int udp_client(const char *hostname, const char *serv, void **saptr, socklen_t *lenp);
hostname 要连接的主机名
service 要连接的端口号
saptr 指向套接字地址结构的指针,函数会把目的IP和端口放在这个结构中
lenp saptr的大小
成功则返回连接的套接字描述符,出错则不返回
udp_connect
创建一个已连接UDP套接字
int udp_connect(const char *hostname , const char *service);
成功则返回连接的套接字描述符,出错则不返回
udp_server
UDP服务端调用,和tcp_linten类似
int udp_server(const char *hostname , const char *service , socklen_t *lenptr);
成功则返回连接的套接字描述符,出错则不返回
unix域
sockpair
socketpair函数创建两个随后连接起来的套接字。本函数仅仅适应于unix域套接字
#include <sys/socket.h>
int socketpair(int family,int type,int protocol,int sockfd[2]);
family参数必须为AFLOCAL,protocol参数必须为0.type参数既可以是SOCKSTREAM。要创建的两个套接字描述符作为sockfd[0]和sockfd[1]返回