Unix C (十)

網絡編程:
  ip 地址 是網絡中計算機的地址,和mac地址(網卡出廠地址/物理地址)聯合 能夠讓網絡找到計算機。用端口(port)定位一個進程。因此網絡編程就是 ip+端口。
  Unix系統中,幾乎一切都可以看成文件。因此網絡信息的交互就用文件的交互方式。
  ip地址底層是整數,分爲ipv4(4位ip)和ipv6(6位)。
  對ip的描述方式一般使用點分十進制。4個或者6個 0-255的數字,並用 . 分開。底層ipv4其實就是一個32位二進制。

 在網絡中,字節順序固定,但本機中,可能從低到高,也可能從高到低。


 端口:16位二進制(0-65535)
  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;
}

     網絡通信地址(ip和端口):
    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;
}


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