Linux系统下socket编程socket接口介绍(二)

2022-03-18 20:56:36 浏览数 (1)

前言

在上一篇文章里面我们介绍了TCP的三次握手和四次挥手过程的介绍以及网络编程里面的一些api接口函数的介绍——Linux系统下socket编程之socket接口介绍(一)。今天我们继续来介绍网络编程里面的其它接口函数,为实战打下 基础;网络编程专题文章拖的有点久,这两天全部把它写完,不能再拖了。

函数介绍

- 发送和接收 -

(1)send和write:

首先说明的一点,之前介绍的socket这个函数,非常类似我们之前介绍的open函数,他们都会返回一下文件描述符;所以这里的send函数和write函数作用类似,我们用man手册来查看它的具体形式和用法:

代码语言:javascript复制
   #include <sys/types.h>
   #include <sys/socket.h>

   ssize_t send(int sockfd, const void *buf, size_t len, int flags);

说明:

第一个参数sockfd就是socket函数返回的文件描述符;第二个参数指向发送的信息所在的缓冲区(内存);第三个参数指缓冲区的长度大小;第四个参数一般设置为0(如果不是这种情况,可以具体再查看)。不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

(2)recv和read:

函数recv和之前介绍的read函数的用法差不多,我们还是用man手册来查看一它的形式和用法:

代码语言:javascript复制
   #include <sys/types.h>
   #include <sys/socket.h>

   ssize_t recv(int sockfd, void *buf, size_t len, int flags);

说明:

这里面的参数和上面send的参数说明一样。不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

- IP地址格式转换函数 -

(1)inet_aton、inet_addr、inet_ntoa(只用IPV4的IP地址),现在用的比较少,不过大多程序里面会看到这些函数,所以还是要学习一下它的作用,老方法使用man手册来查看它的形式和用法:

代码语言:javascript复制
   #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);

   in_addr_t inet_network(const char *cp);

   char *inet_ntoa(struct in_addr in);

   struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host);

   in_addr_t inet_lnaof(struct in_addr in);

   in_addr_t inet_netof(struct in_addr in);

说明:

首先我们来看inet_aton函数,它转换网络主机地址ip(如192.168.1.10)为二进制数值,并存储在struct in_addr结构中,即第二个参数*inp,函数返回非0表示cp主机有地有效,返回0表示主机地址无效。(这个转换完后不能用于网络传输,还需要调用htons或htonl函数才能将主机字节顺序转化为网络字节顺序,这两个函数先不讲,实战遇到的话,再进行解析),具体可以看下面Linux的源文:

代码语言:javascript复制
 inet_aton()  converts  the  Internet  
host  address  cp  from  the  IPv4  
numbers-and-dots notation into binary 
form (in network byte order) and stores it in the 
 structure that inp points to.
   inet_aton() returns nonzero if the address is valid, 
   zero if not.  The address 
 supplied in cp can have one of the following forms:

   a.b.c.d   Each of the four numeric parts specifies a 
  byte of the address; the 
 bytes are assigned in left-to-right order to produce the binary address.

   a.b.c     Parts a and b specify the first two bytes of the binary address.  Part c is interpreted as a 16-bit value that defines the rightmost two bytes of the binary address.  This  notation
             is suitable for specifying (outmoded) Class B network addresses.

   a.b       Part a specifies the first byte of the binary address.  Part b is 
  interpreted as a 24-bit value that defines the
  rightmost three bytes of the binary address.  This notation is suit‐
             able for specifying (outmoded) Class A network addresses.

   a         The value a is interpreted as a 32-bit value that is stored 
   directly into the binary address without any byte rearrangement.

   In all of the above forms, components of the dotted address can be specified
    in decimal, octal (with a leading 0), or hexadecimal, with a leading 0X). 
    Addresses in any  of  these  forms  are
   collectively termed IPV4 numbers-and-dots notation.  The form that uses exactly
    four decimal numbers is referred to as IPv4 dotted-decimal notation (or sometimes: IPv4 dotted-quad notation).

   inet_aton() returns 1 if the supplied string was successfully interpreted, 
  or 0 if the string is invalid (errno is not set on error).

接着是inet_addr函数,它的作用主要是转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char *cp无效,函数回-1(INADDR_NONE),这个函数在处理地址为255.255.255.255时也返回-1,255.255.255.255是一个有效的地址,不过inet_addr无法处理:

代码语言:javascript复制
   The  inet_addr()  function converts the Internet 
   host address cp from IPv4 numbers-and-dots notation into 
   binary data in network byte order.  
   If the input is invalid, INADDR_NONE (usually -1)
   is returned.  
   Use of this function is problematic because -1 is a 
  valid address (255.255.255.255). 
   Avoid its use in favor of inet_aton(), inet_pton(3), 
   or  getaddrinfo(3),  which  provide  a
   cleaner way to indicate error return.

最后就是inet_ntoa函数,它的作用主要是转换网络字节排序的地址为标准的ASCII以点分开的地址,该函数返回指向点分开的字符串地址(如192.168.1.10)的指针,该字符串的空间为静态分配的,这意味着在第二次调用该函数时,上一次调用将会被重写(复盖),所以如果需要保存该串最后复制出来自己管理!

代码语言:javascript复制
 The inet_ntoa() function converts the Internet host 
 address in, given in network byte order, to a string in 
 IPv4 dotted-decimal notation.  The string is returned  
 in  a  statically  allocated
   buffer, which subsequent calls will overwrite.

(2)inet_ntop、inet_pton,这两个函数是随IPv6出现的函数,对于IPv4地址和IPv6地址都适用,函数中p和n分别代表表达(presentation)和数(numeric)。地址的表达格式通常是ASCII字符串,数值格式则是存放到套接字地址结构的二进制值。我们还是用man手册来查看的它们的形式和作用:

代码语言:javascript复制
  #include <arpa/inet.h>

   const char *inet_ntop(int af, const void *src,  char *dst, socklen_t size);

我们先来看inet_ntop这个函数,第一个参数表示地址族(就是ipv4和ipv6),它的作用是把二进制格式转化为点分十进制的ip地址格式;inet_ntop函数的dst参数不可以是一个空指针。调用者必须为目标存储单元分配内存并指定其大小,调用成功时,这个指针就是该函数的返回值。size参数是目标存储单元的大小,以免该函数溢出其调用者的缓冲区。如果size太小,不足以容纳表达式结果,那么返回一个空指针,并置为errno为ENOSPC:

代码语言:javascript复制
   This  function  converts  the  network address 
   structure src in the af address family into a 
   character string.  The resulting string is copied to 
   the buffer pointed to by dst, which must be a
   non-null pointer.  The caller specifies the number of 
   bytes available in this buffer in the argument size.

   inet_ntop() extends the inet_ntoa(3) function to 
   support multiple address families, inet_ntoa(3) is 
   now considered to be deprecated in favor of 
   inet_ntop().  The  following  address  families
   are currently supported:

   AF_INET
          src  points  to a struct in_addr (in network 
   byte order) which is converted to an IPv4 network 
  address in the dotted-decimal format, 
  "ddd.ddd.ddd.ddd".  The buffer dst must be at least
          INET_ADDRSTRLEN bytes long.

   AF_INET6
          src points to a struct in6_addr (in network 
   byte order) which is converted to a representation of 
   this address in the most appropriate IPv6 network 
   address  format  for  this  address.
          The buffer dst must be at least 
 INET6_ADDRSTRLEN bytes long.

 RETURN VALUE
   On success, inet_ntop() returns a non-null pointer to 
  dst.  NULL is returned if there was an error, with 
  errno set to indicate the error.

ERRORS
   EAFNOSUPPORT
          af was not a valid address family.

   ENOSPC The converted address string would exceed the 
   size given by size.

接着我们来看inet_pton函数,它的作用主要是将点分十进制的ip地址转化为二进制格式:

代码语言:javascript复制
  #include <arpa/inet.h>

   int inet_pton(int af, const char *src, void *dst);

DESCRIPTION
   This  function  converts  the character string src 
  into a network address structure in the af address 
  family, then copies the network address structure to 
  dst.  The af argument must be either
   AF_INET or AF_INET6.  dst is written in network byte 
  order.

   The following address families are currently 
supported:

   AF_INET
          src points to a character string containing an 
  IPv4 network address in dotted-decimal format, 
  "ddd.ddd.ddd.ddd", where ddd is a decimal number of up 
  to three digits in the range  0  to
          255.  The address is converted to a struct 
  in_addr and copied to dst, which must be sizeof(struct 
  in_addr) (4) bytes (32 bits) long.

   AF_INET6
          src  points to a character string containing 
   an IPv6 network address.  The address is converted to 
   a struct in6_addr and copied to dst, which must be 
   sizeof(struct in6_addr) (16) bytes
          (128 bits) long.  The allowed formats for IPv6 
   addresses follow these rules:

          1. The preferred format is x:x:x:x:x:x:x:x.  
   This form consists of eight hexadecimal numbers, each 
   of which expresses a 16-bit value (i.e., each x can 
   be up to 4 hex digits).

          2. A series of contiguous zero values in the 
   preferred format can be abbreviated to ::.  Only one 
   instance  of  ::  can  occur  in  an  address.   For  
   example,  the  loopback  address
             0:0:0:0:0:0:0:1 can be abbreviated as ::1.  
   The wildcard address, consisting of all zeros, can be 
  written as ::.

          3. An  alternate  format  is useful for 
 expressing IPv4-mapped IPv6 addresses.  This form is 
 written as x:x:x:x:x:x:d.d.d.d, where the six leading 
 xs are hexadecimal values that define
             the six most-significant 16-bit pieces of 
 the address (i.e., 96 bits), and the ds express a value 
 in dotted-decimal notation that defines  the  least  
 significant  32  bits  of  the
             address.  An example of such an address is 
 ::FFFF:204.152.189.116.

          See RFC 2373 for further details on the 
 representation of IPv6 addresses.

RETURN VALUE
   inet_pton()  returns 1 on success (network address 
 was successfully converted).  0 is returned if src does 
 not contain a character string representing a valid 
 network address in the specified
   address family.  If af does not contain a valid 
 address family, -1 is returned and errno is set to 
EAFNOSUPPORT.

- 表示IP地址相关数据结构 -

(1)上面的一些函数参数里面用到的结构体(比如bind函数参数里的const struct sockaddr *addr等)都定义在 netinet/in.,我们可以用 vim /usr/include/netinet/in.h 来查看,这里具体的我就不理出来了,里面的内容比较多。

(2)struct sockaddr,这个结构体是linux的网络编程接口中用来表示IP地址的

标准结构体,bind、connect等函数中都需要这个结构体,这个结构体是兼容IPV4和IPV6的。在实际编程中这个结构体会被一个struct sockaddr_in或者一个struct sockaddr_in6所填充。

(3)typedef uint32_t in_addr_t:网络内部用来表示IP地址的类型。

代码语言:javascript复制
(4)struct in_addr
    {
       in_addr_t s_addr;
    };
(5)struct sockaddr_in
 {
     __SOCKADDR_COMMON (sin_);
     in_port_t   sin_port;                 /* Port number.  */
    struct in_addr sin_addr;            /* Internet address.  */

/* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
                       __SOCKADDR_COMMON_SIZE -
                       sizeof (in_port_t) -
                       sizeof (struct in_addr)];
   };

总结

今天主要是介绍了一下函数用法,下一篇文章开始进入实战讲解!

0 人点赞