日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

unix网络编程

發(fā)布時(shí)間:2024/2/28 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 unix网络编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

寫在前面: 最近在看nginx具體接口的實(shí)現(xiàn),發(fā)現(xiàn)一些網(wǎng)絡(luò)接口不是很熟悉,大概看了下Unix網(wǎng)絡(luò)編程,發(fā)現(xiàn)上面都有具體介紹。后續(xù)這段時(shí)間攻讀下這本教程。

記于 2018-1-30

第三章 ? 套接字編程簡(jiǎn)介

1. IPv4套接字地址結(jié)構(gòu)

IPv4套接字地址結(jié)構(gòu)通常也稱為“”網(wǎng)際套接字地址結(jié)構(gòu)“”, 他以sockaddr_in命名, 定義在<netinet/in.h>中

struct in_addr{in_addr_t s_addr; //32-bit IPv4 address, network byte ordered};

struct sockaddr_in{uint8_t sin_len; //length of structure(16)sa_family_t sin_family; //AF_INETin_port_t sin_port; //16-bit TCP or UDP port numberstruct in_addr sin_addr; char sin_zero; //unused};


2. 通用套接字地址結(jié)構(gòu)

當(dāng)作為一個(gè)參數(shù)傳遞進(jìn)任何套接字函數(shù)時(shí), 套接字地址結(jié)構(gòu)總是以引用形式(也就是指向該結(jié)構(gòu)的指針)來傳遞,然而以這樣的指針作為參數(shù)之一的任何套接字函數(shù)必須處理來自所支持的任何協(xié)議族的套接字地址結(jié)構(gòu)

//<sys/socket.h>struct sockaddr { uint8_t sa_len; sa_family_t sa_family; //address family:AF_xxx value char sa_data[14]; //portocol-specific address };

3. IPv6 套接字地址結(jié)構(gòu)

//<netinet/in.h> struct in6_addr{ uint8_t s6_addr[16]; //128-bit IPv6 address network byte ordered };#define SIN6_LEN; //required for compile-time testsstruct sockaddr_in6{ uint8_t sin6_len; //length of this struct sa_family_t sin6_family; //AF_INET6 in_port_t sin6_port; //transport layer port//network byte ordered uint32_t sin6_flowinfo; //flow information undefined struct in6_addr sin6_addr; //IPv6 address uint32_t sin6_scope_id; //set of interfaces for a scope };

4. 套接字地址結(jié)構(gòu)是在進(jìn)程和內(nèi)核之間傳遞的

從進(jìn)程到內(nèi)核傳遞套接字地址結(jié)構(gòu)的函數(shù)有3個(gè):bind 、connect、sendto

從內(nèi)核到進(jìn)程傳遞套接字地址結(jié)構(gòu)的函數(shù)有4個(gè): accept、recvfrom、getsockname、getpeername


5. 術(shù)語(yǔ)“小端”和“大端”表示多個(gè)字節(jié)值的哪一端(小端或大端)存儲(chǔ)在該值的起始位置

我們把某個(gè)給定系統(tǒng)所用的字節(jié)序稱為主機(jī)字節(jié)序(host byte order)

主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換函數(shù)

#include<netinet/in.h>uint16_t htons(uint16_t host16bitvalue); uint32_t htonl(uint32_t host32bitvalue);//均返回:網(wǎng)絡(luò)字節(jié)序的值uint16_t ntohs(uint16_t net16bitvalue); uint32_t ntohl(uint32_t net32bitvalue);//均返回:主機(jī)字節(jié)序的值其中: h代表host, n代表network, s 代表short, l 代表long

6. 字節(jié)操作函數(shù)

名字以b開頭的函數(shù)起源于4.2BSD, 名字以mem(表示內(nèi)存)開頭的函數(shù)起源于ANSI C標(biāo)準(zhǔn)

下面是Berkeley函數(shù):

#include<strings.h>void bzero(void* dest, size_t nbytes); void bcopy(const void* src, void* dest, size_t nbytes); void bcmp(const void* ptr1, const void* ptr2, size_t nbytes); //返回:若相等則為0, 否則為非0

下面是ANSI C函數(shù):

#include<string.h>void* memset(void* dest, int c, size_t len); void* memcpy(void* dest, const void* src, size_t nbytes); int memcmp(const void* ptr1, const void* ptr2, size_t nbytes); //若相等則為0,否則為>0或<0

7. inet_aton 、inet_addr、 inet_ntoa 函數(shù)

#include<arpa/inet.h>int inet_aton(const char* strptr, struct in_addr* addrptr); //返回:若字符串有效則為1, 否則為0in_addr_t inet_addr(const char* strptr); //返回:若字符串有效則為32位二進(jìn)制網(wǎng)絡(luò)字節(jié)序的IPv4地址,否則為INADDR_NONEchar* inet_ntoa(struct in_addr inaddr); //返回:指向一個(gè)點(diǎn)分十進(jìn)制數(shù)串的指針

inet_aton將strptr所指C字符串轉(zhuǎn)換成一個(gè)32位的網(wǎng)絡(luò)字節(jié)序二進(jìn)制值,并通過指針addrptr來存儲(chǔ)。

8. inet_pton 和 inet_ntop 函數(shù)

這兩個(gè)函數(shù)是隨IPv6出現(xiàn)的新函數(shù)。函數(shù)名中p和n分別代表表達(dá)(presentation)和數(shù)值(numeric)。

地址的表達(dá)式格式通常是ANSII字符串,數(shù)值格式則是存放到套接字地址結(jié)構(gòu)中的二進(jìn)制值

#include<arpa/inet.h>int inet_pton(int family, const char* strptr, void* addrptr); //返回:若成功則為1, 若輸入不是有效的表達(dá)式格式則為0, 若出錯(cuò)則為-1const char* inet_ntop(int family, const void* addrptr, char* strptr, size_t len); //返回:若成功則為指向結(jié)果的指針,若出錯(cuò)則為NULL

注: 表達(dá)格式就是 點(diǎn)分十進(jìn)制格式, 數(shù)值格式就是in_addr{} 格式

表達(dá)格式就是在一個(gè)IPv4 的點(diǎn)分十進(jìn)制數(shù)串之后,或者在一個(gè)括以方括號(hào)的IPv6地址的十六進(jìn)制數(shù)串格式之后,跟一個(gè)終止符(分號(hào)),再跟一個(gè)十進(jìn)制的端口號(hào),最后跟一個(gè)空字符。

因此,緩沖區(qū)大小對(duì)于IPv4至少為INET_ADDRSTRLEN加上6個(gè)字節(jié)(16+6=22),對(duì)于IPv6至少為INET6_ADDRSTRLEN加上8個(gè)字節(jié)(46+8=54)


9. sock_ntop和相關(guān)函數(shù)

#include"unp.h" char* sock_ntop(const struct sockaddr* sockaddr, socklen_t addlen);

sockaddr指向一個(gè)長(zhǎng)度為addrlen的套接字地址結(jié)構(gòu)。


10. 字節(jié)流套接字

字節(jié)流套接字(如TCP套接字)上的read和write函數(shù)所表現(xiàn)的行為不同于通常的文件I/O, 字節(jié)流套接字上調(diào)用read和write輸入或輸出的字節(jié)數(shù)可能比請(qǐng)求的數(shù)量少,然而這不是出錯(cuò)的狀態(tài),這個(gè)現(xiàn)象的原因在于內(nèi)核中用于套接字的緩沖區(qū)可能已經(jīng)達(dá)到了極限。此時(shí)所需的是調(diào)用者再次調(diào)用read和write函數(shù)。


第四章 ? 基本TCP套接字編程


1. socket函數(shù)

#include<sys/socket.h>int socket(int family, int type, int portocol); //返回:若成功則為非負(fù)描述符,若出錯(cuò)則為-1

family 參數(shù)指明協(xié)議族, type指明套接字類型。 protocol設(shè)為某個(gè)協(xié)議類型常值,或者設(shè)為0

family說明
AF_INETIPv4協(xié)議
AF_INET6IPv6協(xié)議
AF_LOCALUNIX域協(xié)議
AF_ROUTE路由套接字
AF_KEY秘鑰套接字

type說明
SOCK_STREAM字節(jié)流套接字
SOCK_DGRAM數(shù)據(jù)報(bào)套接字
SOCK_SEQPACKET有序分組套接字
SOCK_RAW原始套接字
protocol說明
IPPROTO_TCPTCP傳輸協(xié)議
IPPROTO_UDPUDP傳輸協(xié)議
IPPROTO_SCTPSTCP傳輸協(xié)議

2. connect函數(shù)

#include<sys/socket.h> int connect(int sockfd, const struct sockaddr* seraddr, socklen_t addrlen);

返回: 若成功則為0, 若出錯(cuò)則為-1

按照TCP狀態(tài)轉(zhuǎn)換圖,connect函數(shù)導(dǎo)致當(dāng)前套接字從CLOSED 狀態(tài)(該套接字自從由socket函數(shù)創(chuàng)建以來一直所處的狀態(tài))轉(zhuǎn)移到SYN_SENT狀態(tài),若成功則再轉(zhuǎn)移到ESTABLISHED狀態(tài)。

若connect失敗則該套接字不再可用,必須關(guān)閉,我們不能對(duì)這樣的套接字再次調(diào)用connect函數(shù)。


3. bind函數(shù)

bind函數(shù)把一個(gè)本地協(xié)議地址賦予一個(gè)套接字

?

#include<sys/socket.h> int bind(int sockfd, const struct sockaddr* myaddr, socklen_t addrlen);

對(duì)于TCP, 調(diào)用bind函數(shù)可以指定一個(gè)端口號(hào),或指定一個(gè)IP地址,也可以兩者都指定,還可以都不指定

如果一個(gè)TCP客戶或者服務(wù)器未曾調(diào)用bind捆綁一個(gè)端口,當(dāng)調(diào)用connect或listen時(shí),內(nèi)核就要為相應(yīng)的套接字選擇一個(gè)臨時(shí)端口。讓內(nèi)核來選擇臨時(shí)端口對(duì)于TCP客戶來說是正常的,除非應(yīng)用需要一個(gè)預(yù)留端口。

進(jìn)程指定?結(jié)果
IP地址端口?
通配地址0內(nèi)核選擇IP地址和端口
通配地址非0內(nèi)核選擇IP地址, 進(jìn)程指定端口
本地IP地址0進(jìn)程指定IP地址,內(nèi)核選擇端口
本地IP地址非0進(jìn)程指定IP地址和端口

4. listen函數(shù)

根據(jù)TCP狀態(tài)轉(zhuǎn)換圖,調(diào)用listen導(dǎo)致套接字從CLOSED狀態(tài)轉(zhuǎn)換到LISTEN狀態(tài)

#include<sys/socket.h> int listen(int sockfd, int backlog); //返回:若成功返回0,失敗返回-1

內(nèi)核為任何一個(gè)給定的監(jiān)聽套接字維護(hù)兩個(gè)隊(duì)列:

* 未完成連接隊(duì)列

* 已完成連接隊(duì)列


5. accept函數(shù)

accept函數(shù)由TCP服務(wù)器調(diào)用,用于從已完成連接隊(duì)列頭返回下一個(gè)已完成連接

#include<sys/socket.h> int accept(int sockfd, struct sockaddr* cliaddr, socklen_t* addrlen);//返回:若成功則為非負(fù)描述符,若出錯(cuò)則為-1

cliaddr 和addrlen 用來返回對(duì)方進(jìn)程(客戶)的協(xié)議地址。也就是返回客戶端的IP地址

我們稱第一個(gè)參數(shù)sockfd為監(jiān)聽套接字(listening socket)描述符(由socket創(chuàng)建,隨后用作bind和listen的第一個(gè)參數(shù)的描述符)

稱它的返回值為已連接套接字(connected socket)描述符

個(gè)服務(wù)器通常僅僅創(chuàng)建一個(gè)監(jiān)聽套接字,它在該服務(wù)器的生命期內(nèi)一直存在。內(nèi)核為每個(gè)由服務(wù)器進(jìn)程接收的客戶創(chuàng)建一個(gè)已連接套接字(也就是說對(duì)于它的三次握手過程已經(jīng)完成)。當(dāng)服務(wù)器完成對(duì)某個(gè)給定客戶的服務(wù)時(shí),相應(yīng)的已連接套接字就會(huì)關(guān)閉。

如果accept函數(shù)的第二個(gè)和第三個(gè)參數(shù)都是空指針,表示我們隊(duì)客戶的身份不感興趣

6. fork和exec函數(shù)

#include<unistd.h> pid_t fork();返回:在子進(jìn)程中為0,在父進(jìn)程中為子進(jìn)程Id, -1--出錯(cuò)

fork函數(shù)調(diào)用一次,返回兩次。

在調(diào)用進(jìn)程(成為父進(jìn)程),它返回一次,返回值是新派生進(jìn)程(成為子進(jìn)程)的進(jìn)程ID;在子進(jìn)程它還返回一次,返回值為0.

因此可以用返回值來判斷當(dāng)前進(jìn)程是子進(jìn)程還是父進(jìn)程

fork 在子進(jìn)程返回0而不是父進(jìn)程ID,原因是:子進(jìn)程只有一個(gè)父進(jìn)程,它總是可以調(diào)用getppid來得到

fork有兩個(gè)典型應(yīng)用:

1. 一個(gè)進(jìn)程可以為自己創(chuàng)建一個(gè)拷貝,這樣,當(dāng)一個(gè)拷貝處理一個(gè)操作時(shí),其他的拷貝可以執(zhí)行其他的任務(wù)。這是非常典型的網(wǎng)絡(luò)服務(wù)器

2. 一個(gè)進(jìn)程想執(zhí)行其他的程序,由于創(chuàng)建進(jìn)程的唯一方法是調(diào)用fork,進(jìn)程首先調(diào)用fork來生成一個(gè)拷貝,然后其中一個(gè)拷貝(通常為子進(jìn)程)調(diào)用exec來代替自己去執(zhí)行新程序。

#include<unistd.h> int execve(const char* pathname, char* argv[], char* const envp[] );返回:-1--出錯(cuò), 無(wú)返回--成功

7. close函數(shù)

#include<unistd.h> int close(int sockfd);return: 0-ok, -1--error

8. getsockname 和getpeername函數(shù)

#include<sys/socket.h> int getsockname(int sockfd, struct sockaddr* localaddr, socklen_t* addrlen); int getpeername(int sockfd, struct sockaddr* peeraddr, socklen_t* addrlen);return : 0-ok, -1-error

getsockname : 返回與套接字關(guān)聯(lián)的本地協(xié)議地址

getpeername:? 返回與套接字關(guān)聯(lián)的遠(yuǎn)程協(xié)議地址

當(dāng)一個(gè)服務(wù)器由調(diào)用accept的進(jìn)程調(diào)用exec啟動(dòng)執(zhí)行時(shí),它獲得客戶身份的唯一途徑就是調(diào)用getpeername


第七章 套接字選項(xiàng)

7.1 概述??

有很多方法來獲取和設(shè)置影響套接字接口的選項(xiàng)

* getsockopt 和setsockopt

* fcntl

* ioctl


7.2 getsockopt 和setsockopt 函數(shù)

#include<sys/socket.h> int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen);int setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t* optlen);return : 0-ok, -1-error

sockfd: 指向一個(gè)打開的套接字描述符

level:

????? ? SOL_SOCKET :?

????????IPPROTO_TCP :?

optname:?

????SO_REUSEADDR :? 允許重用本地地址

????SO_REUSEPORT :?允許重用本地地址

????SO_KEEPALIVE :? 如果2 小時(shí)內(nèi)在此套接字的任一方向都沒有數(shù)據(jù)交換,TCP就自動(dòng)給對(duì)方發(fā)一個(gè)keepalive probe

????SO_RCVBUF : 接收緩沖區(qū)大小

????SO_SNDBUF:發(fā)送緩沖區(qū)大小

????SO_SETFIB :?

????SO_SNDLOWAT : 發(fā)送低潮限度, select函數(shù)使用

????SO_ACCEPTFILTER :?

????SO_UPDATE_ACCEPT_CONTEXT

????SO_BINDANY :?

????SO_LINGER : 若有數(shù)據(jù)待發(fā)送則延遲關(guān)閉


????TCP_FASTOPEN :?

????TCP_NODELAY :? ? ?禁止Nagle 算法

????TCP_DEFER_ACCEPT :?

????TCP_NOPUSH

????TCP_CORK


????IP_RECVDSTADDR :? 返回目的ip地址

????IP_PKTINFO :? ??

????IP_BIND_ADDRESS_NO_PORT :?

????IP_TRANSPARENT :?


????IPV6_RECVPKTINFO :?

????IPV6_V6ONLY:?

????IPV6_TRANSPARENT:?

????IPV6_BINDANY :?


? ? 管道的容量稱為帶寬-延遲積(bandwidth-delay product), 我們可以將帶寬(位/秒)乘上RTT(秒),并將結(jié)果由位轉(zhuǎn)換成字節(jié)來計(jì)算得到。




超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的unix网络编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。