linux/unix編程手冊-56_60


title: linux/unix編程手冊-55_56 date: 2018-10-05 11:53:07 categories: programming tags: tips

linux/unix編程手冊-56(SOCKET 介紹)

socket是一種IPC方法。容許單臺或經過網絡鏈接的主句進程間交換數據linux

  • 各應用程序建立一個socket
  • 服務器將本身的socket綁定到一個都知道的地址上

fd=socket(domain, type, protocol)編程

系統調用

#include<sys/socket.h>

int socket(int domain, int type, int protocal) //return fd success, -1 error int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//return 0 s, -1 e

struct sockaddr{
    sa_family_t sa_family;
    char        sa_data[14];
};
複製代碼

socket緩存

  • domain:識別出socket的地址格式,代表通訊範圍
  • type:SOCKET_STREAM(TCP)和SOCKET_DGRAM(UDP)
  • protocol 通常爲0

對於fd,getsockname,getpeername服務器

流socket

#include<sys/socket.h>
int listen(int sockfd, int backlog);
//return 0 s, -1 e

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//return fd success, -1 error

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//return 0 s, -1 e
複製代碼

主動和被動socket網絡

  • 一個主動socket經過connect 創建一個到被動socket的鏈接
  • 一個被動socket經過listen 被標記成容許接入鏈接的socket

listen併發

  • backlog: 若是在服務器調用accept前,客戶端connect,會產生一個未決的鏈接,backlog限制這個數量,在這個數量內,客戶端鏈接請求會當即成功,數量外的會阻塞到一個未決鏈接被accept,並從未決鏈接隊列刪除

accept負載均衡

  • 會建立一個新的socket,這個新的socket會與connect另外一端的socket鏈接
  • addr和addrlen在調用事後會爲對端地址信息,若是不關心對端信息傳入時設爲NULL,0

數據報socket

#nclude<sys/socket.h>

ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
//return num of bytes received, 0 EOF, -1 error

ssize_t recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *dest_addr, socklen_t *addrlen);
//return num of bytes send, -1 error
複製代碼
  • 客戶端若是須要接受服務端發送的數據報的話還須要bind一下
  • 數據報能夠connect以後調用write和直接send_to同樣,只適用於發起connect的一端,connect以後內核會記錄socket的對端,屢次調用connect後面的會修改前面的

linux/unix編程手冊-57(SOCKET UNIX DOMAIN)

struct sockaddr{
    sa_family_t sa_family;
    char        sa_data[108];
};


const char *SOCKNAME = "/tmp/mysock";
int sfd;
struct sockaddr_un addr;
sfd = socket(AF_UNIX, SOCK_STREAM, 0); 
if (sfd == -1)
    errExit("socket");
/* Create socket */
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKNAME, sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
    errExit("bind");
複製代碼
  • 沒法將socket綁定到一個已有路徑名上,bind會返回EADDRINUSE
  • 沒法open 打來一個socket
  • 當不須要一個socket時使用unlink
  • 若是sun_path的第一個字符爲NULL字節,會建立抽象socket命名空間
    • 無需擔憂名字和文件系統衝突
    • socket關閉後自動刪除抽象名
    • 權限無需寫權限

其餘

#include<sys/socket.h>

int socketpair(int domain, int type, int protocol, int sockfd[2]);
複製代碼
  • domian只能是AF_UNIX
  • 調用完sockpair以後,進程會fork一個子進程,子進程繼承fd副本進行通訊

linux/unix編程手冊-58(SOCKET TCP/IP網絡基礎)略

netstat -idom

linux/unix編程手冊-59(SOCKET Internet Domain)

網絡字節序

  • 因爲端口號和IP地址須要被網絡中的全部主機理解,須要統一標準字節序,即網絡字節序,它是大端的
#include<arpa/inet.h>

// return netword byte order
uint16_t htons(uint16_t host_uint16);

uint32_t htonl(uint32_t host_uint32);

// return host byte order

uint16_t ntohs(uint16_t net_uint16);

uint32_t ntohl(uint32_t net_uint32);
複製代碼

internet socket 地址

#include<netinet/in.h>

struct in_addr {                /* IPv4 4-byte address */
    in_addr_t s_addr;           /* Unsigned 32-bit integer */
};
struct sockaddr_in {            /* IPv4 socket address */
    sa_family_t sin_family;     /* Address family (AF_INET) */
    in_port_t sin_port;         /* Port number */
    struct in_addr sin_addr;    /* IPv4 address */
    unsigned char __pad[X];     /* Pad to size of 'sockaddr' structure (16 bytes) */
};

struct in6_addr {               /* IPv6 address structure */
    uint8_t s6_addr[16];        /* 16 bytes == 128 bits */
};
struct sockaddr_in6 {           /* IPv6 socket address */
    sa_family_t sin6_family;    /* Address family (AF_INET6) */
    in_port_t sin6_port;        /* Port number */
    uint32_t sin6_flowinfo;     /* IPv6 flow information */
    struct in6_addr sin6_addr;  /* IPv6 address */
    uint32_t sin6_scope_id;     /* Scope ID (new in kernel 2.4) */
};
複製代碼
#include<arpa/inet.h>
// 二進制ip地址和可讀ip地址('127.0.0.1')轉換
int inet_pton(int domain, const char *src_str, void *addrptr);
//return 1 success, 0 格式str不催, -1 error
const char *inet_ntop(int domain, const void *addrptr, char *dst_str, size_t len);
//return dst_str的指針success, NULL error
複製代碼

域名系統(DNS)

  • 解析也是從頂級域名開始一級級解析
  • 域名的補全規則定義在/etc/resolv.conf文件中,默認會用本機域名補全
  • /etc/services記錄了(IANA)端口號和服務名

主機和服務的轉換

#include<sys/socket.h>
#include<netdb.h>

int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);
//return 0 success, other error,可能須要向DNS服務器發請求

struct addrinfo {
    int ai_flags;               /* Input flags (AI_* constants) */
    int ai_family;              /* Address family (AF_INET | AF_INET6)*/
    int ai_socktype;            /* Type: SOCK_STREAM, SOCK_DGRAM */
    int ai_protocol;            /* Socket protocol */
    size_t ai_addrlen;          /* Size of structure pointed to by ai_addr */
    char *ai_canonname;         /* Canonical name of host */
    struct sockaddr *ai_addr;   /* Pointer to socket address structure */
    struct addrinfo *ai_next;   /* Next structure in linked list */
};

int freeaddrinfo(struct addrinfo *result);
//釋放result分配的內存

int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, size_t hostlen, char *service, size_t servlen, int flags);
// 0 success, other fail,不想要獲取的參數傳NULL,len設爲0

複製代碼

getaddrinfosocket

  • host 爲主機名或者ip字符串
  • service 爲一個服務名或者十進制端口號
  • hint指向的結構規定了,result返回的socket地址結構的標準。hint能夠設置ai_flagsai_familyai_socktypeai_protocol字段用做過濾
  • result指向一個包含addrinfo結構鏈表的表頭

CS實現代碼(略)

linux/unix編程手冊-60(SOCKET 服務器的設計)(大部分略)

併發型服務器的其餘設計方案

  • 預先建立進/線程池,動態改變池大小
  • 單個進程處理多個客戶端(I/O多路複用,信號驅動,或者epoll)
  • 服務器集羣
    • DNS輪轉負載共享,緩存,沒法良好的負載均衡,沒法確保高可用等一些問題
    • 負載均衡

inetd守護進程(看不到在用的)

用來消除運行大量很是用服務器進程的須要tcp

  • 監視一組指定套接字端口,按須要啓動其它服務
  • 簡化了啓動其它服務的編程工做

inetd守護進程一般在系統啓動時運行。以後執行以下步驟

  • /etc/inetd.conf中指定的每項服務,inetd都會建立一個恰當類型的套接字,而後綁定到指定端口上,TCP的話會listen
  • 經過select監視
  • select阻塞直到有請求,在TCP中會先accept建立新的socket
  • inetd調用fork建立一個新的進程,exec()啓動服務器程序,在exec()以前
    • 除了socket描述符外,關閉其餘繼承的文件描述符
    • 在0,1,2上覆制套接字文件描述符,關閉套接字文件描述符自己(這樣相應代碼直接從標準輸出輸入讀取寫入客戶端信息就行了)
    • 爲啓動進程設定與用戶和組ID
  • 若是是tcp而且accept建立了socket fd,inetd關閉這個描述符
  • 繼續select監視
相關文章
相關標籤/搜索