若是你點進了這個文章,我建議你直接訪問 http://beej.us/guide/bgnet/ou... 學習socket編程,下面的資料是在讀CSAPP時的一些總結,已通過時。html
從programmer的角度,咱們們能夠把因特網當作一個世界範圍內的主機集合,知足如下要求:數據庫
主機集合被映射爲一組32位的ip地址編程
這組ip地址被映射爲一組稱爲因特網域名的標識符數組
主機上的進程可以經過鏈接和其餘主機上的進程通訊服務器
ip地址是一個32位無符號整數,網絡程序將ip地址存儲在以下結構中:網絡
#include <netinet/in.h> struct in_addr{ unsigned int s_addr; // big endian }
注意,tcp/ip爲任意整數數據定義了統一的網絡字節順序:大端字節順序。並提供瞭如下方法來在網絡和主機間進行字節順序的轉換:app
#include <netinet/in.h> /* 32位/16位主機轉網絡 */ unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); /* 32位/16位網絡轉主機 */ unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort);
ip地址還可使用點分十進制表示法,因此係統提供瞭如下函數實現無符號整數和點分十進制表示方法的轉換:dom
#include <arpa/inet.h> /* 點分表示->整數 * 若成功返回1,出錯返回0 */ int inet_aton(const char *cp,struct in_addr *inp); /* 整數->點分表示 * 返回指向點分十進制字符串的指針 */ char *inet_ntoa(struct in_addr in);
因特網定義了域名集合和ip地址集合之間的映射,這個映射是經過分佈在世界範圍內的數據庫來維護的。從概念上講,DNS數據庫由上百萬以下所示的主機條目結構組成,其中每條定義了一組域名和一組ip地址之間的映射。socket
#include <netdb.h> struct hostent{ char *h_name; //主機的官方域名 char **h_aliases; //別名的字符串數組 int addrtype; //地址類型,通常是AF_INET int h_length; //地址的字節長度 char **h_addr_list; //字符串數組 }
網絡程序經過調用下面的函數,從DNS數據庫檢索主機條目(for myself csapp 622)tcp
#include <netdb.h> /* 經過域名檢索 * 若失敗,返回NULL,並設置h_errno */ struct hostent *gethostbyname(const char *name); /* 經過ip地址檢索,第二個參數爲地址的字節長度 * 若失敗返回NULL,並設置h_errno */ struct hostent *gethostbyaddr(const char *addr,int len,0);
一個套接字是鏈接的一個端點,每一個套接字都有相應的地址,是由一個因特網地址和一個16位的整數端口組成,通常用 「地址:端口」來表示。通常來講,服務器的套接字端口一般是某個知名端口,而客戶端端口由內核自動分配。
一個鏈接是由兩端的套接字地址惟一肯定的。
套接字地址存放在以下所示的結構中:
#include <sys/socket.h> #include <netinet/in.h> /* 這個結構是爲了函數 connect、bind、accept而設計的 */ struct sockaddr{ unsigned short sa_family; //protocol family char sa_data[14]; //address data } /* 套接字地址結構 */ struct sockaddr_in{ unsigned short sin_family; //address family 通常爲AF_INET unsigned short sin_port; //大端表示的接口 struct in_addr sin_addr; //大端表示的ip地址 unsigned char sin_zero[8]; //pad to sizeof(struct sockaddr) }
客戶端使用函數的順序是 socket->connect
服務端使用函數的順序是 socket->bind->listen->accept
#include <sys/types.h> #include <sys/socket.h> /* 建立套接字描述符,成功返回描述符,失敗返回-1 * 通常老是這樣使用:clientfd=socket(AF_INET,SOCK_STREAM,0); */ int socket(int domin,int type,int protocol);
socket返回的描述符還不能用於讀寫,在客戶端和服務端要通過不一樣的處理,如前文的順序所示。
#include <sys/socket.h> /* 客戶端使用該函數創建與服務器的鏈接 * 成功,返回0;失敗,返回-1 */ int connect(int sockfd,struct sockaddr *serv_addr,int addrlen); /* 服務端使用該函數將服務器的地址和描述符鏈接起來 * addrlen是 sizeof(sockaddr_in) * 成功返回0,不然-1 */ int bind(int sockfd,struct sockaddr *my_addr,int addrlen); /* 服務端使用該函數將一個主動套接字改成監聽套接字 * 成功返回0,失敗-1 */ int listen(int sockfd,int backlog);