linux/unix编程手册-56_60
生活随笔
收集整理的這篇文章主要介紹了
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方法。允許單臺或通過網絡連接的主句進程間交換數據
- 各應用程序創建一個socket
- 服務器將自己的socket綁定到一個都知道的地址上
fd=socket(domain, type, protocol)
系統調用
int socket(int domain, int type, int protocal) //return fd success, -1 errorint bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //return 0 s, -1 estruct 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
int listen(int sockfd, int backlog); //return 0 s, -1 eint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //return fd success, -1 errorint 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
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 errorssize_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關閉后自動刪除抽象名
- 權限無需寫權限
其他
int socketpair(int domain, int type, int protocol, int sockfd[2]); 復制代碼- domian只能是AF_UNIX
- 調用完sockpair之后,進程會fork一個子進程,子進程繼承fd副本進行通信
linux/unix編程手冊-58(SOCKET TCP/IP網絡基礎)略
netstat -i
linux/unix編程手冊-59(SOCKET Internet Domain)
網絡字節序
- 由于端口號和IP地址需要被網絡中的所有主機理解,需要統一標準字節序,即網絡字節序,它是大端的
internet socket 地址
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) */ }; 復制代碼 // 二進制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)端口號和服務名
主機和服務的轉換
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復制代碼getaddrinfo
- host 為主機名或者ip字符串
- service 為一個服務名或者十進制端口號
- hint指向的結構規定了,result返回的socket地址結構的標準。hint可以設置ai_flags,ai_family,ai_socktype,ai_protocol字段用作過濾
- result指向一個包含addrinfo結構鏈表的表頭
CS實現代碼(略)
linux/unix編程手冊-60(SOCKET 服務器的設計)(大部分略)
并發型服務器的其他設計方案
- 預先創建進/線程池,動態改變池大小
- 單個進程處理多個客戶端(I/O多路復用,信號驅動,或者epoll)
- 服務器集群
- DNS輪轉負載共享,緩存,無法良好的負載均衡,無法確保高可用等一些問題
- 負載均衡
inetd守護進程(看不到在用的)
用來消除運行大量非常用服務器進程的需要
- 監視一組指定套接字端口,按需要啟動其它服務
- 簡化了啟動其它服務的編程工作
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監視
總結
以上是生活随笔為你收集整理的linux/unix编程手册-56_60的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务器的攻与防(firewall 禁止指
- 下一篇: SDUT-2449_数据结构实验之栈与队