linux IPC socket

套接字是通讯端点的抽象

 

创建一个套接字

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
返回值:成功文件(套接字)描述符,失败-1
domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。 协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。 protocal:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等 它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

 

套接字通信是双向的。可以禁止一个套接字的I/O

#include <sys/socket.h>

int shutdown(int sockfd, int how);
返回值:成功0,出错-1
sockfd:套接字的描述符
how:三种SHUT_RD(0)关闭sockfd上的读功能
SHUT_WR(1)关闭sockfd上的写功能
SHUT_RDWR(2)关闭sockfd的读写功能

 

用来在处理器字节序和网络字节序之间实施转换的函数

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
返回值:以网络字节序表示的32位整数 uint16_t htons(uint16_t hostshort);
返回值:以网络字节序表示的16位整数
uint32_t ntohl(uint32_t netlong);
返回值:以主机字节序表示的32位整数
uint16_t ntohs(uint16_t netshort);
返回值:以主机字节序表示的16位整数

 h表示主机字节序,n表示网络字节序,l表示长整型,s表示短整型

 

打印出能被人理解而不是计算机所理解的地址格式。同时支持IPv4和IPv6地址

#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
返回值:成功地址字符串指针,出错NULL
af:地址簇,仅支持AF_INET和AF_INET6
src:来源地址结构指针
dst:接收转换后的字符串
size:保存文本字符串的缓冲区大小

int inet_pton(int af, const char *src, void *dst);
返回值:成功1,格式无效0,出错-1
af:地址簇,仅支持AF_INET和AF_INET6
src:转换的地址字符串
dst:转换后的地址结构指针

这个很常用,所有使用socket都需要用这两个函数转换,p应该是protocol,n应该是net吧。

例子

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/ioctl.h>
 5 #include <stdlib.h>
 6 #include <netdb.h>
 7 #include <arpa/inet.h>
 8 #include <netinet/in.h>
 9 #include <string.h>
10 
11 int main(int argc, char *argv[])
12 {
13         char dst[100];
14         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
15 
16         struct sockaddr_in serv;
17         memset(&serv, 0 ,sizeof(struct sockaddr_in));
18 
19         serv.sin_family = AF_INET;
20         serv.sin_port = htons(5555);
21 
22         if((inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr)) == 0)
23                 printf("inet_pton error\n");
24         if((inet_ntop(AF_INET, &serv.sin_addr.s_addr, dst, sizeof(dst))) == NULL)
25                         printf("inet_ntop error\n");
26         printf("dst=%s,sizeof(dst)=%d\n", dst, sizeof(dst));
27 
28         bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));
29         listen(sockfd, 15);
30         return 0;
31 }
inet_pton

  

找到给定计算机系统的主机信息

#include <netdb.h>

struct hostent *gethostent(void);
返回值:成功返回指针,出错NULL

void sethostent(int stayopen);
stayopen:true就是TCP,否则UDP
void endhostent(void);

 

能够采用一套相似的接口来获得网络名字和网络编号

#include <netdb.h>

struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent *getnetent(void);
返回值:成功返回指针,出错NULL

void setnetent(int stayopen);
void endnetent(void);

 

在协议名字和协议编号之间进行映射

#include <netdb.h>

struct protoent *getprottobyname(const char *name);
struct protoent *getprotobynumber(int proto);
struct protoent *getprotoent(void);
返回值:成功返回指针,出错NULL

void setprotoent(int stayopen);
void endprotoent(void);

 

服务是由地址的端口号部分表示的,每个服务由一个唯一的众所周知的端口号来支持。可以使用getservbyname将一个服务名映射到一个端口号,使用函数getservbyport将一个端口号映射到一个服务名,使用函数getservent顺序扫描服务数据库。

#include <netdb.h>

struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
struct servent *getservent(void);
返回值:成功返回指针,出错NULL

void setservent(int stayopen);
void endservent(void);

 

将一个主机和一个服务名映射到一个地址

#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *node, const char *service,
                        const struct addrinfo *hints,
                        struct addrinfo **res);
返回值:成功0,出错非0错误码
node:向一个主机名(域名)或者地址串(IPv4的点分十进制串或者IPv6的16进制串)。
service:指向一个服务名或者10进制端口号数串。
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构的指针
res:指向的变量已被填入一个指针,它指向的是由其中的ai_next成员串联起来的addrinfo结构链表
void freeaddrinfo(struct addrinfo *res);

addrinfo结构体

struct addrinfo
{ 
    int ai_flags; 
    int ai_family; //AF_INET,AF_INET6,UNIX etc
    int ai_socktype; //STREAM,DATAGRAM,RAW
    int ai_protocol; //IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc
    size_t ai_addrlen;//length of ai_addr
    char* ai_canonname; //full hostname 
    struct sockaddr* ai_addr; //addr of host
    struct addrinfo* ai_next;
}

 

错误码需要调用函数来转换成错误消息

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

const char *gai_strerror(int errcode);

 

将一个地址转换成一个额主机名和一个服务名

#include <sys/socke.h>
#include <netdb.h>

int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                        char *host, socklen_t hostlen,
                        char *serv, socklen_t servlen, int flags);
返回值:成功0,出错非0值
sa:指向包含协议地址的套接口地址结构,它将会被转换成可读的字符串,
salen:结构的长度,这个结构长度通常由accept、recvfrom、getsockname、getpeername
host:主机字符串
hostlen:长度
serv:服务器字符串
servlen:长度
flags:标志位可以有多个用与或

 sockaddr结构体

struct sockaddr
{
  unsigned short sa_family;  /*addressfamily,AF_xxx*/
  char sa_data[14];       /*14bytesofprotocoladdress*/
};

 

16-9.c

  1 #include "apue.h"
  2 #if defined(SOLARIS)
  3 #include <netinet/in.h>
  4 #endif
  5 #include <netdb.h>
  6 #include <arpa/inet.h>
  7 #if defined(BSD)
  8 #include <sys/socket.h>
  9 #include <netinet/in.h>
 10 #endif
 11 
 12 void print_family(struct addrinfo *aip)
 13 {
 14     printf(" family ");
 15     switch(aip->ai_family) {
 16     case AF_INET:
 17         printf("inet");
 18         break;
 19     case AF_INET6:
 20         printf("inet6");
 21         break;
 22     case AF_UNIX:
 23         printf("unix");
 24         break;
 25     case AF_UNSPEC:
 26         printf("unspecified");
 27         break;
 28     default:
 29         printf("unknown");
 30     }
 31 }
 32 
 33 void print_type(struct addrinfo *aip)
 34 {
 35     printf(" type ");
 36     switch(aip->ai_socktype) {
 37     case SOCK_STREAM:
 38         printf("stream");
 39         break;
 40     case SOCK_DGRAM:
 41         printf("datagram");
 42         break;
 43     case SOCK_SEQPACKET:
 44         printf("seqpacket");
 45         break;
 46     case SOCK_RAW:
 47         printf("raw");
 48         break;
 49     default:
 50         printf("unknown (%d)", aip->ai_socktype);
 51     }
 52 }
 53 
 54 void print_protocol(struct addrinfo *aip)
 55 {
 56     printf(" protocol ");
 57     switch(aip->ai_protocol) {
 58     case 0:
 59         printf("default");
 60         break;
 61     case IPPROTO_TCP:
 62         printf("TCP");
 63         break;
 64     case IPPROTO_UDP:
 65         printf("UDP");
 66         break;
 67     case IPPROTO_RAW:
 68         printf("raw");
 69         break;
 70     default:
 71         printf("unknown (%d)", aip->ai_protocol);
 72     }
 73 }
 74 
 75 void print_flags(struct addrinfo *aip)
 76 {
 77     printf("flags");
 78     if(aip->ai_flags == 0) {
 79         printf(" 0");
 80     } else {
 81         if(aip->ai_flags & AI_PASSIVE)
 82             printf(" passive");
 83         if(aip->ai_flags & AI_CANONNAME)
 84             printf(" canon");
 85         if(aip->ai_flags & AI_NUMERICHOST)
 86             printf(" numhost");
 87         if(aip->ai_flags & AI_NUMERICSERV)
 88             printf(" numserv");
 89         if(aip->ai_flags & AI_V4MAPPED)
 90             printf(" v4mapped");
 91         if(aip->ai_flags & AI_ALL)
 92             printf(" all");
 93     }
 94 }
 95 
 96 int main(int argc, char *argv[])
 97 {
 98     struct addrinfo *ailist, *aip;
 99     struct addrinfo hint;
100     struct sockaddr_in *sinp;
101     const char *addr;
102     int err;
103     char abuf[INET_ADDRSTRLEN];
104 
105     if(argc != 3)
106         err_quit("usage: %s nodename service", argv[0]);
107     hint.ai_flags = AI_CANONNAME;
108     hint.ai_family = 0;
109     hint.ai_socktype = 0;
110     hint.ai_protocol = 0;
111     hint.ai_addrlen = 0;
112     hint.ai_canonname = NULL;
113     hint.ai_addr = NULL;
114     hint.ai_next = NULL;
115     if((err = getaddrinfo(argv[1], argv[2], &hint, &ailist)) != 0)
116         err_quit("getaddrinfo error %s", gai_strerror(err));
117     for(aip = ailist; aip != NULL; aip = aip->ai_next) {
118         print_flags(aip);
119         print_family(aip);
120         print_type(aip);
121         print_protocol(aip);
122         printf("\n\thost %s", aip->ai_canonname?aip->ai_canonname:"-");
123         if(aip->ai_family == AF_INET) {
124             sinp = (struct sockaddr_in *)aip->ai_addr;
125             addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf, INET_ADDRSTRLEN);
126             printf(" address %s", addr?addr:"unknown");
127             printf(" port %d", ntohs(sinp->sin_port));
128         }
129         printf("\n");
130     }
131     exit(0);
132 }
getaddrinfo

 

转载于:https://www.cnblogs.com/ch122633/p/8074110.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值