一、基础知识。
1:套接字基础。
1,是通信端点的抽象。
2,在UNIX类系统中被当作是一种文件描述符。
3,套接字通信域。
域 | 描述 |
AF_INET | IPV4因特网域 |
AF_INET6 | IPV6因特网域 |
AF_UNIX | UNIX域 |
AF_UPSPEC | 未指定 |
4,套接字类型。
类型 | 描述 |
SOCK_DGRAM | 固定长度的,无链接的,不可考的报文传递 |
SOCK_RAW | IP协议的数据报接口 |
SOCK_SEQPACKET | 固定长度的,有序的,可靠的,面向连接的报文传递。 |
SOCK_STREAM | 有序的,可靠的,双向的,面向连接的字节流。 |
5,协议。
协议 | 描述 |
IPPROTO_IP | IPv4网际协议 |
IPPROTO_IPV6 | IPv6网际协议 |
IPPROTO_ICMP | 因特网控制报文协议(internet control message protocol) |
IPPROTO_RAW | 原始IP数据包协议 |
IPPROTO_TCP | 传输控制协议 |
IPPROTO_UDP | 用户数据报协议(user datagram protocol) |
6,创建一个原始套接字需要root权限。
2:套接字寻址和传输。
1,在网络中,进程标识由:计算机网络地址(找到计算机) + 计算机的端口号(找到特定进程) 组成。
2,大端和小端。
1)大端字节序:最大字节地址上 保存 最低有效字节。
2)小端字节序:最大字节地址上 保存 最高有效字节。
3)大部分系统使用小端字节序。但TCP/IP使用大端字节序。
3,域名系统( Domain name system,DNS)
4,网络信息服务( Network information service, NIS )
5,服务是由地址的端口号部分标示。每个服务由一个唯一的端口号支持。
6,章16的代码在阅读结束后,进行尝试性理解和自编写。
7,当异步IO中因为某种原因导致读/写阻塞,在阻塞条件不存在后,可以发送SIGIO信号来重新启用IO。步骤为:
1)建立套接字所有权。这样信号可以被传递到对应的进程。
2)通知套接字当IO操作不会阻塞时发送信号。
8,带外数据
1)含义:紧急数据。它有相对普通数据更高的优先级。
2)部分通信协议支持此功能。(可选功能)
3)当有新的紧急数据到来,旧有数据会被覆盖。
3:套接字选项。
1,套接字机制提供了 两个套接字选项接口:设置选项接口,查询选项接口。
4:UNIX域套接字。
1,IPC的一种:可以在同一计算机系统上运行的两个进程之间传递打开文件描述符。
1)用于同一台计算机的进程通信。
2)效率比因特网套接字高。因为它仅复制数据,无协议,无校验等复杂操作。
2,一些实例(未阅读)。
1)P508,借助UNIX域套接字轮询XSI消息队列。
2)P512,将地址绑定到UNIX域套接字。
3)P518,传送文件描述符:在两个进程之间传送打开文件描述符的技术非常有用。
3,sockaddr_un结构体。
1)可以将一个地址绑定到UNIX域套接字上。系统会使用该路径创建一个S_IFSOCK类型的文件。此文件无法打开。当关闭套接字时,必须显式的删除文件。
二、相关函数。
1:套接字。
1 创建一个套接字 int socket( int domain, int type, int protocol ); // 1 参数protocol:通常为0。表示使用默认协议。 2 禁止一个套接字IO int shutdown( int sockfd, int how ); // 1 参数how:SHUT_RD,SHUT_WR,SHUT_RDWR
2:寻址。
1 处理器字节序 和 网络字节序 的转换。 uint32_t htonl( uint32_t hostint32 ); uint16_t htons( uint16_t hostint16 ); uint32_t ntohl( uint32_t netint32 ); uint16_t ntohl( uint16_t netint16 ); // 1 h 主机,n 网络,l 长整数,s 短整数。 2 地址通用结构体。 struct socketaddr { sa_family_t sa_family; // address family char sa_data[]; // variable-length address ... } 3 网络地址的 二进制地址 和 文本字符串 相互转换 const char *inet_ntop( int domain, const void *restrict addr, char *restrict str, socklen_t size ); // 二进制地址 转换成 文本字符串 int inet_pton( int domain, const char *restrict str, void *restrict addr ); // 文本字符串 转换成 二进制地址。 4 查询主机信息。 struct hostent* gethostent( void ); void sethostent( int stayopen ); void endhostent( void ); struct hostent { char *h_name; // name of host char **h_aliases; // pointer to alternate host name array int h_addrtype; // address type int h_length; // length in bytes of address char **h_addr_list; // pointer to array of network address ... } 5 获取网络名字 和 网络编号。 struct netent* getnetbyaddr( uint32_t net, int type ); struct netent* getnetbyname( const char *name ); struct netent* getnetent( void ); void setnetent( int stayopen ); void endnetent( void ); struct netent{ char *n_name; // network char **n_aliases; // alternate network name array pointer int n_addrtype; // address type uint32_t n_net // network number ... } 6 协议名字和协议编号之间进行映射。 struct protoent* getprotobyname( const char *name ); struct protoent* getprotobynumber( int proto ); struct protoent* getprotoent( void ); void setprotoent( int stayopen ); void endprotoent( void ); struct protoent{ char *p_name; // protocol name char **p_aliases; // pointer to altername protocol name array int p_proto; // protocol number ... } 7 函数getservent顺序扫描服务数据库。 struct servent* getservbyname( const char *name, const char *proto ); struct servent* getservbyport( int port, const char *proto ); struct servent* getservent( void ); void setservent( int stayopen ); void endservent( void ) struct servent{ char s_name; // service name char **s_aliases; // pointer to alternate service name array int s_port; // port name char *s_proto; // name of protocol ... } 8 将主机名和服务名映射到一个地址。 int getaddrinfo( const char *restrict host, const char *restrict service, const struct addrinfo *restrict hint, struct addrinfo **restrict res ); void freeaddrinfo( struct addrinfo *ai ); struct addrinfo{ int ai_flags; // custemize behavior int ai_family; // address family int ai_socktype; // socket type int ai_protocol; // protocol socklen_t ai_addrlen; // length in bytes of address struct sockaddr *ai_addr; // address char *ai_canonname; // canonical name of host struct addrinfo *ai_next; // next in list ... } 9 将返回的错误码转换成错误信息 consr char *gai_strerror( int error ); 10 将地址转换成 主机名 和 服务名 int getnameinfo( const struct sockaddr *restrict addr, socklen_t alen, char *restrict host, socklen_t hostlen, char *restrict service, socklen_t servlen, int flags );
3:套接字 和 地址关联。
1 绑定 关联地址 和 套接字。 int bind( int sockfd, const struct sockaddr *addr, socklen_t len len ); // 1 地址必须有效,且格式匹配。 // 2 端口一般不小于1024.root权限用户除外。 // 3 一般不允许多重绑定。 2 查找 套接字对应的地址。 int getsockname( int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp ); 3 找到和套接字连接的对等方地址。 int getpeername( int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp ); 4 (请求服务端)建立连接。 int connect( int sockfd, const struct sockaddr *addr, socklen_t len ); // 1 参数addr:期望通信的服务器地址。 // 2 应用程序必须能够处理connect函数返回的错误。 5 (接收信息端)接收连接请求。 int listen( int sockfd, int backlog ); 6 获得连接请求,并建立连接。 int accept( int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len ); // 1 返回值:套接字描述符。
4:数据传输。
1 发送数据。 ssize_t send( int sockfd, const void *buf, size_t nbytes, int flags ); // 套接字必须已经连接。 // 1 返回成功,仅代表发送成功。接收错误不反馈。 ssize_t sendto( int sockfd, const void *buf, size_t nbytes, int flags, const struct sockaddr *destaddr, socklen_t destlen ); // 可以在无连接套接字上发送信息。 ssize_t sendmsg( int sockfd, const struct msghdr *msg, int flags, ); // 可以指定多重缓冲区传输数据。 2 接收数据。 ssize_t recv( int sockfd, void *buf, size_t nbytes, int flags ); // ssize_t recvfrom( int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen *restrict addrlen ); // 得到数据发送者的原地址 ssize_t recvmsg( int sockfd, struct msghdr *msg, int flags ); // 将接收数据送入多个缓冲区
5:套接字选项。
1 设置套接字选项。 int setsockopt( int sockfd, int level, int option, const void *val, socklen_t len ); // 1 参数level:标识选项应用协议。 2 查看当前选项。 int getsockopt( int sockfd, int level, int option, void *restrict val, socklen_t *restrict lenp ); // 1 参数level:标识选项应用协议。
6:带外数据。
1 TCP中,判断是否已经到达紧急数据标记位置。 int sockarmark( int sockfd ); // 1 返回值:1 在标记处,0 不在标记处,-1 出错
7: UNIX域套接字。
1 创建一对无命名的,相互连接的UNIX域套接字。(一般只用于UNIX域。) int socketpair( int domain, int type, int protocol, int sockfd[2] ); // 打开的为全双工管道。 // 1 返回值:0 成功,-1 出错。 2 sockaddr_un 结构体。 struct sockaddr_un { sa_family_t sun_family; // AF_UNIX char sun_path[108]; // pathname } // OS:linux and solaris。 Head file name is "sys/un.h";
三