UNIX程式設計隨筆 三十四 socket位址

2021-08-26 14:31:52 字數 4493 閱讀 6063

unix程式設計隨筆(三十四)socket位址

2023年04月22日

不同的處理器架構對於大於乙個位元組的資料型別的各個位元組如何存放存在差別,分為

[b]大端[/b]:高位位元組到低位位元組存放位址為從低到高,也就是對於乙個4位元組的整數比如0x01020304,在記憶體的起始位址為0x00000000,則0x00000000存放0x01,0x00000001存放0x02,0x00000002存放0x03,0x00000003存放0x04。

[b]小端[/b]:高位位元組到低位位元組存放位址為從高到低,也就是對於乙個4位元組的整數比如0x01020304,在記憶體的起始位址為0x00000000,則0x00000000存放0x04,0x00000001存放0x03,0x00000002存放0x02,0x00000003存放0x01。

tcp/ip協議使用大端位元組序,因此在小端系統(linux,windows,freebsd)上必須進行轉換。

分別呼叫以下函式完成本機位元組序到網路位元組序的轉換:

uint32_t htonl(uint32_t hostint32); //將本地位元組序的32位整數轉換成網路位元組序的32位整數

uint16_t htons(uint16_t hostint16); //將本地位元組序的16位整數轉換成網路位元組序的16位整數

uint32_t ntohl(uint32_t netint32); //將網路位元組序的32位整數轉換成本地位元組序的32位整數

uint16_t ntohs(uint16_t netint16); //將網路位元組序的16位整數轉換成本地位元組序的16位整數

對於不同的協議族有不同的位址,posix定義了通用的位址資料結構:

struct sockaddr

; ipv4的位址(af_inet)結構定義如下:

struct in_addr

; struct sockaddr_in

; ipv6的位址(af_inet6)結構定義如下:

struct in6_addr ;

struct sockaddr_in6 ;

呼叫const char *inet_ntop(int domain, const void *restrict addr,char *restrict str, socklen_t size);將網路位元組序的二進位制位址轉換成可讀的字串,只支援af_inet以及af_inet6協議。str用來接收返回的字串,對於af_inet可以使用inet_addrstrlen分配緩衝區,而對於af_inet6來說可以使用inet6_addrstrlen。

呼叫int inet_pton(int domain, const char *restrict str, void *restrict addr);將可讀的字串位址轉換成網路位元組序的二進位制位址,只支援af_inet以及af_inet6協議。對於af_inet,addr為32位,而對於af_inet6,addr為128位。

呼叫以下函式取得本機知道的所有主機資訊:

struct hostent *gethostent(void);

void sethostent(int stayopen);

void endhostent(void);

依次呼叫gethostent可以取得本機知道的所有主機資訊,返回的struct hostent結構定義如下:

struct hostent ;

呼叫以下函式可以得到網路名以及網路號:

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結構定義如下:

struct netent ;

呼叫以下函式得到協議名以及協議號:

struct protoent *getprotobyname(const char *name);

struct protoent *getprotobynumber(int proto);

struct protoent *getprotoent(void);

void setprotoent(int stayopen);

void endprotoent(void);

返回的struct protoent結構定義如下:

struct protoent ;

呼叫以下函式得到網路服務(services)資訊:

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結構定義如下:

struct servent ;

int getaddrinfo(const char *restrict host,

const char *restrict service,

const struct addrinfo *restrict hint,

struct addrinfo **restrict res);

void freeaddrinfo(struct addrinfo *ai);

可以傳入主機名或者服務名,也可以兩個都傳入(不傳的使用null即可),host可以傳入主機名也可以傳入以小數點.分隔的ip位址。service可以傳入服務名也可以傳入十進位制埠號數串。res返回struct addrinfo結構列表,struct addrinfo結構定義如下:

struct addrinfo ;

引數hint用來對返回的位址進行過濾,僅可以設定ai_family, ai_flags, ai_protocol以及 ai_socktype欄位的值進行過濾。ai_flags取值如下:

ai_addrconfig 查詢所有位址型別(ipv4,ipv6)

ai_canonname ai_canonname返回正式主機名(非別名)

ai_numerichost 如果hint指定此標誌則host只能傳入小數點分隔的ip位址,不用進行主機名到ip的轉換

ai_numericserv 如果hint指定此標誌則host只能傳入十進位制埠號數串,不用進行服務名到埠號的轉換

ai_passive 返回的ai_addr設定為inaddr_any(ipv4)或者in6addr_any_init(ipv6),如果沒有指定則為迴路(loopback)位址。

如果getaddrinfo[b]失敗則返回錯誤號(函式返回值[/b]),必須呼叫const char *gai_strerror(int error);取得錯誤資訊。

反之可以呼叫getnameinfo根據網路位址得到對應的主機名以及服務名:

int getnameinfo(const struct sockaddr *sa, socklen_t salen,

char *host, size_t hostlen, char *serv, size_t servlen,

int flags);

flags取值如下:

ni_dgram 返回udp服務

ni_namereqd 找不到主機名則返回錯誤

ni_nofqdn 對於本地主機只返回fqdn中的主機名部分(fqdn帶有網域名稱)

ni_numerichost 返回小數點分隔的ip位址

ni_numericserv 返回十進位制的數串服務埠

呼叫int bind(int sockfd, const struct sockaddr *addr, socklen_t len);繫結乙個socket到乙個網路位址上,addr指定的網路位址必須為本機上的網路位址,而且網路位址對應的協議必須跟建立socket使用的協議匹配,如果位址中的埠號小於1024則只有擁有root許可權的程序才能繫結成功,另外一般來說乙個位址只能繫結到乙個socket上(除非有的協議支援多重繫結)。[b]呼叫listen以及connet函式之前如果對socket沒有呼叫bind繫結網路位址,則listen以及connect會自動繫結乙個隨機的埠給socket[/b]。bind函式一般在伺服器端呼叫,繫結socket到乙個眾所周知的埠供客戶端連線,而客戶端一般不需要呼叫bind函式,由connet函式自動繫結乙個即可。

呼叫int getsockname(int sockfd, struct sockaddr*restrict addr, socklen_t *restrict alenp);得到socket本地端對應的位址資訊。

呼叫int getpeername(int sockfd, struct sockaddr*restrict addr, socklen_t *restrict alenp);得到socket連線的對端socket的位址資訊。

unix 程式設計隨筆

該篇為本人在工作程式設計中的一些心得體會,願初入此道的小生們少走些彎路,我只願面朝大海,春暖花開。持續更新 c程式設計 譚浩強 編著 c 物件導向程式設計 譚浩強 編著 unix環境高階程式設計 等 權威 譚浩強的這兩本教科書,權威中的權威,我每每翻開查詢,都會有新的發現,覺得在某些方面蠻強大的,因...

socket程式設計(十四)

1 無連線 2 基於訊息的資料傳輸服務 3 不可靠 4 一般情況下udp更加高效 1 udp保溫可能丟失,重複 2 udp報文可能亂序 3 udp缺乏流量控制 4 udp協議資料報文截斷 5 recvfrom返回0,不代表連線關閉,因為udp是無連線的 6 icmp非同步錯誤 上面 server.c...

C 高階程式設計三十四天 陣列作為引數

陣列作為引數 陣列可以作為引數傳遞給方法,也可以從方法中返回 要返回乙個陣列 只需要把陣列宣告為返回型別.static void main string args int array printarray new int printarray array static void printarray...