分类: LINUX
2011-06-15 21:52:46
在Unix下,为使不同格式的地址能够被传入到套接字函数,地址被强制转换成通用的sockaddr表示:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[];//长度由实现定义
......
};
在Linux下,定义为:
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
......
};
因特网地址定义在
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函数:
connect(int sockfd, const struct sockaddr *serv_addr,socklen_t addrlen);
就需要得到struct sockaddr格式的socket地址。
目前从APUE和Unix/Linux编程实践看到两种获取的方法:
方法一(APUE):
通过调用函数getaddrinfo,在参数中返回struct addrinfo *类型链表,每个链节点中都包含了struct sockaddr类型成员,并将其用作为connect函数的参数。
其中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,然后调用函数gethostbyname,该函数返回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通过强制转换为struct sockaddr来调用bind和connect等函数:
bind(sock_id,(struct sockaddr *)&saddr,sizeof(saddr));
在这种方法中,也可以通过调用函数inet_network()系列函数对saddr.sin_addr进行赋值:
saddr.sin_addr.s_addr=inet_network("127.0.0.1");
详细内容清参考关于这一系列函数的man手册。