sockaddr_in结构体:
- struct sockaddr_in {
- short int sin_family; // Address family
- unsigned short int sin_port; // Port number
- struct in_addr sin_addr; // Internet address
- unsigned char sin_zero[8]; // Same size as struct sockaddr
- };
- struct sockaddr {
- unsigned short sa_family; // address family, AF_xxx
- char sa_data[14]; // 14 bytes of protocol address
- };
- struct in_addr {
- unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
- };
- struct hostent {
- char *h_name; /* 主机的官方域名 */
- char **h_aliases; /* 一个以NULL结尾的主机别名数组 */
- int h_addrtype; /* 返回的地址类型,在Internet环境下为AF-INET */
- int h_length; /* 地址的字节长度 */
- char **h_addr_list; /* 一个以0结尾的数组,包含该主机的所有地址*/
- };
填充sockaddr_in结构体时:serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
sockaddr_in与sockaddr都是16个字节,只是sockaddr的表现形式更形象,对象化而已。而in_addr结构体就是一个long型
gethostbyname进行域名于IP的转换。返回一个hostend的结构体
可以猜测h_addr_list是一个4字节网络字节序的in_addr,只是使用char*来表示,h_addr与struct in_addr其实形式是一样的。然后将host->h_addr强转成struct in_addr格式的指针,最后取值。
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号(使用网络字节顺序)
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向
sockadd的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,
在最后用进行类型转换就可以了bzero((char*)&mysock,sizeof(mysock));//初始化
mysock结构体名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
……
等到要做转换的时候用:
(struct sockaddr*)mysock
#include<stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 3333
#define MAXDATASIZE 100 /*每次最大数据传输量 */
main(int argc, char *argv[]) {
int sockfd, recvbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if (argc < 2) {
fprintf(stderr, "Please enter the server's hostname!\n");
exit(1);
}
if ((host = gethostbyname(argv[1])) == NULL) {
herror("gethostbyname出错!");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket创建出错!");
exit(1);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *) host->h_addr);
bzero(&(serv_addr.sin_zero), 8);
if (connect(sockfd, (struct sockaddr *) &serv_addr,
sizeof(struct sockaddr)) == -1) {
perror("connect出错!");
exit(1);
}
if ((recvbytes = recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv出错!");
exit(1);
}
buf[recvbytes] = '\0';
printf("Received: %s", buf);
close(sockfd);
}
将网络地址字符串转换成网络使用的二进制数字
unsigned long inet_addr(const char *cp)
in_addr_t inet_network(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
struct sockaddr_in src
src.sin_addr.s_addr = inet_addr("192.168.1.123");
inet_addr和inet_network函数都是用于将字符串形式转换为整数形式用的,两者区别很小,inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序。(你一定会纳闷,为什么函数叫inet_network,却返回的是主机字节序,呵呵,就是这么奇怪,你又有什么办法呢…)其他地方两者并无二异。他俩都有一个小缺陷,那就是当IP是255.255.255.255时,这两个“小子”(对这两个函数的昵称,请谅解…^_^)会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部分的路由器上,这个255.255.255.255的IP都是有效的。
inet_aton函数和上面这俩小子的区别就是在于他认为255.255.255.255是有效的,他不会冤枉这个看似特殊的IP地址。所以我们建议你多多支持这个函数,那两个小子还是少用为好:)对了,inet_aton函数返回的是网络字节序的IP地址。
将网络使用的二进制数字转换成网络地址字符串:
char *inet_ntoa(struct in_addr in)
将主机字节顺序转换为网络字节顺序:
htons和htonl函数,是用来将主机字节顺序转换为网络字节顺序
在进行网络抓包时,抓到的包的数据是网络字节顺序,在进行编程时,要进行主机字节顺序和网络字节顺序间的转换。
将网络字节顺序转换为主机字节顺序:
ntohs ntohl