APUE筆記 網絡IPC

套接字描述符


#include <sys/scoket.h>

int socket(int domain, int type, int protocol);

domain 

協議族:

AF_INETipv4

AF_INET6ipv6

AF_UNIX unix域


type

套接字類型

SOCKET_STREAM 流式字節流,tcp時使用這個 

SOCKET_DGRAM   固定長度,無連接,不可靠協議  UDP使用這個

SOCKET_SEQPACKET 長度固定,有序可靠,面向連接的報文 ,讀發的字節數是相等的

SOCKET_RAW  允許直接操作IP,需要root權限


type == 0 時使用默認協議 tcp udp,,,


#include <sys/socket.h>

int shutdouwn(int fd, int how);

SHUTDOWN_RD         關閉讀

SHUTDOWN_WR        關閉寫

SHUTDOWN_RDWR  關閉讀寫

相對於close 只有所有引用socket描述符(dup dup2)的都關閉才能關閉文件

shutdown 可以控制socket與 描述符引用無關!

方便控制寫,讀


字節序

由於歷史原因,tcp/ip的字節序是打算字節序

現在很多服務器,pc都是小端序,so爲支持tcp/ip,地址端口必須轉換爲網絡地址序(大端序)

對於數據,只要發送端和接收端都是小端序就沒問題!

#include <arpa/inet.h>

uint32_t htonl(uni32_t hostint32);//ip用這個

uint16_t htons(uni16_t hostint16);//端口用這個

uint32_t ntohl(uni32_t net32);//網絡序轉換成小端序 ip

uint16_t ntohl(uni32_t net16);//網絡序轉換成小端序 端口用


地址格式

struct sockaddr

{

    sa_family_t sa_family;

    char sa_data[];

...

};


struct in_addr

{

    in_addr s_addr;//ipv4的地址

};


struct sockaddr_in

{

    sa_family_t sin_family;//地址族

    in_port_t sin_port;

    struct in_addr sin_addr;//ip地址

};

family ipv4 AF_INET

          ipv6 AF_INET6


由於歷史原因,在bind和connect中地址都強制轉換成sockaddr


#include <arpa/inet.h>

const char* inet_ntop(int domain, const void*restrict addr, const char *restrict str, socklen_t bufsize);

socksize  str緩衝區大小,防止越界

成功返回轉換後的字符串,失敗返回NULL


int inet_pton(int domain, const char* restrict str, void *restrict addr);

成功返回0,失敗返回-1

轉換後的結果存放在add指向的地址r中


套接字綁定地址

#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t len);

len 表示addr的字節長度

地址端口號必須>=1024,在root權限下可以 < 1024

必須綁定本機的地址

INADDR_ANY可以綁定到本機安裝的所有網卡


可以通過getsockname 獲取fd上綁定的地址,若fd未綁定地址則結果未定義

#include <sys/socket.h>

int getsocketname(int fd, struct sockaddr *restrict addr, socklen_t *alenp);

alenp填充返回的addr的字節數

地址通過addr返回

如果addr緩衝區大小不匹配,自動截斷,不報錯

int getpeername(int fd, struct sockaddr *restrict addr, socklen_t *alenp);

返回鏈接另一端的地址信息

O_NOBLOCK

int connect(int sockfd, struct sockaddr *addr, socklen_t len);

客戶端可以向指定的服務器地址嘗試建立連接

若服務器端,未運行可接受連接,則返回-1

對udp也可以用此函數,則此函數會將fd與目的端地址綁定

在linux下如果連接失敗,還可以繼續使用fd再次連接,但在有些系統中,不能再用需要用socket函數產生一個新的fd

若果是爲了可移植性,需要在失敗後在socket()


int listen(int fd, int backlog);

在服務器端用此函數

此函數backlog設置fd,在三次握手未成功,和剛建立連接的隊列的最大排隊值 tcp默認128



int accept(int fd, struct socketaddr *restrict addr, socklen_t len);

用於TCP

監聽連接connect請求,客戶端的地址填充到addr中,len表示addr的字節數

在fd未設置O_NOBLOCK時,阻塞直到連接請求到來

若fd設置了O_NOBLOCK,則返回-1,errno EWOULDBLOCK

成功返回一個新的 socket fd連接到客戶端


tcp中有  用於accept的fd 綁定到本機的ip,用於接受連接請求

還有直接連接客戶端的fd,讀寫的數據都是發送到客戶端,讀客戶端的數據

accept的fd accept成功 返回連接到客戶端的fd

TCP socket的服務器端& 客戶端代碼順序

服務端

int fd = socket()產生一個socketfd

設置地址信息sockaddr_in ip 端口

bind(fd, &addr, len)綁定fd與本地地址

listen 設置可正在握手,和剛握手成功的等待隊列大小

rwfd = accept

讀寫 fd


客戶端

int fd = socket()產生一個socketfd

設置地址信息sockaddr_in ip 端口

connect

用fd讀寫

套接字選項

套接字機制使用了set 和get函數,來獲取和設置socket的

通用套接字選項

套接字層次管理的選項

特定協議選項


int setsockopt(int fd, int level, int op, const void *val, sock_len len);

int getsockopt(int fd, int level, int op, void * val, socklen_t lenp);








































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