套接字是通訊端點的抽象 創建一個套接字 套接字通信是雙向的。可以禁止一個套接字的I/O 用來在處理器位元組序和網路位元組序之間實施轉換的函數 h表示主機位元組序,n表示網路位元組序,l表示長整型,s表示短整型 列印出能被人理解而不是電腦所理解的地址格式。同時支持IPv4和IPv6地址 找到給定電腦系統的 ...
套接字是通訊端點的抽象
創建一個套接字
#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