1. 程式人生 > >1.套接字程式設計基礎

1.套接字程式設計基礎

套接字地址結構:


IPv4套接字地址結構

IPv4套接字地址結構也被成為網際套接字地址結構,被命名為sockaddr_in,IPv6命名為sockaddr_in6,他們被定義在<netinet/in.h 中,posix標準中的IPv4套接字地址結構定義如下:

/* ipv4套接字地址結構  */
struct sockaddr_in
  {
    sa_family_t   sin_family   /*AF_INET*/
    in_port_t    sin_port;          /* 埠號 16位網路序二進位制 */
    struct   in_addr sin_addr;      /* ip地址 32位網路序二進位制  */
char sin_zero[8]; };

通用套接字地址結構

每個協議簇都定義了自己套接字地址結構,他們都已sockaddr_ 開頭,比如上面的IPv4套接字地址結構。
一種通用的套接字地址結構被命名為sockaddr ,定義如下

struct sockaddr
  {
    sa_family_t   sin_family  
    char   sa_data[14];
  };

bind函式是一個使用到通用套接字地址結構的函式:

typedef struct sockaddr SA;
bind(int,SA *,socklen_t);//其中socklen_t是套接字地址結構的大小,用sizeof獲得

值-結果引數

當王一個套接字函式傳遞一個套接字地址結構時,該結構總是以引用的方式傳遞,也就是說傳遞的是指向結構的引數。該結構的大小也座位一個引數來傳遞,不過傳遞方式分直接傳遞和指標。

  1. 從程序到核心(connect、bind、sento)——值傳遞:connect(sockfd,(SA *) &serv,sizeof(serv);
  2. 從核心到程序(accept、recvfrom、getsockname、getpeername)——引用傳遞:getpeername(unixfd,(SA *)&cli,&len;

為何將結構大小由整數改為指向整數的指標呢?
這是因為:當函式被呼叫時,結構大小是一個值(value, 此值告訴核心該結構的大小,使核心在寫此結構時不至於越界),當函式返回時,結構大小又是一個結果(result,它告訴程序核心在此結構中確切儲存了多少資訊),這種引數叫做值-結果引數(value-result)。
通俗一點講就是,值傳遞不可以修改核心中資料,引用傳遞可以通過指標修改核心中的資料。


位元組排序函式

考慮一個16位整數,由2個位元組組成,記憶體儲存這兩個位元組有兩種方式:

  1. 將低序位元組儲存在起始地址(小端位元組序)
  2. 將高序位元組儲存在起始地址(大端位元組序)
  3. 小端和大端指多位元組的哪一端存在起始位置。

對於網路,傳送協議棧和接受協議棧必須就多位元組欄位多位元組的傳輸順序達成一致,因此存在網路位元組序。
因為主機位元組序和網路位元組序會存在不同,所以出現了位元組排序函式:

#include <netinet/in.h>
uint32_t ntohl (uint32_t __netlong);
uint16_t ntohs (uint16_t __netshort);
uint32_t htonl (uint32_t __hostlong);
uint16_t htons (uint16_t __hostshort);

位元組操縱函式

位元組操縱函式有兩組:一組以b開頭,代表位元組;一組以mem開頭,代表記憶體。他們都進行記憶體的初始化、複製和比較。
下面給出函式宣告:
b組:

#include <string.h>
extern int bcmp (const void *__s1, const void *__s2, size_t __n);
/* Copy N bytes of SRC to DEST (like memmove, but args reversed).  */
extern void bcopy (const void *__src, void *__dest, size_t __n);
/* Set N bytes of S to 0.  */
extern void bzero (void *__s, size_t __n);

mem組

#include <string.h>
extern void *memccpy (void *__restrict __dest, const void *__restrict __src,
              int __c, size_t __n);
/* Set N bytes of S to C.  */
extern void *memset (void *__s, int __c, size_t __n);
/* Compare N bytes of S1 and S2.  */
extern int memcmp (const void *__s1, const void *__s2, size_t __n)

地址轉換函式

地址轉換函式用於在ASCII字串和網路位元組序的二進位制值之間轉換網路地址。

  1. inet_aton、inet_addr、inet_ntoa在點分十進位制(127.0.0.1)與長度為32位的網路位元組序的二進位制之間轉換IPv4地址。
  2. 兩個較新的函式inet_ptoninet_ntop 對IPv4和IPv6地址都適用。

後面主要使用較新的兩個函式,下面給出他們的函式宣告。

  • 注意:有些系統沒有實現這兩個函式,需要自己宣告和定義,參見下面。
//用於轉換ip地址(類似127.0.0.1的“表述”轉換為二進位制的“數”);
int
inet_pton(int af,const char *src,void *dst);

//將網路序中的二進位制數轉化為點分十進位制數(p——表示式)
const char *
inet_ntop(int af, const void *src, char *dst, socklen_t size);
/**
 * 定義size是為了防止超出緩衝區
 * size 使用 <netinet/in.h>中定義的
   #define INET_ADDRSTRLEN 16
   #define INET6_ADDRSTRLEN 46
 */

inet_ptoninet_ntop 的函式原型見我的github