函數介紹
- 發送和接收 -
(1)send和write:
首先說明的一點,之前介紹的socket這個函數,非常類似我們之前介紹的open函數,他們都會返回一下文件描述符;所以這裡的send函數和write函數作用類似,我們用man手冊來查看它的具體形式和用法:
#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手冊來查看一它的形式和用法:
#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手冊來查看它的形式和用法:
#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的源文:
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無法處理:
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)的指針,該字符串的空間為靜態分配的,這意味著在第二次調用該函數時,上一次調用將會被重寫(復蓋),所以如果需要保存該串最後複製出來自己管理!
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手冊來查看的它們的形式和作用:
#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:
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地址轉化為二進位格式:
#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位址的類型。
(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)];
};
今天主要是介紹了一下函數用法,下一篇文章開始進入實戰講解!
關注公眾號,每周分享至少3篇開源技術乾貨,文章中如有沒看懂的地方可以私聊我,我看到了會立馬回覆你,個人微信號:a18879499804