【2016/1/27】 網絡編程 - TCP協議

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hsgwpj/article/details/50597368

網絡編程

2016-1-27:
網絡協議: 用結構體(報頭)來描述數據包的屬性與內容來處理
- 有源IP和目標IP
- 網絡協議層層封裝 HTTP <- TCP <- IP <- 機器屬性
- IP 同時被 TCP 和 UDP 封裝 , IP本身是不可靠的
- TCP以應用層的技術,保障了協議的可靠程度

B/S方式
HTTP: 通用的客戶端協議 讓任何人可以輕易的使用瀏覽器來訪問服務端

C/S方式
TCP:
1. TCP在擁堵時會自動收縮自己的傳輸範圍(用數學公式推算的)
2.【滑動窗口】技術:不斷清除返回的隊列內容來縮減隊列
3. 基於流的連續傳輸:保障所有的包按順序到達
UDP: 不保障可靠和順序,但是效率高

    短鏈接:瞬間斷開
    長鏈接:一直建立等待超時再斷開的鏈接

socket:
一個描述符 代表的是一片內存區域
含有接受緩存和發送緩存 通過內核將信息發到網卡上發送
— domian 使用AF_UNIX 可以使用本地模式 使用本地套結字通信
— 多進程的socket之間沒有意義,但是fork()是可以放在accept之前的,但是要用AF_UNIX來渡過去

單個主機內,每一個進程需要採用不同的端口號來使用與標識
客戶端的端口號可以人爲指定也可以系統分配
上下限:(0-65535)short類型
    netstat -antplue  #shell查看各種有關端口的信息
    tcpdump port <端口號> -i <網卡> -nn #查看端口的信息

DDOS攻擊: 不斷地連環ping目標網卡 然後使之緩存區立即溢出 無法接受數據
— 低級 有效 不可防範

TCP編程:
eg:
https://github.com/KhalilWang/IPC_samples/tree/master/Socket

客戶端:
           1.socket(AF_INET, SOCK_STREAM, 0);      //創建套結字
           2.connect(sockfd, *sa_addr, addrlen);   //連接端口
           3.send() / recv();                      //發送/接受數據
           4.close(fd);                            //退出

服務端:


           1.socket(AF_INET, SOCK_STREAM, 0);       //創建套結字
           2.bind(sockfd, *sa_addr, addrlen);       //綁定端口
           3.listen(sockfd, backlog);               //監聽端口4.accept(sockfd, *addr, *addrlen);      //等待接受請求5.fork() / pthread_create();            //創建進線程處理
           6.close(fd);                             //退出

listen中的backlog是可以允許的排隊人數
— 真正的人數是 backlog * 3 / 2 + 1
accept中的addr接收的是連接人的addr信息
accept返回的是一個sockfd!CS之間的通信由此開始!
通常在accept之後創建進線程來處理新的fd,
然後主進程繼續accept來接受請求
進程立即fork()(線程沒有獨立空間,不太適合存儲accept的返回值)
線程則需要將fd存儲於棧上,使用同步技術防止fd被覆蓋

對於描述符的使用:(適合tcp, 但是這兩個函數和協議無關)

           send(sockfd, *buf, len, flags);
           recv(sockfd, *buf, len, flags);

其實就是對於read() / write()的封裝

   struct sockaddr{
       sa_family_t sa_family  ;
       char        sa_data[14];
   }               //原版的sockaddr地址信息
   新版: sockaddr_in 將sa_family 轉換爲連續的幾個變量
          sa_family_t ->  sin_family + sin_port(short) + sin_addr(32位整形)
           宏定義的##意思是將後面的的變量轉爲字符補在後面

*一般採用sockaddr_in 強轉爲 sockaddr 使用
端口信息採用了網絡字節序:
htonl()/htons() host to network long/short 將端口號進行網絡字節序轉化
sin_addr -> 這個結構體變量是宏定義: 接受本網段還是全網的連接
IP地址是字符串的地址 是一個16字節的char數組 存儲的IPV4的字符串
使用inet_aton()來將字符串進行網絡字節序轉換 inet_ntoa()反之

*tip: 網絡傳輸時一定要注意內存對齊!

粘包問題:收包的時候沒有區分好數據邊界
解決方法:發每一個包之前自己做一個報頭,分兩次收報頭,再收數據:
struct head{
int ctl;
int size;
}
根據size 的值收第二個包 防止粘包現象

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