linux_网络通信-套接字通信socket-网络字节序-IP地址转换函数-inet_pton函数-htonl函数-htons函数-ntohl函数-ntohs函数

这篇具有很好参考价值的文章主要介绍了linux_网络通信-套接字通信socket-网络字节序-IP地址转换函数-inet_pton函数-htonl函数-htons函数-ntohl函数-ntohs函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

接上一篇:linux_进程锁与文件锁-pthread_mutexattr_init函数-pthread_mutexattr_setpshared函数

  今天开始分享网络通信了,主要是就是socket套接字通信,本篇先分享一些预备知识,有网络字节序以及一些IP地址转换函数,话不多说,开始上菜:

此博主在CSDN发布的文章目录:我的CSDN目录,作为博主在CSDN上发布的文章类型导读

1.套接字概念

  Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。
  既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
  套接字的内核实现较为复杂,不宜在学习初期深入学习。
  在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。
  “IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
  套接字通信原理如下图所示:
inet_pton,Linux笔记,网络,linux,tcp/ip,网络字节序,inet_pton
  在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。
  TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。

2.网络字节序

  我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。
  网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
  TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。
  但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。
  同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。
  为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>
	uint32_t htonl(uint32_t hostlong);
	uint16_t htons(uint16_t hostshort);
	uint32_t ntohl(uint32_t netlong);
	uint16_t ntohs(uint16_t netshort);

  h表示host,n表示network,l表示32位长整数,s表示16位短整数。
  如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
  int a = 7845;//0x1EA5(两个字节)
  大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法,存储方式:1EA5。
  小端字节序:低位字节在前,高位字节在后,存储方式:A51E。(计算机存储方式)

2.1.htonl函数

函数作用:
  将无符号整数hostlong从主机字节顺序转换为网络字节顺序。
头文件:
  #include <arpa/inet.h>
函数原型:
  int32_t htonl(uint32_t hostlong);
函数参数:
  hostlong:需要转换的无符号主机字节
返回值:
  返回一个网络字节顺序的值。

2.2.htons函数

函数作用:
  从主机字节转换无符号短整数hostshort顺序到网络字节顺序。
头文件:
  #include <arpa/inet.h>
函数原型:
  uint16_t htons(uint16_t hostshort);
函数参数:
  hostshort:需要转换的无符号短整数主机字节
返回值:
  返回一个网络字节顺序的值。

2.3.ntohl函数

函数作用:
  从网络字节顺序转换无符号整数netlong到主机字节顺序。
头文件:
  #include <arpa/inet.h>
函数原型:
  uint32_t ntohl(uint32_t netlong);
函数参数:
  netlong:需要转换的无符号整数网络字节顺序的值。
返回值:
  返回主机字节顺序的值。(32位)
注意:

2.4.ntohs函数

函数作用:
  从网络字节转换无符号短整数netshort顺序到主机字节顺序。
头文件:
  #include <arpa/inet.h>
函数原型:
  uint16_t ntohs(uint16_t netshort);
函数参数:
  netshort:需要转换的无符号短整数网络字节顺序的值。
返回值:
  返回主机字节顺序的值。(16位)

3.IP地址转换函数

早期:
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  int inet_aton(const char *cp, struct in_addr *inp);
  in_addr_t inet_addr(const char *cp);
  char *inet_ntoa(struct in_addr in);
①只能处理IPv4的ip地址
②是不可重入函数
③注意参数是struct in_addr

现在:
  #include <arpa/inet.h>
  int inet_pton(int af, const char *src, void *dst);
  const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

①支持IPv4和IPv6
②可重入函数
③其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr。

  因此函数接口是void *addrptr。

3.1.inet_pton函数

函数作用:
  将点分文本的IP地址转换为二进制网络字节序”的IP地址。
头文件:
  #include <arpa/inet.h>
函数原型:
  int inet_pton(int af, const char *src, void *dst);
函数参数:
af:地址簇
  取值:AF_INET --表示IPV4
  取值:AF_INET6 --表示IPV6
src:源地址
dst:转换后的地址
返回值:
  返回1:成功;
  返回0:输入不是有效表达式;
  返回-1:失败。
例如:
   struct sockaddr_in serv_addr;
   char buf[BUFSIZ];
   bzero(&serv_addr, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
  serv_addr.sin_port = htons(SERV_PORT);

3.2.inet_ntop函数

函数作用:
  将数值格式转化为点分十进制的ip地址格式。
头文件:
  #include <arpa/inet.h>
函数原型:
  const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
函数参数:
af:地址簇
  取值:AF_INET --表示IPV4
  取值:AF_INET6 --表示IPV6
src:源地址
dst:转换后的地址

返回值:
  若成功则为指向结构的指针,若出错则为NULL,将errno置为EAFNOSUPPORT。
注意:

3.3.bzero函数

函数作用:
  将指定内存清0。
头文件:
  #include <strings.h>
函数原型:
  void bzero(void *s, size_t n);
函数参数:
  s:需要清空内存的首地址;
  n:s的大小
返回值:
无。
例如:
  struct sockaddr_in serv_addr;
  bzero(&serv_addr, sizeof(serv_addr));

4.sockaddr数据结构

  strcut sockaddr 很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。

sockaddr数据结构:
inet_pton,Linux笔记,网络,linux,tcp/ip,网络字节序,inet_pton

struct sockaddr {
	sa_family_t sa_family; 		/* address family, AF_xxx */
	char sa_data[14];			/* 14 bytes of protocol address */
};

  使用 sudo grep -r “struct sockaddr_in {” /usr 命令可查看到struct sockaddr_in结构体的定义。一般其默认的存储位置:/usr/include/linux/in.h 文件中。

struct sockaddr_in {
	__kernel_sa_family_t sin_family; 			/* Address family */  	地址结构类型
	__be16 sin_port;					 		/* Port number */		端口号
	struct in_addr sin_addr;					/* Internet address */	IP地址
	/* Pad to size of `struct sockaddr'. */
	unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
	sizeof(unsigned short int) - sizeof(struct in_addr)];
};

struct in_addr {						/* Internet address. */
	__be32 s_addr;
};

struct sockaddr_in6 {
	unsigned short int sin6_family; 		/* AF_INET6 */
	__be16 sin6_port; 					/* Transport layer port # */
	__be32 sin6_flowinfo; 				/* IPv6 flow information */
	struct in6_addr sin6_addr;			/* IPv6 address */
	__u32 sin6_scope_id; 				/* scope id (new in RFC2553) */
};

struct in6_addr {
	union {
		__u8 u6_addr8[16];
		__be16 u6_addr16[8];
		__be32 u6_addr32[4];
	} in6_u;
	#define s6_addr 		in6_u.u6_addr8
	#define s6_addr16 	in6_u.u6_addr16
	#define s6_addr32	 	in6_u.u6_addr32
};

#define UNIX_PATH_MAX 108
	struct sockaddr_un {
	__kernel_sa_family_t sun_family; 	/* AF_UNIX */
	char sun_path[UNIX_PATH_MAX]; 	/* pathname */
};

  Pv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,IPv6地址用sockaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。
  UNIX Domain Socket的地址格式定义在sys/un.h中,用sock-addr_un结构体表示。各种socket地址结构体的开头都是相同的,前16位表示整个结构体的长度(并不是所有UNIX的实现都有长度字段,如Linux就没有),后16位表示地址类型。
  IPv4、IPv6和Unix Domain Socket的地址类型分别定义为常数AF_INET、AF_INET6、AF_UNIX。这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。
  因此,socket API可以接受各种类型的sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *类型以便接受各种类型的指针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,
  例如:

	struct sockaddr_in servaddr;
	bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));		/* initialize servaddr */

  以上就是本次的分享了,希望对大家有所帮助,欢迎关注博主一起学习更多的新知识!文章来源地址https://www.toymoban.com/news/detail-770339.html

到了这里,关于linux_网络通信-套接字通信socket-网络字节序-IP地址转换函数-inet_pton函数-htonl函数-htons函数-ntohl函数-ntohs函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 「网络编程」第二讲:网络编程socket套接字(三)_ 简单TCP网络通信程序的实现

    「前言」文章是关于网络编程的socket套接字方面的,上一篇是网络编程socket套接字(二),下面开始讲解!  「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「每篇一句」 I do not know where to go,but I have been on the road. 我不知

    2024年02月11日
    浏览(52)
  • Linux之套接字UDP实现网络通信

    ​ 套接字(Socket)是计算机网络中实现网络通信的一种 编程接口 。它提供了应用程序与网络通信之间的一座桥梁,因为它允许应用程序通过网络发送和接收相应的数据以实现不同主机之间的通信。 ​ 通常套接字由以下两部分组成: 1.网络IP和端口号 :IP用来标识主机,而端口

    2024年02月11日
    浏览(45)
  • Linux下套接字TCP实现网络通信

    ​ 套接字(Socket) 是计算机网络中实现网络通信的一种 编程接口 。它提供了应用程序与网络通信之间的一座桥梁,因为它允许应用程序通过网络发送和接收相应的数据以实现不同主机之间的通信。 通常套接字由以下两部分组成: 1.网络IP和端口号 :IP用来标识主机,而端口号

    2024年02月10日
    浏览(45)
  • 【Java】网络编程与Socket套接字、UDP编程和TCP编程实现客户端和服务端通信

    为什么需要网络编程? 现在网络普及程序越来越高,网络上保存着我们日常生活中需要的各种资源,使用程序通过网络来获取这些资源的过程就需要网络编程来实现。 什么是网络编程? 网络编程,指网络上的主机,通过不同的进程以程序的方式实现网络通信(网络数据传输)

    2024年02月17日
    浏览(78)
  • 学习网络编程No.5【TCP套接字通信】

    北京时间:2023/8/25/15:52,昨天刚把耗时3天左右的文章更新,充分说明我们这几天并不是在摆烂中度过,而是在为了更文不懈奋斗,历时这么多天主要是因为该部分知识比较陌生,所以需要我们花费大量的时间去细细研究,为后面无论是TCP套接字,还是网络的学习都能更加融会

    2024年02月10日
    浏览(60)
  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(60)
  • 【网络编程】利用套接字实现一个简单的网络通信(UDP实现聊天室 附上源码)

    源IP地址(Source IP Address): 源IP地址是数据包发送方(或数据流出发点)的唯一标识符。它用于在互联网或本地网络中定位发送数据包的设备或主机。源IP地址是数据包的出发点,即数据从这个地址开始传送,向目的IP地址指示的设备发送。 在TCP/IP协议中,源IP地址通常由发

    2024年02月14日
    浏览(84)
  • 【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

    橙色 所谓套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进程通

    2024年02月09日
    浏览(55)
  • Linux网络编程- 原始套接字(Raw Socket)

    原始套接字(Raw Socket)提供了一种机制,允许应用程序直接访问底层传输协议,绕过操作系统提供的传输层接口。这种套接字通常用于实现新的协议或对现有协议进行低级别的操作。 以下是对原始套接字的详细介绍: 定义与用途 : 原始套接字是直接基于网络层(如IP)的。

    2024年02月07日
    浏览(55)
  • 【Linux网络】网络编程套接字 -- 基于socket实现一个简单UDP网络程序

    我们把数据从A主机发送到B主机,是目的吗?不是,真正通信的不是这两个机器!其实是这两台机器上面的软件(人) 数据有 IP(公网) 标识一台唯一的主机 ,用谁来标识各自主机上客户或者服务进程的唯一性呢? 为了更好的表示一台主机上服务进程的唯一性,我们采用 端口号

    2024年02月12日
    浏览(158)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包