TCP/IP网络编程复习(上)
生活随笔
收集整理的這篇文章主要介紹了
TCP/IP网络编程复习(上)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第一章 理解網絡編程和套接字
#include<sys/socket.h> int socket(int domain, int type , int protocol); //socket返回文件描述符或-1 int bind(int sockfd , struct sockaddr *myaddr, socklen_t addrlen); //bind返回0或-1 int listen(int sockfd,int backlog); //listen返回0或-1 int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen); //返回文件描述符或-1 ##以上為服務器端 編譯指令:gcc hello_server.c -o hserver- Linux下socket被認為是文件的一種,windows區分socket和文件
- 0,1,2這三個文件描述符(方便描述文件)為STDIN STDOUT STDERR
- windows在這方面的函數與linux差不多,不過套接字有專屬類型SOCKET
第二章 套接字類型與協議設置
- int socket(int domain, int type , int protocol);
第一個參數為協議族有PF_INET PF_INET6等;第二個參數為套接字類型:有SOCK_STREAM(傳送帶傳糖果,面向連接,無數據邊界,可靠有序)和SOCK_DGRAM)(摩托車,不可靠,無序,以數據的高速傳輸為目的的套接字);最后一個參數默認情況是0
第三章 地址族與數據序列
- IPV4傳數據是先向網絡號傳輸數據(傳到路由器,交換機),再由這個網絡具體傳給相應主機號的主機
- A類地址首字節范圍:0-127 B:128-191 C:192-223
- NIC(網絡接口卡)為數據傳輸設備,os會將傳遞到內部的數據分配給套接字,這時需要用到端口號,NIC接收的數據內有端口號,os參考此端口號把數據傳給對應套接字;端口號范圍0-65535,但0-1023為知名端口
- 主機字節序一般為小端序,網絡字節序為大端序
- 數據在傳輸之前都需要經過轉換嗎:這個過程是自動的,除了向sockaddr_in結構體變量填充數據外,其他情況無需考慮字節序問題
- p52有兩個不是特別清楚的點,到時候可以回頭看看
第四章 基于TCP的服務器端/客戶端(1)
- listen中的sock成為服務器端套接字,是接收連接或請求的保安
- accept會內部產生一個用于數據I/O的套接字,調用accept時,若等待隊列為空,則accept函數不會返回,直到隊列中出現新的客戶端連接
agrv agrc參數的描述
###echo服務端 #include <stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h>#define BUF_SIZE 1024 void error_handling(char *message);int main(int argc,char *agrv[]) {int serv_sock,clnt_sock;char message[BUF_SIZE];int str_len,i;struct sockaddr_in serv_adr,clnt_adr;socklen_t clnt_adr_sz;if(argc!=2){printf("Usage : %s <PORT>\n", agrv[0]);exit(1);}serv_sock=socket(PF_INET,SOCK_STREAM,0);if(serv_sock==-1)error_handling("socket() error");memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(agrv[1]));if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr))==-1)error_handling("bind() error");if(listen(serv_sock,5)==-1)error_handling("listen() error");clnt_adr_sz=sizeof(clnt_adr);for(int i=0; i<5; i++){clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz);if(clnt_sock==-1)error_handling("accept() error");elseprintf("Connected client %d \n",i+1);while((str_len=read(clnt_sock,message,BUF_SIZE))!=0)write(clnt_sock,message,str_len);close(clnt_sock);}close(serv_sock);return 0; } void error_handling(char *message) {fputs(message,stderr);fputc('\n',stderr);exit(1); }
gcc編譯顯示警告
第五章 基于TCP的服務器端/客戶端(2)
##完美的回聲客戶端 #include <stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h>#define BUF_SIZE 1024 void error_handling(char *message);int main(int argc,char *agrv[]) {int sock;char message[BUF_SIZE];int str_len,recv_len,recv_cnt;struct sockaddr_in serv_adr;if(argc!=3){printf("Usage : %s <IP> <PORT>\n", agrv[0]);exit(1);}sock=socket(PF_INET,SOCK_STREAM,0);if(sock==-1)error_handling("socket() error");memset(&serv_adr,0,sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(agrv[1]);serv_adr.sin_port=htons(atoi(agrv[2]));if(connect(sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr))==-1)error_handling("connect() error");elseputs("Connected............");while(1){fputs("Input message(Q to quit): ",stdout);fgets(message,BUF_SIZE,stdin);if(!strcmp(message,"q\n")||!strcmp(message,"Q\n"))break;str_len=write(sock,message,strlen(message));recv_len=0;while(recv_len<str_len){recv_cnt=read(sock,message,BUF_SIZE-1);if(recv_cnt==-1)error_handling("read() error");recv_len+=recv_cnt;}message[str_len]=0;printf("Message from server: %s",message);}close(sock);return 0; } void error_handling(char *message) {fputs(message,stderr);fputc('\n',stderr);exit(1); }- I/O緩沖在每個TCP套接字中單獨存在;I/O緩沖在創建套接字時自動生成;即使關閉套接字也會繼續傳遞輸入緩沖中遺留的數據;關閉套接字將丟失輸入緩沖中的數據
- TCP中因為TCP會控制數據流(Sliding Window協議),不會發生超過輸入緩沖大小的傳輸數據
- write函數并不會在完成向對方主機的數據傳輸時返回,而是在數據移到輸出緩沖時,但TCP會保證對輸出緩沖數據的傳輸
第六章 基于UDP的服務器端/客戶端
- UDP提供不可靠的數據傳輸服務,在重視性能而非可靠性的情況下,UDP是一種很好的選擇
- UDP最重要的作用就是根據端口號將傳到主機的數據包交付給最終的UDP套接字,TCP中套接字是一對一的關系,而UDP每方只需要一個,收發信件的郵箱可以比喻成UDP套接字
- UDP存在數據邊界,一個數據包即可成為一個完整數據,UDP通信過程中使用I/O函數調用次數應保持一致
- 通過sendto傳遞數據分為3個階段:1.向UDP套接字注冊目標IP和端口號;2.傳輸數據;3.刪除UDP套接字中注冊的目標地址信息。這種未注冊目標地址信息的套接字稱為未連接套接字,與此相對的還有已連接套接字(可以避免了1,3階段的過程)
- 創建已連接UDP套接字:connect(sock,(struct sockaddr*)&adr,sizeof(adr))就是調用了connect函數,向UDP套接字注冊目標IP和端口信息,注冊后可以使用write,read和sendto,recvfrom
第七章 優雅地斷開套接字連接
- TCP的半關閉:兩臺主機通過套接字建立連接后進入可交換數據的狀態,又稱“流形成的狀態”,此時有I/O流1和I/O流2,close函數會同時斷開這兩個流,不夠優雅(發送完數據可能就調用close函數,而此時可能還有對面發過來讓你必須接收的數據,這種數據就被損毀了)
- 服務器端向客戶端傳送文件時,客戶端不知道要接收到什么時候,也不能一直調用read函數(會阻塞),所以約定一個EOF標志文件傳輸結束
第八章 域名及網絡地址
- DNS將域名轉換為IP
- IP地址比域名發生變更的概率更高,用域名比較好一些
- 對于上面的h_addr_list,他指向字符串指針數組,但字符串指針數組中的元素實際指向的是(實際保存的是)in_addr結構體變量地址值;這里面用char **是因為它為多門協議所用,指針類型不確定,而當時又沒有void *,就用char *表示無法確定的指針類型
第九章 套接字的多種可選項
int getsockopt(int sock,int level, int optname, void *optval,socklen_t *optlen); ##optval為保存查看結果的緩沖地址值;optlen保存通過第四個參數返回的可選項信息的字節數 int setsockopt(int sock,int level,int optname,const void* optval,socklen_t optlen); ##level為協議層;optval為可選項名- 一些常用的選項:SO_SNDBUF&SO_RCVBUF;SO_REUSEADDR;TCP_NODELAY
- Nagle算法:p150,TCP套接字默認使用Nagle算法交換數據,網絡流量未受到太大影響時,不使用Nagle算法要比使用它時傳輸速度更快(如傳輸大文件數據);未準確判斷數據特性時不應禁用Nagle算法
總結
以上是生活随笔為你收集整理的TCP/IP网络编程复习(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android卡顿检测及优化
- 下一篇: GP232RL与FT232RL操作区别