linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数

1、socket

不管是 Windows 还是 Linux,都使用 socket() 函数来创建套接字。socket() 在两个平台下的参数是相同的,不同的是返回值:
(1)Linux 中的一切都是文件,每个文件都有一个整数类型的文件描述符;socket 也是一个文件,也有文件描述符。使用 socket() 函数创建套接字以后,返回值就是一个 int 类型的文件描述符。
(2)Windows 会区分 socket 和普通文件,它把 socket 当做一个网络连接来对待,调用 socket() 以后,返回值是 SOCKET 类型,用来表示一个套接字。

Linux 下的 socket() 函数

在 Linux 下使用 头文件中 socket() 函数来创建套接字,原型为:

int socket(int af, int type, int protocol);

参数:

  1. af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。
  2. type 为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)
  3. protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议
    Linux下创建套接字:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  //IPPROTO_TCP表示TCP协议

2、sockaddr和sockaddr_in详解

struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址
1、sockaddr
sockaddr在头文件#include 中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:

struct sockaddr {  
      sa_family_t sin_family;//地址族
      char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
   }; 

2、sockaddr_in
sockaddr_in在头文件#include或#include 中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下:
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第1张图片
sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。
3、总结
二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。

sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息,是一种通用的套接字地址。
sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。

#include 
#include 
#include 
#include 

int main(int argc,char **argv)
{
    int sockfd;
    struct sockaddr_in mysock;

    sockfd = socket(AF_INET,SOCK_STREAM,0);  //获得fd

    bzero(&mysock,sizeof(mysock));  //初始化结构体
    mysock.sin_family = AF_INET;  //设置地址家族
    mysock.sin_port = htons(800);  //设置端口
    mysock.sin_addr.s_addr = inet_addr("192.168.1.0");  //设置地址
    bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr); /* bind的时候进行转化 */
    ... ...
    return 0;
}

3、inet_addr()

描述:
  inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值
返回值:
  若无错误发生,inet_addr()返回一个无符号长整型数,其中以适当字节顺序存放Internet地址。如果传入的字符串不是一个合法的Internet地址,如“a.b.c.d”地址中任一项超过255,那么inet_addr()返回INADDR_NONE

4、gethostbyname

函数原型:
  struct hostent* gethostbyname(const char *name);
调用函数成功返回一个hostent结构体

struct hostent
{
  char *h_name;
  char ** h_aliases;
  short h_addrtype;
  short h_length;
  char ** h_addr_list;
};

测试代码

#include
#include
#include
#include
#include
#include  
#include
#include
#include
#include
#include
#include 

int main(int argc,char *argv[])
{
	int optret;
	char *ipname = NULL;
	char ip[50];
	struct hostent *gethost = NULL;
	int file_fd;
	char buf[50];
	char *ptrf;
	char *ptrb;
	int n;
	char fptr[50];
	const char *ptr = NULL;
	struct in_addr  inAddr;
	while((optret = getopt(argc,argv,"i:")) != -1)
	{
		switch(optret)
		{
			case 'i':
				ipname = optarg;
				printf("option = i,the ipname is:%s\n",optarg);
				break;
		}
	}
	gethost = gethostbyname(ipname);
	if (NULL == gethost)
	{
		perror("get ipaddr fail!");
		return -1;
	}
	printf("get host successfully!\n");
	memset(ip,0,sizeof(ip));
	ptr = inet_ntop(gethost->h_addrtype,gethost->h_addr_list[0],ip,sizeof(ip));
	printf("DNS ip is:%s\n",ptr);

	system("ping studio.iot-yun.com -c 2 >> /home/deepin/APUE/malunkun/test/.domain.log");
	file_fd=open("/home/deepin/APUE/malunkun/test/.domain.log",O_RDONLY,644);
	if (file_fd < 0)
	{
		perror("open file fail!\n");
	}
	read(file_fd,buf,sizeof(buf));
	close(file_fd);
	ptrf = strstr(buf,"(");
	ptrf += 1;
	ptrb = strstr(buf,")");
	n = strlen(ptrf)-strlen(ptrb);
	strncpy(fptr,ptrf,n);
	printf("ping ip is:%s\n",fptr);

	return 0;
}

输出:
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第2张图片
使用输出的IP地址去访问网站,发现显示的也是百度
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第3张图片

5、getsockopt和setsockopt函数

这两个函数仅用于套接字。

函数原型:

#include 
 #include  
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

sockfd:必须指向一个打开的套接字描述符

level:指定系统中解释选项的代码或为通用套接字代码,或为某个特定于协议的代码(例如IPv4IPv6、TCP或SCTP)。
optval:指向某个变量(*optval)的指针,setsockopt从optval中取得选项设置的新值,getsockopt则把以获取的选项当前值存入optval。
optlen:指定*optval的大小
套接字选项的汇总可以查看unix网络编程(卷1)151页 图7-1和图7-2
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第4张图片
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第5张图片
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第6张图片
linux之socket相关的函数结构体解析inet_addr、gethostbyname、sockaddr和sockaddr_in、getsockopt和setsockopt函数_第7张图片

你可能感兴趣的:(杂项)