《APUE》读书笔记-第十六章网络IPC:套接字

来源:互联网 发布:广东省教育网络平台 编辑:程序博客网 时间:2024/05/18 16:16

通过网络套接字可以使得不同计算机上运行的进程相互通信。

1、创建套接字

#include <sys/socket.h>

Int socket( int domain, int type, int protocol);

注意:AF_LOCAL域是AF_UNIX的别名,AF_UNSPEC域可以代表任何域。

2、套接字通信是双向的,禁止套接字上的输入/输出

#include < sys/socket.h>

Int shutdown ( int sockfd, int how);

3、处理字节序和网络字节序之间的轮换:

#include< arpa/inet.h>

Uint32_t htonl (uint32_t hostint32);

Uint16_t htons(uint16_t hostint16);

Uint32_t ntohl (uint32_t netint32);

Uint16_t ntohs (uint16_t netint16);

4、地址格式:

Struct sockaddr{

       Sa_family_t sa_family;

       Char sa_data[];}

在Linux中,该结构定义如下:

Struct sockaddr{

       Sa_family_t sa_family;

       Char sa_data[14];};

而在FreeBSD中,该结构定义如下:

Struct sockaddr{

       Unsigned char sa_len;

       Sa_family_t sa_family;

       Char sa_data[14];};

因特网地址定义在<netinet/in.h>中。在IPV4因特网域(AF_INET)中,套接字地址用如下结构sokaddr_in表示:

Struct in_addr{

       In_addr_t s_addr;}

Struct sockaddr_in{

       Sa_family_t sin_family;

       In_port_t sin_port;

Struct in_addr sin_addr;

};

数据类型in_port_t 定义成uint16_t。数据类型in_addr_t 定义成uint32_t。这些整数类型在<sdint.h>中定义并指定了相应的位数。

与IPV4因特网域(AF_INET)相比较,IPV6因特网域(AF_INET6)套接字地址用如下结构sockaddr_in6表示:

Struct in6_addr{

       Uint8_t s6_addr[16];};

 Struct sockaddr_in6{

       Sa_family_t sin6_family;

       In_port_t sin6_port;

       Uint32_t sin6_flowinfo;

       Struct in6_addr sin6_addr;

       Uint32_t sin6_scope_id;}

 在Linux中,sockaddr_in 定义如下:

Struct sockaddr_in{

       Sa_family_t sin_family;

       In_port_t sin_port;

       Struct in_addr sin_addr;

       Unsigned char sin_zero[8];};

5、打印出能被人理解的地址格式函数

#include <arpa/inet.h>

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);

 6、找给定计算机的主机信息

#include<netdb.h>

Struct hostent * gethostent (void);

Void sethostent (int stayopen);

Void endhostent (void);

Struct hostent{

       Char * h_name;

       Char ** h_aliases;

       Int h_addrtype;

       Int h_length;

       Char ** h_addr_list;};

7、从接口获得网络名字和网络号:

#include<netdb.h.

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;

       Char ** n_aliases;

       Int n_addrtype;

       Uint32_t n_net;};

8、将协议名字和协议号采用以下函数映射

#include <netdb.h>

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;

       Char ** p_aliases;

       Int p_proto;};

9、从一个服务名映射到一个端口号,服务名

#include<netdb.h>

Struct servent * getservbyname (const char * name, const char * proto);

Struct servent * getservbyport (int port, const char * proto);

Struct servent * getservent( (void);

Void setervent (int stayopen);

Void endservent (void);

Struct servent{

       Char * s_name;

       Char ** s_aliases;

       Int s_port;

       Char * s_proto;};

 10、从一个主机名字和服务名字映射到一个地址

#include <sys/socket.h>

#include <netdb.h>

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;

       int ai_family;

       Int ai_socktype;

       Int ai_protocol;

       Socklen_t ai_addrlen;

       Struct sockaddr * ai_addr;

       Char * ai_canonname;

       Struct addrinfo * ai_next;};

11、gai_strerror将返回的错误码转换成错误消息

#include<netdb.h>

Const char * gai_strerror (int error);

 12、将地址转换成主机或者服务名

#include<sys/socket.h>

#include <netdb.h>

Int getnameinfo (const struct sockaddr * restrict addr, socklen_t alen, char * restrict host,socklen_t hostlen, char * restrict service, socklen_t servlen, unsigned int flags);   

13、将套接字与地址绑定

#include <sys/socket.h>

Int bind (int sockfd, const struct sockaddr * addr, socklen_t len );

对于使用的地址有一些限制:

A、 在进程所运行的机器上,指定的地址必须有效,不能指定一个其他机器的地址。

B、 地址必须和创建套接字时的地址族支持的格式相匹配。

C、 端口号必须不小于1024,除非该进程具有相应的特权(即为超级用户)。

D、一般只有套接字端点能够与地址绑定,尽管有些协议允许多重绑定。

14、获取绑定到一个套接字的地址:

#include <sys/socket.h>

Int getsockname ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict alenp);

注意:在调用getsockname之前,设置alenp为一个指向整数的指针,该整数指定缓冲区sockaddr的大小。返回时,该整数会被设置成返回地址的大小。如果该地址和提供的缓冲区长度不匹配,则将其截断而不报错。如果当前没有绑定到该套接字的地址,其结果没有定义。

15、获得对方地址:

#include <sys/socket.h>

Int getpeername ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict alenp);

注意:如果套接字已经和对方连接,调用getpeername来找到对方的地址。除了还会返回对方的地址之外,函数getpeername和getsockname一样。

16、建立连接          

#include <sys/socket.h>

Int connect ( int sockfd, const struct sockaddr * addr, socklen_t len);

17、listen函数

#include <sys/socket.h>

Int listen ( int sockfd,int backlog);

18、accept函数

#include <sys/socket.h>

Int accept ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict len);

19、send、sendto以及sendmsg信息发送函数

#include <sys/socket.h>

Ssize_t send ( int sockfd, const void * buf, size_t nbytes, int flags);

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);

Struct msghdr{

Void * msg_name;

Socklen_t msg_namelen;

Struct iovec * msg_iov;

Int msg_iovlen;

Void * msg_control;

Socklen_t msg_controllen;

Int msg_flags;

};

19、recv、recvfrom 与recvmsg接收数据函数

#include <sys/socket.h>

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_t  * restrict addrlen);

Ssize_t recvmsg ( int sockfd, struct msghdr * msg, int flags);

20、带外数据:TCP支持带外数据,但是UDP不支持。TCP仅支持一个字节的紧急数据,但是允许紧急数据在普通数据传递机制数据流之外传输。为了产生紧急数据,在三个send函数中任何一个指定MSG_OOB。如果带MSG_OOB标志传输字节超过一个时,最后一个字节被看作紧急数据字节。当接收到紧急数据时,那么改善信号SIGURG。

TCP支持紧急标记的概念:在普通数据流中紧急数据所在的位置。如果采用套接字选项SO_OOBINLINE,那么可以在普通数据中接收紧急数据。为帮助判断是否接收到紧急标记,可以使用函数sockatmark

#include <sys/socket.h>

Int sockatmark ( int sockfd);

当下一个要读的字节在紧急标志所标识的位置时,sockatmark返回1。当带外数据出现在套接字读取队列时,select函数会返回一个文件描述符并且拥有一个异常状态挂起。可以在普通数据流上接受紧急数据,或者在某个recv函数中MSG_OOB标志在其他队列数据之前接收紧急数据。TCP队列仅有一字节的紧急数据,如果在接收当前的紧急数据字节之前又有新的紧急数据到来,那么当前的字节会被丢弃。

21、在基于套接字异步I/O中,当能够从套接字中读取数据,或者套接字写队列中的空间变得可用时,可以安排发送信号SIGIO。通过两个步骤来使用异步I/O:

1) 建立套接字拥有者关系,信号可以被传送到合适的进程。

2) 通知套接字当I/O操作不会阻塞时发信号告知。

可以使用三种方式来完成第一个步骤:

A、 在fcntl使用F_SETOWN命令

B、 在ioctl中作用FIOSETOWN命令

C、 在ioctl中使用SIOCSPGRP命令。

     要完成第二个步骤,有两个选择:

A、 在fcntl中使用F_SETFL命令并且启用文件标志O_ASYNC。

B、 在ioctl中使用FIOASYNC


0 0