基本概念 套介面也就是網路中的ID。網路通信,歸根到底還是進程間通信(不同電腦上的進程間的通信)。在網路中,每一個節點(電腦或路由器)都有一個網路地址,也就是IP地址。 IP地址:在網路中唯一標識一臺主機 埠號:在主機中唯一標識一個進程 IP+port:在網路環境中唯一標識一個進程(socke ...
基本概念
套介面也就是網路中的ID。網路通信,歸根到底還是進程間通信(不同電腦上的進程間的通信)。在網路中,每一個節點(電腦或路由器)都有一個網路地址,也就是IP地址。
- IP地址:在網路中唯一標識一臺主機,32
- 埠號:在主機中唯一標識一個進程,16
- IP+port:在網路環境中唯一標識一個進程(socket)
socket也稱套接字,是linux文件的一種類型(偽文件:不占存儲空間的文件。linux 有7中文件, 1.普通文件 2.目錄(d)3.字元設備文件(c) 4.塊設備文件(b) 5.套介面文件(s)[如我們開啟MySQL服務後,在/var/lib/mysql/下生成的mysql.sock文件,關閉MySQL服務後,這個文件就消失了],6.管道(p):有兩端,讀端 r:流出 fd[0] 寫段w:流入 fd[1] 7.符號鏈接文件(l)[有點兒像WIN下的快捷方式] 其中占存儲的有三種:普通,目錄,軟鏈接)
socket成對出現,
一個文件描述符指向兩個緩衝區,一個讀一個寫。
預備知識 、
網路位元組序:
TCP/IP規定,網路數據流應採用大端位元組序,即低地址高位元組。(大端:低地址--高位 高地址--地位 小端:低--低 高--高,即埠號和IP地址都是以網路位元組序存儲的,網路位元組序使用的是大端模式。稱給某個系統所採用的位元組序為主機位元組序,它可能是小端模式也可能是大端模式。
為使網路編程具有可移植性,使同樣的C代碼在大端和小端電腦上編譯後能正常運行,可以調用一下庫函數做網路位元組序和主機位元組序的轉換。
#include<arpa/inet.h> uint32_t htoal(uint32_t hostlong); uint16_t htons(uint16_t hostshort); //返回的是網路位元組序 uint32_t ntoh1(uint32_t netlong); uint16_t ntohs(uint16_t netshort); //返回的主機位元組序 //h表示host,to,n代表network,s代表short,l表示long //埠16位 ,ip 32位
套介面的數據結構
在Linux中,每一種協議都有自己的網路地址數據結構,以sockaddr_開頭,如IPV4對應的是sockaddr_in.
//man 7 ip 查看 struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ /*套介面結構地址族,如IPV4為AF_INET*/ in_port_t sin_port; /* port in network byte order */ /*16位TCP或UDP埠號,網路位元組順序*/ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };
C/S編程
伺服器是指在網路上提供服務的應用程式,客戶機是指用戶為了得到某種服務所需要 運行的應用程式,即申請服務的程式。一個伺服器程式可以同時接收多個客戶機的請求。
server.c: socket() 建立套接字 bind() 綁定IP 埠號(struct sockaddr_in addr 初始化) listen() 指定最大同時發起連接數 accept() 阻塞等待客戶端發起連接 read() 小--大 write 給客戶端 close();
client.c:
socket();
bind();可以依賴“隱式綁定”,即寫不寫都行
connect();發起連接
write();
read();
close();
//server編程 #include<stdio.h> #include<unistd.h> #include<sys/socket.h> #include<stdlib.h> #include<arpa/inet.h> #include<ctype.h> #define SERV_PORT 6666 //埠號 int main(void) { int lfd,cfd;//定義套介面描述符 struct sockaddr_in serv_addr;//定義伺服器IPV4套介面地址數據結構serv_addr struct sockaddr_in clie_addr;//d定義客戶端client socklen_t clie_addr_len; char buf[BUFSIZ];//用BUFSIZ就不需要自己定義巨集了 int i,n; lfd=socket(AF_INET,SOCK_STREAM,0);//AF_INET:IPV4 AF_INET6:IPV6 serv_addr.sin_family=AF_INET;//設置addr的成員信息 serv_addr.sin_port=htons(SERV_PORT);//本地位元組序轉換為網路位元組序 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//IP地址設為本地IP INADDR_ANY本地任意IP bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//綁定埠 listen(lfd,128);//最多可以接受128個客戶端的請求,監聽ifd描述符 clie_addr_len=sizeof(clie_addr); cfd=accept(lfd,(struct sockaddr *)&clie_addr,&clie_addr_len);//bind accept connect 需要強轉 n= read(cfd,buf,sizeof(buf)); for(i=0;i<n;i++) { buf[i]=toupper(buf[i]);//下寫轉換為大寫 } write(lfd,buf,n); close(lfd); close(cfd); return 0; }