arongnet 阅读(763) 评论(6)
说明 前一篇


所有的WinSock函数都使用sockaddr结构来传递地址信息,该结构定义如下:

struct sockaddr {
u_short sa_family; /* address family */ char sa_data[14];/* up to 14 bytes of direct address */
};

需要注意的是,socket并不只是为TCP服务的,它支持多种协议,而各种协议的地址格式又大相径庭。因此,我们在socket相关的API中不可能用同样的地址结构来描述地址信息,这里的sockaddr只是一个占位符的角色,我们在实际编程中必须替换乘合适的地址类型。

对于TCP/IP族,我们需要用的结构类型是sockaddr_in,该结构定义如下:

struct sockaddr_in {
short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8];
};
其中in_addr定义为:
struct in_addr {
        union {
                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { u_short s_w1,s_w2; } S_un_w;
                u_long S_addr;
        } S_un;
#define s_addr  S_un.S_addr
/* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2
/* host on imp */
#define s_net   S_un.S_un_b.s_b1
/* network */
#define s_imp   S_un.S_un_w.s_w2
/* imp */
#define s_impno S_un.S_un_b.s_b4
/* imp # */
#define s_lh    S_un.S_un_b.s_b3
/* logical host */
};

需要注意的是,这个sockaddr_in结构和sockaddr结构尺寸一样,我不清楚这是巧合还是必须遵守的一个准则。在我看来,这个结构不一样也是可以的。

我不打算一一介绍各个宏和域的含义,因为绝大多数人都不会记住这个。我只想简要介绍一下如何初始化这个地址信息

  1. sa_family:这个域描述了地址族信息。对于TCP/IP,这个值必须设置为AF_INET。有兴趣的朋友可以到WinSock.H中找找看它还支持哪些值。
  2. sin_port:端口号,对于我们提供的端口号,必须用htons转换一下再赋值,方法是:
    addr.sin_port = htons(port);
  3. sin_addr:地址,这里应该是IP地址。我们可以用inet_addr函数从点分式IP地址转换得到这个IP地址,方法是:
    addr.sin_addr.s_addr = inet_addr("100.101.102.103");
    注意:这里使用了宏s_addr,该宏的定义请参考上文。
  4. sin_zero:填充信息,必须设置为0。初学编程的人往往忘记初始化这个域,根据我的经验,这会导致函数调用失败。

由于API中都使用sockaddr结构,因此在使用时必须进行强制类型转换,并提供结构尺寸信息。下面就是accept函数调用时的例子:

sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sa_family = AF_INET;
int size = sizeof(addr);
SOCKET sd = accept(serversd, (sockaddr*)&addr, &size);

评论列表
somebody
re: socket 程序设计(2) - 地址
下一篇快出来啊
anotherone
同意
后面的不出来,谁知道作者整体水平怎么样
superreader
顶楼上的
楼上说的很有道理,
不过从登出来的两篇来看,还是有点条理的.
但是后面的谁知道写的出写不出.......
BOJIA
re: socket 程序设计(2) - 地址
我相信楼主是因为忙才没写下去的,
新的应该很快会出来.
目前的两篇来看,写的很好:)
馨荣家园
re: socket 程序设计(2) - 地址
嘿嘿,我这人就烦激将和怀疑,决定再过几天再写
babazhang
re: socket 程序设计(2) - 地址
:::需要注意的是,这个sockaddr_in结构和sockaddr结构尺寸一样,我不清楚这是巧合还是必须遵守的一个准则。在我看来,这个结构不一样也是可以的。
~~~~~~~~~~~~~~~~~~~~
下面这段代码说明两个结构长度一致是一种约定:
sockaddr_in name;
int namelen=sizeof(sockaddr_in);

struct sockaddrin {
    short sin_family; u_short sin_port; struct in_addr sin_addr;
}addr;

g_Server=socket(AF_INET,SOCK_STREAM,0);

name.sin_family=AF_INET;
name.sin_port=htons(5000);
name.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

bind(g_Server,(sockaddr*)(&name),namelen);
listen(g_Server,5);

namelen=sizeof(addr);
getsockname(g_Server,(sockaddr*)(&addr),&namelen);

此时调用GetLastError返回的错误信息是:
系统检测到在一个调用中尝试使用指针参数时的无效指针地址。

如果修改一行代码:
namelen=sizeof(addr)+8;
则程序OK。但namelen>sizeof(addr),又有谁敢这么做呢?

发表评论
切换编辑模式