linux c socket

来源:互联网 发布:网络远程教育哪家好 编辑:程序博客网 时间:2024/06/09 16:46

sockaddr_in结构体:

  1. struct sockaddr_in {  
  2.      short int sin_family; // Address family  
  3.      unsigned short int sin_port; // Port number  
  4.      struct in_addr sin_addr; // Internet address  
  5.      unsigned char sin_zero[8]; // Same size as struct sockaddr  
  6. };  
sockaddr结构体:

  1. struct sockaddr {  
  2.       unsigned short sa_family; // address family, AF_xxx  
  3.       char sa_data[14]; // 14 bytes of protocol address  
  4. }; 
in_addr结构体:

  1. struct in_addr {  
  2.       unsigned long s_addr; // that’s a 32-bit long, or 4 bytes  
  3. };  
hostent 结构体:

  1. struct hostent {  
  2.     char *h_name; /* 主机的官方域名 */  
  3.    char **h_aliases; /* 一个以NULL结尾的主机别名数组 */  
  4.    int h_addrtype; /* 返回的地址类型,在Internet环境下为AF-INET */  
  5.    int h_length; /* 地址的字节长度 */  
  6.    char **h_addr_list; /* 一个以0结尾的数组,包含该主机的所有地址*/  
  7. };  

填充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