ip 地址 是網絡中計算機的地址,和mac地址(網卡出廠地址/物理地址)聯合 能夠讓網絡找到計算機。用端口(port)定位一個進程。因此網絡編程就是 ip+端口。
Unix系統中,幾乎一切都可以看成文件。因此網絡信息的交互就用文件的交互方式。
ip地址底層是整數,分爲ipv4(4位ip)和ipv6(6位)。
對ip的描述方式一般使用點分十進制。4個或者6個 0-255的數字,並用 . 分開。底層ipv4其實就是一個32位二進制。
在網絡中,字節順序固定,但本機中,可能從低到高,也可能從高到低。
0-1023 儘量不用,系統會非連續的使用
1024-48XXX 使用,固有端口
48XXX-65535 不要使用,動態端口(不穩定)
編程:
1 socket套接字
socket 編程 分類:
一對一(點對點)
一對多(多個客戶端/一個服務器)
支持TCP/UDP傳輸
1.1 一對一本地通信
a 服務端
1) 創建一個socket
int socket(int domain,int type,int protocol)
domain: 域 ,選擇協議簇
PF_UNIX / PF_LOCAL / PF_FILE (PF換AF)
本地通信(進程間通信)
PF_INET/AF_INET 網絡通信(IPV4)
PF_INET6/AF_INET6 網絡通信(IPV6)
type : 通信協議的類型
SOCK_STREAM : 數據流(TCP)
SOCK_DGRAM :數據報(UDP)
protocol : 本來應該是選協議,但基本沒用,因爲協議由前2個參數決定
返回值是一個整數,socket描述符。socket描述符類似文件描述符,read讀,write寫。
2) 準備通信地址
參數通信地址(只是做參數,不會真正使用)
struct sockaddr{
int sa_family;//協議簇
char sa_data[];//地址
};
本地通信地址(文件):
struct sockaddr_un{ // sys/un.h
int sun_family;//協議簇
char sun_path[];//文件名
};
實例:
(1)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
int main(){
//創建通信描述符
int sockfd = socket(PF_UNIX,SOCK_DGRAM,0);
if(sockfd == -1)
perror("socket"),exit(-1);
//準備本地通新地址
struct sockaddr_un addr;
addr.sun_family = PF_UNIX;
strcpy(addr.sun_path,"a.sock");
//連接
int res = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res == -1)
perror("bind"),exit(-1);
printf("connect ok\n");
//寫內容
write(sockfd,"hello socket!",13);
printf("成功寫出\n");
//關閉描述符
close(sockfd);
return 0;
}
(2)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
int main(){
//創建通信描述符
int sockfd = socket(PF_UNIX,SOCK_DGRAM,0);
if(sockfd == -1)
perror("socket"),exit(-1);
//準備本地通信地址
struct sockaddr_un addr;
addr.sun_family = PF_UNIX;
strcpy(addr.sun_path,"a.sock");
//綁定
int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res == -1)
perror("bind"),exit(-1);
printf("bind ok\n");
//讀取內容
char buf[100] = {};
read(sockfd,buf,sizeof(buf));
printf("讀到了:%s\n",buf);
//關閉描述符
close(sockfd);
return 0;
}
struct sockaddr_in{ // netinet/in.h
int sin_family;//協議簇
short sin_port;//端口
struct in_addr sin_addr;//IP
};
網絡編程:
基於TCP的編程步驟:
Server端:
1 socket()
2 準備通信地址 struct sockaddr_in
3 綁定 bind()
4 listen()
5 accept(),返回一個用於交互的新的描述符
6 讀寫 read() write()
7 關閉close()
Client端:
1 socket()
2 準備通信地址 struct sockaddr_in
3 連接 connect()
4 讀寫 read() write()
5 關閉close()
基於UDP的編程步驟:
接收方:
1 socket()
2 準備通信地址,struct sockaddr_in
3 綁定 bind()
4 發送或接收 sendto() recvfrom() read()
5 關閉close()
發送方:
1 socket()
2 準備通信地址,struct sockaddr_in
3 發送或接收 sendto() recvfrom() read()
4 關閉close()
實例:
TCP通信
(1)服務端
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
//實現一對多
void fa(int signo){
printf("服務器即將退出\n");
//sleep(1);
exit(0);
}
int main(){
signal(SIGINT,fa);
//1 創建socket,accept不支持UDP
int sockfd = socket(PF_INET,SOCK_STREAM,0);
if(sockfd == -1) perror("socket"),exit(-1);
//2 準備通信地址
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr = inet_addr("172.40.0.65");
//addr.sin_addr.s_addr = INADDR_ANY;//本機ip
//防止地址已經使用
int reuseaddr = 1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&reuseaddr,sizeof(reuseaddr));
//3 綁定
int res = bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res == -1) perror("bind"),exit(-1);
printf("bind ok\n");
//4 監聽
if(listen(sockfd,100)==-1)perror("list"),exit(-1);
printf("listen........\n");
//5 等待客戶端的連接
while(1){
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
int fd = accept(sockfd,//阻塞,直到客戶端連接
(struct sockaddr*)&clientaddr,&len);
if(fd == -1) perror("accept"),exit(-1);
char *ip = inet_ntoa(clientaddr.sin_addr);//轉換
printf("客戶端%s連接了服務器\n",ip);
pid_t pid = fork();
if(pid == 0){
//6 用fd進行信息交互
while(1){
char buf[100] = { };
if(read(fd,buf,100)==-1)
perror("read"),exit(-1);
printf("讀到了:%s\n",buf);
write(fd,buf,strlen(buf));
}
close(fd);//練習:用信號在關閉服務器時打印信息
exit(0);
}
}
//close(sockfd);//7 關閉
}
(2)客戶端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int main(){
//創建網絡通信描述符
int sockfd = socket(PF_INET,SOCK_STREAM,0);
if(sockfd == -1)
perror("socket"),exit(-1);
//準備通信地址
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr = inet_addr("172.40.0.65");
//addr.sin_addr.s_addr = INADDR_ANY;//本機ip
//連接服務器
int res = connect(sockfd,(struct sockaddr*)&addr,
sizeof(addr));
if(res == -1) perror("connect"),exit(-1);
//通信
while(1){
char bufscan[100] = {};
printf("請輸入要說的話\n");
scanf("%s",bufscan);
res = write(sockfd,bufscan,strlen(bufscan));
if(res == -1)
perror("write"),exit(-1);
if(strcmp(bufscan,"bye")==0) break;
char buf[100] = {};
res = read(sockfd,buf,100);
if(res == -1)
perror("read"),exit(-1);
printf("讀到了:%s\n",buf);
}
close(sockfd);
}
UDP通信
(1)服務端
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(){
//創建網絡通信描述符
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd==-1)
perror("socket"),exit(-1);
//準備通信地址
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);
addr.sin_addr.s_addr = inet_addr("172.40.0.11");
//綁定
int res = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)
perror("bind"),exit(-1);
printf("bind ok\n");
//通信
char buf[100] = {};
struct sockaddr_in from;
socklen_t length = sizeof(from);
int len = recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&from,&length);
printf("讀到%d字節,內容:%s\n",len,buf);
sendto(fd,"welcome",7,0,(struct sockaddr*)&from,length);
//關閉描述符
close(fd);
return 0;
}
(2)客戶端
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(){
//創建通信描述符
int fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd==-1)
perror("socket"),exit(-1);
//準備通信地址
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2222);//服務端口
addr.sin_addr.s_addr =inet_addr("172.40.0.11");
//UDP無連接協議,理應不connect就能發送
//int res = write(fd,"hello",5);
//通信
int res = sendto(fd,"hello",5,0,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)
perror("write"),exit(-1);
char buf[100] = {};
read(fd,buf,sizeof(buf));
printf("buf=%s\n",buf);
close(fd);
return 0;
}