from http://blog.chinaunix.net/uid-11765716-id-373941.html
2011.06
在Unix下,為使不同格式的地址能夠被傳入到套接字函數(shù),地址被強制轉(zhuǎn)換成通用的sockaddr表示:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[];//長度由實現(xiàn)定義
......
};
在Linux下,定義為:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
......
};
因特網(wǎng)地址定義在
struct n_addr
{
in_addr_t s_addr;//IPV4 addr
};
struct sockaddr_in
{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
有了以上定義,當我們需要使用socket地址時,比如connect函數(shù):
connect(int sockfd, const struct sockaddr *serv_addr,socklen_t addrlen);
就需要得到struct sockaddr格式的socket地址。
目前從APUE和Unix/Linux編程實踐看到兩種獲取的方法:
方法一(APUE):
通過調(diào)用函數(shù)getaddrinfo,在參數(shù)中返回struct addrinfo *類型鏈表,每個鏈節(jié)點中都包含了struct sockaddr類型成員,并將其用作為connect函數(shù)的參數(shù)。
其中struct addrinfo定義如下:
struct addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
從自己程序拷過來的部分代碼如下:
struct addrinfo *ailist,*aip;
struct addrinfo hint;
int sockfd,err;
hint.ai_flags = 0;
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
getaddrinfo(argv[1],"ruptime",&hint,&ailist);
for(aip = ailist;aip != NULL;aip = aip->ai_next)
{
if((sockfd = socket(aip->ai_family,SOCK_STREAM,0))<0)
err = errno;
if(connect_retry(sockfd,aip->ai_addr,aip->ai_addrlen)<0)
{
err = errno;
}
}
方法二(Linux/Unix編程實踐教程):
直接定義IPV4中socket 的地址格式sockaddr_in,然后調(diào)用函數(shù)gethostbyname,該函數(shù)返回struct hostent類型變量:
struct hostent
{
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
}
#define h_addr h_addr_list[0] /* for backward compatibility */
然后對定義的sockaddr_in變量中的struct in_addr sin_addr進行初始化為h_addr,如下方式:
struct hostent hp = gethostbyname("hostname");
struct sockaddr_in saddr;
bcopy((void*)hp->h_addr,(void*)&saddr.sin_addr,hp->h_length);
然后再對saddr中的其他成員進行賦值:
saddr.sin_port = "8080";
sassr.sin_family = AF_INET;
最后將得到初始化完成的struct sockaddr_in通過強制轉(zhuǎn)換為struct sockaddr來調(diào)用bind和connect等函數(shù):
bind(sock_id,(struct sockaddr *)&saddr,sizeof(saddr));
在這種方法中,也可以通過調(diào)用函數(shù)inet_network()系列函數(shù)對saddr.sin_addr進行賦值:
saddr.sin_addr.s_addr=inet_network("127.0.0.1");
詳細內(nèi)容清參考關(guān)于這一系列函數(shù)的man手冊。