網(wǎng)絡(luò):
1.?OSI模型?
????*?物理層:硬件連接的接口。
????*?數(shù)據(jù)鏈路層:?通信道的無差錯傳輸,提供數(shù)據(jù)成幀。
????*?網(wǎng)絡(luò)層:?將數(shù)據(jù)正確并且迅速的從原點主機(jī)傳送到目的主機(jī)。
????*?傳輸層:?掩蓋下層結(jié)構(gòu)細(xì)節(jié),保證會話層的消息正確的傳輸?shù)搅硪环降臅拰印?/p>
????*?會話層:?實現(xiàn)兩端主機(jī)之間的會話管理。
????*?表示層:?信息轉(zhuǎn)換,壓縮,解密,代碼轉(zhuǎn)換。
????*?應(yīng)用層:?提供日常的應(yīng)用。
2.?網(wǎng)絡(luò)?
網(wǎng)絡(luò)連接也是一個文件,它也有文件描述符!
stdin:0?標(biāo)準(zhǔn)輸入
stdout:1?標(biāo)準(zhǔn)輸出
數(shù)據(jù)傳送不會消失,順序傳送,發(fā)送和接收非同步。
TCP/IP
TCP:保證數(shù)據(jù)的可靠性,和正確性。
IP:控制數(shù)據(jù)如何從源頭到達(dá)目的地。
3.?進(jìn)程?
??正在執(zhí)行的程序被稱為進(jìn)程,進(jìn)程樹頂端是init控制進(jìn)程。
*?fork()?調(diào)用進(jìn)程創(chuàng)建新的進(jìn)程。
*?wait()?進(jìn)程同步措施,使一個進(jìn)程等待進(jìn)程,到另一個進(jìn)程結(jié)束為止。
*?exit()?終止一個進(jìn)程的運行。
*?exec()?系統(tǒng)調(diào)用。
pid_t?fork(void);?//?創(chuàng)建一個進(jìn)程,返回進(jìn)程id是pid_t類型。
4.?TCP和UDP?
tcp:可靠的通信傳輸,面向連接,面向字節(jié)流,數(shù)據(jù)傳輸慢。
udp:不需要建立連接,不可靠通信傳輸,面向報文,速度快。
5.?常見端口及對應(yīng)服務(wù)?
21????FTP文件傳輸協(xié)議
22????SSH
23????Telnet
80????HTTP超文本傳輸協(xié)議
6379??redis默認(rèn)端口
6.?tcp三次握手?
??*?客戶端發(fā)送請求SYN報文段到服務(wù)器,進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)。??????發(fā)送?SYN=1?seq=client_isn
??*?服務(wù)器收到SYN進(jìn)行確認(rèn),回復(fù)給客戶端,進(jìn)入SYN_RECV狀態(tài)。?????????????????發(fā)送?SYN=1?seq=server_isn??ack=client_isn+1
??*?客戶端收到SYN_ACK報文段,進(jìn)入ESTABLISHED狀態(tài),完成三次握手。????????????發(fā)送?SYN=0?seq=clien_isn+1?ack=server_isn+1
7.?tcp四次揮手?
??*?客戶端發(fā)送連接釋放報文,停止發(fā)送數(shù)據(jù),進(jìn)入終止等待狀態(tài)?1?????????????????發(fā)送?FIN=1?seq=client_isn????????????????
??*?服務(wù)器收到報文,發(fā)出確認(rèn)報文ack帶上自己序列號seq,進(jìn)入等待關(guān)閉狀態(tài)???????發(fā)送??ack=client_isn+1??seq=server_isn
????*?客戶端收到服務(wù)器報文后,進(jìn)入終止等待狀態(tài)?2
??*?服務(wù)器發(fā)送完數(shù)據(jù)后,向客戶端發(fā)送釋放報文,自身進(jìn)入最后確認(rèn)狀態(tài)。??????????發(fā)送?FIN=1?ack=client_isn+1?seq=server_isn
??*?客戶端收到確認(rèn)后,發(fā)送最后確認(rèn),進(jìn)入wait狀態(tài),等待2*MSL時間。????????????發(fā)送?ack=server_isn+1?seq=client_isn+1
????*?服務(wù)器收到客戶端發(fā)出的確認(rèn),立即進(jìn)入close狀態(tài)。
8.?為什么結(jié)束連接的TIME_WAIT需要等待2MSL才能返回close狀態(tài)?
客戶端發(fā)送的最后一步的確認(rèn),不完全是可靠的,網(wǎng)絡(luò)可能存在別的異常情況。
所以客戶端會進(jìn)入TIME_WAIT狀態(tài),設(shè)置定時器,如果服務(wù)器一直發(fā)送第三步消息,client會再次發(fā)送確認(rèn)信息,并繼續(xù)等待2MSL時間。
2MSL:網(wǎng)絡(luò)的最大存活時間,一個發(fā)送和一個回復(fù)所需的最大時間。
直到服務(wù)器收到最后確認(rèn),不再發(fā)送FIN消息,就知道已經(jīng)被成功接收,結(jié)束tcp連接。
9.?建立了連接,客戶端故障。
tcp存在?;钣嫊r器。?服務(wù)器在既定時間(2h)沒有收到客戶端的任何消息。然后每隔一段時間(75s)發(fā)送一個探測報文段。
如果一連10次都沒有反應(yīng),將自動關(guān)閉這個連接。
10.?IP地址分類。
A???1.0.0.1?-?127.255.255.254
B???128.0.0.1?-?191.255.255.254
C???192.0.0.1?-?223.255.255.254
D???224.0.0.0?-?239.255.255.255
E???保留用于實驗使用
11.?tcp比udp慢的原因?
*?收發(fā)數(shù)據(jù)前后進(jìn)行的連接設(shè)置及清除過程。
*?收發(fā)過程中為保證數(shù)據(jù)可靠性添加的流控制。
12.?udp的傳輸函數(shù):
ssize_t?sendto(int?sock,?void?*buff,?size_t?nbytes,?int?flags,?struct?sockaddr?*to,?socklen_t?addrlen);
sock:?創(chuàng)建的套接字
buff:?傳輸數(shù)據(jù)的緩沖地址值。
nbytes:?待傳輸?shù)淖止?jié)數(shù)據(jù)
flags:?可選項參數(shù),無則是0
to:?發(fā)送對象地址。
addrlen:地址結(jié)構(gòu)體長度
13.?udp的接收函數(shù)?
ssize_t?recvfrom(int?sock,?void?*buff,?size_t?nbytes,?int?flags,?struct?sockaddr*?from,?socklen_t?addrlen);
和上面基本信息一樣。
14:udp
不存在請求和連接,因此某種意義上說,不區(qū)分服務(wù)器和客戶端。
15:回聲消息,read和write
tcp在發(fā)送數(shù)據(jù)時候,如果數(shù)據(jù)過大,會分包發(fā)送,如果write和read是同時進(jìn)行的,那么會存在,write還沒有把數(shù)據(jù)全部發(fā)送到服務(wù)器,
服務(wù)器回復(fù)一部分?jǐn)?shù)據(jù)時,read讀取會出現(xiàn)問題。
16.?什么是協(xié)議?
網(wǎng)絡(luò)中交換數(shù)據(jù)的標(biāo)準(zhǔn)規(guī)則,約定的集合。
17.?大端小端?
大端:高位字節(jié)存放到低位地址。
小端:高位字節(jié)存放到高位地址。
*?程序判斷:int?i?=?0x12345678?char?*c?=?(char?*)&i;?c[0]?==?0x12?小端
*?typedef?union?{
*???int?i;
*???char?c;
*?}?myunion;
*?myunion.i?=?1;?return?myunion.i?==?myunion.c
18.?tcp和udp的4層協(xié)議棧?經(jīng)過的層級結(jié)構(gòu)差異
應(yīng)用層,?tcp/udp層,IP層,鏈路層。
19.?write和read函數(shù)。
write和read交互,write可以直接一次性將數(shù)據(jù)發(fā)送到另一端,但是read不一定能全部讀取,因為數(shù)據(jù)量太大的情況下,read讀不全數(shù)據(jù)。
20.?udp
tcp在不可靠的IP層進(jìn)行流控制,udp缺少這種流控制。
tcp和udp最基本的區(qū)別就是流控制,其它區(qū)別所剩無幾。
21.?壓縮文件傳輸。
壓縮文件必須選擇tcp進(jìn)行傳輸,如果中途有數(shù)據(jù)丟失,解壓就會失敗,所以必須是選擇tcp進(jìn)行傳輸。
22.?gethostbyname?通過域名轉(zhuǎn)換為IP
struct?hostent{
??char?*h_name;????????//?office?name?官方域名
??char?**h_aliases;????//?alias?list?同一IP可以綁定多個域名,出官方域名,還有其它域名。
??int?h_addrtype;??????//?IP地址族信息,
??int?h_length;????????//
??char?**h_addr_list;??//?IP
}
23.?Nagle算法。tcp?消息。
只有收到前一數(shù)據(jù)的ACK消息時,Nagle算法才發(fā)送下一次數(shù)據(jù)。
開啟Nagle算法時候,會合理的減少流量,但是傳輸速度會降低。
關(guān)閉Nagle算法時候,會增加網(wǎng)絡(luò)流量,傳輸速度會增加,尤其是在大數(shù)據(jù)量的傳輸中,這種速度會很明顯。
注:未準(zhǔn)確判斷數(shù)據(jù)特性時不應(yīng)禁用Nagle算法。
禁用Nagle算法:?int?opt_val?=?1
開啟Nagle算法:?int?opt_val?=?0
setsockopt(sock,?IPPROTO_TCP,?TCP_NODELAY,?(void*)&opt_val,?sizeof(opt_val))
24.?并發(fā)服務(wù)器的實現(xiàn)。
多進(jìn)程服務(wù)器:?通過創(chuàng)建多個進(jìn)程提供服務(wù)。
多路復(fù)用服務(wù)器:?通過捆綁并統(tǒng)一管理I/O對象提供服務(wù)。
多線程服務(wù)器:?通過生成與客戶端等量的線程提供服務(wù)。
25.?進(jìn)程和子進(jìn)程
fork創(chuàng)建進(jìn)程之后,父進(jìn)程返回子進(jìn)程的進(jìn)程ID
子進(jìn)程返回0.
父子進(jìn)程,只共享一段代碼,有不同的數(shù)據(jù)存儲空間。
26.?僵尸進(jìn)程
子進(jìn)程比父進(jìn)程先結(jié)束,父進(jìn)程又沒有回收子進(jìn)程,釋放子進(jìn)程占用的資源。
應(yīng)向創(chuàng)建子進(jìn)程的父進(jìn)程傳遞子進(jìn)程的exit參數(shù)或return返回。
*?只有父進(jìn)程主動發(fā)起請求,操作系統(tǒng)才會傳遞該值。(父母要負(fù)責(zé)回收自己孩子。)
27.?wait函數(shù)
調(diào)用wait函數(shù)可以將終止的子進(jìn)程退出。wait函數(shù)會阻塞等待,直到有子進(jìn)程退出。
WIFEXITED?子進(jìn)程正常終止時返回?true
WEXITSTATUS?返回子進(jìn)程的返回值
28.?waitpid函數(shù)
wait函數(shù)會引起程序阻塞。waitpid(pid_t,?pid,?int?*?statloc,?int?options);成功返回終止的子進(jìn)程ID,失敗返回-1
參數(shù):?pid?等待目標(biāo)子進(jìn)程,若為-1,則可以等待任意子進(jìn)程退出。
statloc:?status??options:?WNOHANG即使沒有終止的子進(jìn)程,也不會進(jìn)入阻塞狀態(tài)。
29.?信號。
void?(*signal(int?signo,?void(*func)(int)))(int);
void?function(int?flag)?{}
調(diào)用signal?signal(SIGNO,?function)
接收第二個參數(shù)是一個函數(shù)指針(地址),函數(shù)的參數(shù)是int類型,返回值是void
30.??信號的高級用法:
??struct?sigaction?act;
??act.sa_handler?=?read_childproc;??
??sigemptyset(&act.sa_mask);??
??act.sa_flags?=?0;?????
??sigaction(SIGCHLD,&act,0);??//注冊信號,觸發(fā)SIGCHILD信號后將會調(diào)用act函數(shù)
??return?和?exit將會觸發(fā)到該信號。
??read_childproc函數(shù)如下:
??void?read_childproc(int?sig){??
??????int?status;??
??????pid_t?id?=?waitpid(-1,?&status,?WNOHANG);??
??????if(WIFEXITED(status)){??
????????printf("Removed?proc?id?:?%d?\n",id);??
????????printf("child?send?:?%d?\n",WEXITSTATUS(status));??
??????}???
??}
31.?進(jìn)程間通信->pipe
int?pipe(int?fileds[2])?fileds[0]?出口,?fileds[1]?入口
test:
??int?fds[2];?pipe(fds);?fork一個父進(jìn)程,和子進(jìn)程,子進(jìn)程寫數(shù)據(jù)到文件,父進(jìn)程從文件讀數(shù)據(jù),就實現(xiàn)了進(jìn)程間通信、
32.?fread和read
fread是C語言的庫,read是系統(tǒng)調(diào)用。
?read每次讀取要求大小的數(shù)據(jù),從用戶態(tài)切換到內(nèi)核態(tài)(損耗性能)
?fread每次從內(nèi)核緩沖區(qū)讀取較多的數(shù)據(jù),放到應(yīng)用進(jìn)程緩沖區(qū),下次再取直接去應(yīng)用進(jìn)程緩沖區(qū)取,不用消耗太多性能。
?33.?fwrite和write
?write是系統(tǒng)調(diào)用,每次需要將數(shù)據(jù)寫到磁盤,寫的大小是要求的大小,依然涉及頻繁的用戶態(tài)和內(nèi)核態(tài)切換。
?fwrite是庫函數(shù),每次講數(shù)據(jù)寫入到換乘區(qū),等緩沖區(qū)滿了,一次寫入磁盤?;蛘呤褂胒flush沖洗緩沖區(qū)。
?34.?sigaction?捕捉信號的類型
??????struct?sigaction?{
??????????void?(*sa_handler)(int);??//?信號處理函數(shù)
??????????void?(*sa_sigaction)(int,?siginfo_t?*,?void?*);
??????????sigset_t?sa_mask;?????????//?設(shè)置處理該信號時,暫時將sa_mask指定信號擱置
??????????int?sa_flags;?????????????//?信號其它相關(guān)操作。
??????????void?(*sa_restorer)(void);??//?
??????}
??注:聯(lián)合?信號的高級用法使用
35.?使用多任務(wù)并發(fā)服務(wù)器
??fork出來的子進(jìn)程,需要關(guān)閉ser_sockID?只保留父進(jìn)程的ser_sockID,持續(xù)去accept客戶端的連接。
??父進(jìn)程,只負(fù)責(zé)接收客戶端的連接,客戶端的cli_sockID?也需要關(guān)閉。
36.?I/O復(fù)用.
??select?將多個文件描述符,集中到一起進(jìn)行監(jiān)控。
??fd_set?set;?FD_ZERO,?清零。?FD_SET?設(shè)置1,?FD_CLR?單個清零。
37.?select函數(shù)
int?select(int?maxfd,?fd_set?*readset,?fd_set?*writeset,?fd_set?*exceptset,?const?struct?
timeval?*timeout)
調(diào)用select函數(shù)后,除了發(fā)生變化的描述符外,剩下的所有位都將被初始化為0。
38.?select使用。
在進(jìn)行select使用時候,需要維護(hù)兩個描述符集合(use,copy),兩個內(nèi)容一樣。
復(fù)制的copy,用作select調(diào)用傳入,當(dāng)有收到消息時候,copy內(nèi)除了有消息的描述符,其它都被置0。
所以只需要循環(huán)檢查,F(xiàn)D_ISSET?文件描述符是否存在copy中,如果存在,就證明這個有消息了。開始處理吧。
39.?多播(組播)、廣播.
int?so_ard?=?1
廣播:?setsockopt(sockid,?SOL_SOCKET,?SOL_BORADCAST,?(void?*)&so_ard,?sizeof(so_ard))
40.?標(biāo)準(zhǔn)IO的缺點
*?不容易進(jìn)行雙向通信
*?有時可能需要頻繁的調(diào)用fflush
*?需要以FILE結(jié)構(gòu)體指針的形式返回文件描述符
41.?select的弊端
無論如何優(yōu)化程序性能,也無法同時接入上百個客戶端,select不適合以web服務(wù)器端。
42.?select函數(shù)
每次調(diào)用select函數(shù)時,向操作系統(tǒng)傳遞檢視對象信息。
僅向操作系統(tǒng)傳遞1次監(jiān)視對象,監(jiān)視的范圍發(fā)生變化時,只通知發(fā)生變化的事項。
43.?epoll的優(yōu)點
無需編寫以檢視狀態(tài)變化為目的的針對所有文件描述符的循環(huán)語句。
調(diào)用對于select函數(shù)的epoll_wait函數(shù)時,無需每次傳遞檢視對象信息。
44.?epoll需要的3個函數(shù)
epoll_create?創(chuàng)建保存epoll文件描述符的空間
epoll_ctl?想空間注冊并注銷文件描述符
epoll_wait?與select函數(shù)類似,等待文件描述符發(fā)生變化
45.?select和epoll不同點
select需要FD_SET,?FD_CLR函數(shù)。????????epoll需要通過epoll_wait函數(shù)。
select下調(diào)用select函數(shù)等待描述符變化。?epoll中調(diào)用epoll_wait函數(shù)。
select下通過fd_set查看檢視對象的變化。?epoll中通過結(jié)構(gòu)體epoll_event將發(fā)生變化的文件描述符幾種到一起。
struct?epoll_event?{
??__unit32_t?events;
??epoll_data_t?data;
}
46.?epoll_create(int?size)函數(shù)
epoll_create創(chuàng)建的文件描述符保存空間稱為"epoll例程",?
參數(shù)size的值,決定epoll例程的大小。
47.?epoll_ctl
生成epoll例程后,在內(nèi)部注冊監(jiān)視對象文件描述符,使用epoll_ctl函數(shù)。
epoll_ctl(int?epfd,?int?op,?int?fd,?struct?epoll_event?*?event)
op參數(shù)的模型如下?
?*?EPOLL_CTL_ADD?注冊到例程中
?*?EPOLL_CTL_DEL?例程中刪除文件描述符
?*?EPOLL_CTL_MOD?更改文件描述符的關(guān)注事件發(fā)生情況
?48.?epoll_wait
int?epoll_wait(int?fd,?struct?epoll_event*?events,?int?maxevents,?int?timeout)
epfd:?發(fā)生監(jiān)視范圍的epoll
events:?保存發(fā)生事件的文件描述符集合的結(jié)構(gòu)體地址值
maxevents:?第二個參數(shù)中保存最大的事件數(shù)
timeout:等待時間
epoll回聲服務(wù)器端
#include?<stdio.h>
#include?<stdlib.h>
#include?<string.h>
#include?<unistd.h>
#include?<arpa/inet.h>
#include?<sys/socket.h>
#include?<sys/epoll.h>
#define?BUFF_SIZE?100
#define?EPOLL_SIZE?50
int?main(int?argc,?char?*argv[])
{
????int?ser_sock,?cln_sock;
????struct?sockaddr_in?ser_adr,?cln_adr;
????socketlen_t?adr_sz;
????int?str_len,?i;
????char?buf[BUFF_SIZE];
????struct?epoll_event?*ep_events;
????struct?epoll_event?event;
????int?epfd,?event_cnt;
????ser_sock?=?socket(PF_INET,?SOCK_STREAM,?0);
????memset(&ser_adr,?0,?sizeof(ser_adr));
????ser_adr.sin_family?=?AF_INET;
????ser_adr.sin_addr.s_addr?=?htonl(INADDR_ANY);
????ser_adr.sin_port?=?htons(atoi(argv[1]));
????if(bind(ser_sock,?(struct?sockaddr*)&ser_adr,?sizeof(ser_adr))?==?-1)
??????error();
????if(listen(ser_sock,?5)?==?-1)
??????error();
????//?創(chuàng)建epoll的例程空間
????epfd?=?epoll_create(EPOLL_SIZE);?//?返回值和套接字相同,最后也需要close掉
????ep_events?=?malloc(sizeof(struct?epoll_event)*EPOLL_SIZE);?//?申請一個epoll空間池
????event.events?=?EPOLLIN;?//?需要讀取數(shù)據(jù)情況
????event.data.fd?=?ser_sock;?//?socket的文件描述符
????epoll_ctl(epfd,?EPOLL_CTL_ADD,?ser_sock,?&event);?//?添加一個事件
????while(1)
????{
??????//?返回發(fā)生事件的文件描述符數(shù),?event_cnt個數(shù)
??????event_cnt?=?epoll_wait(epfd,?ep_events,?EPOLL_SIZE,?-1);?
??????if(event_cnt?==?-1)
????????break;
??????for(i=0;?i<event_cnt;?i++)
??????{
????????if(ep_events[i].data.fd?==?ser_sock)?//?新的客戶端連接走這里。
????????{
??????????//?將新連接的客戶端fd加入到epoll例程中
??????????adr_sz?=?sizeof(cln_adr);
??????????cln_sock?=?accept(ser_sock,?(struct?sockaddr*)&cln_adr,?&adr_sz);
??????????event.events?=?EPOLLIN;
??????????event.data.fd?=?cln_sock;
??????????epoll_ctl(epfd,?EPOLL_CTL_ADD,?cln_sock,?&event);
??????????printf("connected?client:?%d\n",?cln_sock);
????????}
????????else
????????{
??????????//?實現(xiàn)和已連接的客戶端通信
??????????str_len?=?read(ep_events[i].data.fd,?buf,?BUFF_SIZE);
??????????if(str_len?==?0)
??????????{
????????????//?處理完事件之后,將其從例程中刪除。
????????????epoll_ctl(epfd,?EPOLL_CTL_DEL,?ep_events[i].data.fd,?NULL);
????????????close(ep_events[i].data.fd);
????????????printf("close?client:%d\n",?ep_events[i].data.fd);
??????????}
??????????else
??????????{
????????????write(ep_events[i].data.fd,?buf,?str_len);
??????????}
????????}
??????}
????}
????close(ser_sock);
????close(epfd);
????return?0;
}