全部博文(842)
分类: LINUX
2012-05-17 16:26:25
struct sockaddr_in {
short int sin_family; /* 通信类型 */
unsigned short int sin_port; /* 端口 */
struct in_addr sin_addr; /* Internet 地址 */
unsigned char sin_zero[8]; /* 与sockaddr结构的长度相同*/
};
struct in_addr {
unsigned long s_addr; // 32 位IP 地址,网络字节序
};
注意 sin_zero (它被加入到这个结构,并且长度和 struct sockaddr 一样) 应该使用函数 bzero() 或 memset() 来全部置零。 同时,这一重要的字节,一个指向 sockaddr_in结构体的指针也可以被指向结构体sockaddr并且代替它。这 样的话即使 socket() 想要的是 struct sockaddr *,你仍然可以使用 struct sockaddr_in,并且在最后转换。
sin_port和 sin_addr 必须是网络字节顺序 (Network Byte Order)
的socket 地址结构(定长)struct in6_addr{
uint8_t s6_addr[16]; //128 位IP 地址,网络字节序
}
struct sockaddr_in6{
uint8_t sin6_len; //IPv6 为固定的24 字节长度
sa_family_t sin6_family; //地址簇类型,为AF_INET6
in_port_t sin6_port; //16 位端口号,网络字节序
uint32_t sin6_flowinfo; //32 位流标签
struct in6_addr sin6_addr; //128 位IP 地址
}
socket 地址结构struct sockaddr {
uint8_t sa_len;
unsigned short sa_family; /* 地址家族, AF_xxx */
char sa_data[14]; /*14字节协议地址*/
};
sa_family 能够是各种各样的类型,但是在这篇文章中都是 "AF_INET"
--------------------------------------------------------------------------------
一个16位整数,它由2个字节组成。
内存中存储这两个字节有两种方法:
小端字节序:低序字节存储在起始地址
大端字节序:高序字节存储在起始地址
网际协议必须指定一个网络字节序(Network Byte Order)
主机字节序和网络字节序的转换函数:
#include
unit16_t htons(uint16_t host16bitvalue);
unit32_t htonl(uint32_t host32bitvalue);
unit16_t ntohs(uint16_t net16bitvalue);
unit32_t ntohl(uint32_t net32bitvalue);
h : host
n : network
s : short (16 bits)
l : long (32 bits)
--------------------------------------------------------------------------------
#include
int inet_aton(const char *strptr,struct in_addr *addrptr);
inet_aton函数将strptr 所指的C字符串转换成32位的网络字节序二进制值并通过指针addrptr来存储。如果成功返回1,否则返回0。
in_addr_t inet_addr(const char *strptr);
inet_addr函数将strptr 所指的C字符串转换成32位的网络字节序二进制值并通过涵数值返回。若成功,返回32位二进制的网络字节序地址;若出错,则返回INADDR_NONE
假设已经有了一个sockaddr_in结构体ina,有一个IP地 址"132.241.5.10"要储存在其中,可以使用函数inet_addr()将IP地址从点分格式转换成无符号长整型。使用方法如下:
ina.sin_addr.s_addr = inet_addr("132.241.5.10");
注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用函数htonl()。
char *inet_ntoa (struct in_addr inaddr);
函数inet_ntoa将一个32位的网络字节序二进制IPv4地址转换成相应的点分十进制数串。
返回:指向点分十进制数串指针
将一个in_addr结构体输出成点分格式的IP地址,使用函数inet_ntoa()("ntoa"的含义是"network to ascii"),如:
printf("%s",inet_ntoa(ina.sin_addr));
它将输出IP地址。需要注意的是inet_ntoa()将结构体in_addr作为一个参数,不是长整形。同样需要注意的是它返回的是一个指向一个字符的指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址。例如:
char *a1, *a2;
……
……
a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */
a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */
printf("address 1: %s\n",a1);
printf("address 2: %s\n",a2);
输出如下:
address 1: 132.241.5.10
address 2: 132.241.5.10
假如你需要保存这个IP地址,使用strcopy()函数来指向你自己的字符指针。
-------------------------------------------------------------
字节流处理函数
void bzero(void *s, int n); //置字节字符串s的前n个字节为零
void bcopy(const void *src, void *dest, int n); //将字符串src的前n个字节复制到dest中
int bcmp(const void *s1, const void *s2, int n); //比较字符串s1和s2的前n个字节是否相等
返回:0——相等,非0——不相等
void *memset(void *buffer, int c, int count); //把buffer所指内存区域的前count个字节设置成字符c
void *memcpy(void *dest, void *src, unsigned int count); //由src所指内存区域复制count个字节到dest所指内存区域
int memcmp(void *buf1, void *buf2, unsigned int count); //比较内存区域buf1和buf2的前count个字节。
返回:0——相同,非0——不相同
字节流读写函数
ssize_t readn(int filedes, void * buff, size_t nbytes);
ssize_t writen(int filedes, const void *buff, size_t nbytes);
ssize_t readline(intfiledes, void *buff, size_t maxlen);
--------------------------------------------------------------------------------
TCP/IP的socket提供下列三种类型套接字。
1)字节流套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传送协议(FTP)即使用流式套接字。
2)数据报套接字(SOCK_DGRAM)
提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。
3)原始套接字(SOCK_RAW)
该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。
定义一个连接的一个端点的两元组,即IP 地址和端口号,称为一个套接口。
在网络连接中,两个端点所组成的四元组(即本地IP、本地PORT、远程IP 和远程PORT)
称为socket pair,该四元组唯一的标识了一个网络连接。该情况可通过netstat 验证。