網絡編程第三章:套接字編程簡介


#include "unp.h"

struct in_addr
{
    in_addr_t s_addr;
};
struct  sockaddr_in
{
    uint8_t sin_len;//非必要的無符號短整數
    //規範裏面只是強制要求了以下三個字段,但是幾乎所有的實現都增加了sin_zero字段
    sa_family_t sin_family;//地址族,
    in_port_t sin_port;//端口,至少8位
    struct in_addr sin_addr;//IP地址至少32位
    char sin_zero[8];
};
//TCP或者端口總是以網絡字節序來存儲
//套接字地址結構僅僅在給定主機上使用,雖然某些字段用於通信,但是結構本身並不用於通信




//通用套接字地址結構:作爲參數傳遞任何套接字函數的時候,套接字總是以引用的方式傳遞,所以要有一個通用的地址結構,如下:
struct sockaddr{
    uint8_t sa_len;
    sa_family_t sa_family;
    char sa_data[14];
};
//調用的時候,要進行強制類型轉換
struct sockaddr_in serv;
bind(sockfd,(struct sockaddr*)&serv,sizeof(serv));//可以將bind函數看作是一個通用的函數適配器,它接受一個可調用對象,生成一個新的可調用對象來“適應”原對象的參數列表。



//IPV6套接字地址結構,在<netinet/in.h>頭文件中定義

struct in6_addr
{
    uint8_t s6_addr[16];//128位的IP地址
};
#define SIN6_LEN    
struct sockaddr_in6{
    uint8_t sin6_len;//長度字段,如果系統支持這個字段,那麼這個字段必須定義
    sa_family_t sin6_family;//AF_INET6.地址族
    in_port_t sin6_port;//端口號,
    uint32_t sin6_flowinfo;//流信息,低20位是流標準,高20位保留
    struct in6_addr sin6_addr;//IP地址
    uint32_t sin6_scope_id;//
};


//新的套接字結構:
struct sockaddr_storage{
    uint8_t ss_len;
    sa_family_t sa_family;
};
//如果系統有字節對齊要求,那麼這個能夠滿足
//除了這兩個字段,其他字段對用戶來講是透明的,


//不同套接字的地址長度不同(比如,Unix域地址長度固定,但是信息不固定)


//值結果參數定義:getpeername(unixfd, (SA *)&cli, &len);本例中 getpeername 函數的入參 len 本身有值,即結構體變量 cli 的大小,用於告訴內核待會寫 cli 的值時別寫越界了,它只有 len 的大小;

//網絡編程中的定義:當函數參數是從 內核 到 進程 時:
//函數被調用時,參數大小是一個值,進程告訴內核該參數的結構大小避免內核寫操作越界;
//函數返回時,參數的結構大小又是一個結果,應用進程可以知道內核所寫數據的大小。
//往往涉及到兩個參數:存儲數據的結構體指針 和 存儲結構體大小的整數指針




//字節排序函數代碼實例
#include "unp.h"
#include<bits/stdc++.h>
using namespace std;
int main(){
    //小端方式:低序在低地址,高序在高地址
    //大端方式:低序在高地址,高度在低地址
    union 
    {       
        short s;
        char c[sizeof(short)];
    }un;
    un.s=0x0102;
    if(sizeof(short)==2){
        if(un.c[0]==1&&un.c[1]==2)
            printf("大端方式");
        else printf("小端方式");
    }else{

        printf("error");
    }
    return 0;
}

//位序:沒有看懂,,,


//字節序之間的轉換函數(主機字節序和網絡字節序不一定相同)
#include<netinet/in.h>
//以下兩個函數返回網絡字節序的值
uint16_t htons(uint16_t host16bitvalue);

uint32_t htonl(uint16_t host32bitvalue);
//以下兩個函數返回主機字節序的值,
uint16_t ntohs(uint16_t host16bitvalue);

uint32_t ntohl(uint16_t host32bitvalue);
//h代表host主機,n代表network,s代表short,l代表long(要把long視爲一個32位的值)

//字操縱函數:
#include <strings.h>
void bzero (void *dest,size_t mybytes){}//指定字節數字清零
void bcopy(const void *src,void*dest,size_t mbytes){}//從源到目的複製指定數量字節
int bcmp(const void *ptr1,const void *ptr2,size_t mybytes){}//相同返回值爲0,否則非0

#include<strings.h>
void memset(void *dest,size_t len)//目的地址清零
void memcpy(void*dest,const void *src,size_t nbytes)//指定數目的字節數置爲c
void memcmp(const void*ptr1,const void *ptr2,size_t nbytes)//比較兩個字符串,相同就返回0,否則返回非0

//兩組地址轉換函數
#include  <arpa/inet.h>
int inet_aton(cosnt char* strptr,struct in_addr,*addrptr)//將一個字符串點分十進制IP4地址轉換爲網絡字節序二進制序
char* inet_ntoa(struct in_addr inaddr);//將網絡字節序轉換爲點分十進制


//ipV6地址轉換:
#incldue<arpa/inet.h>
int inet_pton(int family,cosnt char *strptr,void *addrptr);//吧字符串轉換爲二進制序,如果成功就返回,不是有效的表達式返回0,出錯返回-1
int inet_ntop(int family,const void *addrptr,char *strptr,size_t len);//二進制序轉化爲點分十進制,len是char的長度,避免緩衝區溢出

//如果當前機器不支持IPV6.也可以用以上兩個函數
foo.sin_addr.s_addr=inet_addr(cp);
//等同於inet_pton(AF_INET,cp,&foo.sin_addr)
char ptr[] = inet_ntoa(foo.sin_addr);
//等同於:char ptr[ ] =inet_ptoa(AF_INET,&foo.sin_addr,str,sizeof(str))


//sock_ntop和相關函數:
//在網絡編程卷一P70,這是一些包裹函數

/*
readn,writen,readline函數
字節流套接字調用readn或者writen輸出輸入的字節數可能會少(因爲內核用於套接字的緩衝區已滿):這時要再次調用readn或者writen,用來輸入輸出剩餘的字節

readline函數是非常慢的,因爲這個函數每讀入一個字節就會調用一次read函數,stdio提供的標準輸入輸出很誘人,但是容易有錯誤.詳見P74


*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章