網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
1.網(wǎng)絡(luò)通信
1.消息傳遞(管道、FIFO、消息隊(duì)列)
2.同步(互斥量、條件變量、讀寫(xiě)鎖、文件和寫(xiě)記錄鎖、信號(hào)量)
3.共享內(nèi)存(匿名的和具名的)
使用TCP/IP協(xié)議 通過(guò)socket完成
2.posix API
目的:實(shí)現(xiàn)不同系統(tǒng)上的源代碼的可移植性。
舉例:linux和windows都要實(shí)現(xiàn)基本的posix標(biāo)準(zhǔn),linux把fork函數(shù)封裝成posix_fork(隨便說(shuō)的),windows把creatprocess函數(shù)也封裝成posix_fork,都聲明在unistd.h里。這樣,程序員編寫(xiě)普通應(yīng)用時(shí)候,只用包含unistd.h,調(diào)用
3.POSIX網(wǎng)絡(luò)API
4.函數(shù)內(nèi)部過(guò)程解析
4.1 socket套接字創(chuàng)建
int socket(int domain, int type, int protocol);
//參數(shù)分別是地址族、 套接字類型和協(xié)議
//AF_INET SOCK_STREAM 可默認(rèn)為0
//IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等
4.2 bind 綁定端口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:即socket描述字
addr:一個(gè)const struct sockaddr *指針,指向要綁定給sockfd的協(xié)議地址。
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0 監(jiān)聽(tīng)時(shí),監(jiān)聽(tīng)所有的地址
server_addr.sin_port = htons(port);
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET 協(xié)議族*/
in_port_t sin_port; /* port in network byte order 端口號(hào)*/
struct in_addr sin_addr; /* internet address IP地址*/
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
通常服務(wù)器在啟動(dòng)的時(shí)候都會(huì)綁定一個(gè)眾所周知的地址(如ip地址+端口號(hào)),用于提供服務(wù),客戶就可以通過(guò)它來(lái)接連服務(wù)器;而客戶端就不用指定,有系統(tǒng)自動(dòng)分配一個(gè)端口號(hào)和自身的ip地址組合。這就是為什么通常服務(wù)器端在listen之前會(huì)調(diào)用bind(),而客戶端就不會(huì)調(diào)用,而是在connect()時(shí)由系統(tǒng)隨機(jī)生成一個(gè)。但是我認(rèn)為客戶端也可以綁定。
4.3 網(wǎng)絡(luò)字節(jié)序和主機(jī)字節(jié)序
小端:小字節(jié)放前面,大字節(jié)放后面
大端:大字節(jié)放前面,小字節(jié)放后面
轉(zhuǎn)換端口
uint16_t htons(uint16_t hostshort); //主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序
uint16_t ntohs(uint16_t netshort); //網(wǎng)絡(luò)字節(jié)序->主機(jī)字節(jié)序
轉(zhuǎn)IP
htonl(uint32_t hostlong);//主機(jī)字節(jié)序->網(wǎng)絡(luò)字節(jié)序
ntohl(uint32_t netlong);//網(wǎng)絡(luò)字節(jié)序->主機(jī)字節(jié)序
4.4 listen監(jiān)聽(tīng)fd
int listen(fd,size) // 無(wú)錯(cuò)返回0,錯(cuò)誤返回-1
服務(wù)端調(diào)用listen()后,開(kāi)始監(jiān)聽(tīng)網(wǎng)絡(luò)上發(fā)送給socket的連接請(qǐng)求。
也就是說(shuō),開(kāi)始接收請(qǐng)求了。
4.5 connect發(fā)起連接請(qǐng)求
int connect(int sockfd,
const struct sockaddr *serv_addr,
int socklen_t addrlen);
4.6 accept()接收請(qǐng)求建立連接
accept()函數(shù)只做兩件事,將連接請(qǐng)求從全連接隊(duì)列中取出,給該連接分配一個(gè)fd并返回。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
4.7 消息的發(fā)送和接收
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count); // 目的fd 消息 消息長(zhǎng)度
ssize_t write(int fd, const void *buf, size_t count);
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
4.8 粘包問(wèn)題
2個(gè)數(shù)據(jù)包同時(shí)被提出,但是由于數(shù)據(jù)是在一起的,沒(méi)有辦法分離
解決方法:
- 在包頭添加一個(gè)數(shù)據(jù)包長(zhǎng)度的字段,標(biāo)明長(zhǎng)度來(lái)確定數(shù)據(jù)包
- 在包結(jié)束后添加分割符,這里注意分割符要選擇不經(jīng)常使用的
注意: 1優(yōu)于2,因?yàn)椋砑臃指罘?,需要遍歷整個(gè)消息來(lái)找到分隔符,這樣大大影響效率,但是2可以結(jié)合1使用。
4.9 close
#include <unistd.h>
int close(int fd);
close操作只是使相應(yīng)socket描述字的引用計(jì)數(shù)-1,只有當(dāng)引用計(jì)數(shù)為0的時(shí)候,才會(huì)觸發(fā)TCP客戶端向服務(wù)器發(fā)送終止連接請(qǐng)求。
過(guò)程分析
1.正常情況下一方調(diào)用close情況如下圖:
2.當(dāng)雙方同時(shí)調(diào)用close,如下圖:
當(dāng)同時(shí)發(fā)送close時(shí),兩邊同時(shí)發(fā)送fin 和ack 這時(shí)候調(diào)用time_wait等待消息發(fā)送完畢。
Fin_wait_1作用?
等待對(duì)方回復(fù),超時(shí)自動(dòng)重發(fā)fin。
Fin_wait_2作用?
等待對(duì)方業(yè)務(wù)邏輯處理后,發(fā)送fin包。這里有可能出現(xiàn)死等待的情況服務(wù)器如果出現(xiàn)大量的Fin_wait_2可能需要考慮是不是沒(méi)有close,或者close之前做了耗時(shí)操作。time_wait 作用?
防止最后一個(gè)ACK沒(méi)有順利到達(dá)對(duì)方,超時(shí)重新發(fā)送ack。time_wait時(shí)常一般是120s可以修改。
服務(wù)器掉線重啟出現(xiàn)端口被占用怎么辦?
其實(shí)主要是由于還處于time_wait狀態(tài),端口并沒(méi)有真正釋放。這時(shí)候可以設(shè)置SO_REUSEADDR屬性,保證掉線能馬上重連。
原文鏈接:https://blog.csdn.net/qq_42265608/article/details/127810657
相關(guān)推薦
- 2022-03-08 使用C語(yǔ)言實(shí)現(xiàn)本地socke通訊的方法_C 語(yǔ)言
- 2022-08-31 pandas基礎(chǔ)?Series與Dataframe與numpy對(duì)二進(jìn)制文件輸入輸出_python
- 2022-04-16 WPF框架Prism中View?Injection用法介紹_基礎(chǔ)應(yīng)用
- 2022-04-11 用python的哈希函數(shù)對(duì)密碼加密_python
- 2022-07-02 一個(gè)Python優(yōu)雅的數(shù)據(jù)分塊方法詳解_python
- 2023-07-16 spring boot多模塊打包 運(yùn)行
- 2022-12-08 linux服務(wù)器中搭建redis6.0.7集群_Redis
- 2022-03-03 css實(shí)現(xiàn)tooltip文字提示
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支