天天看點

C++實作區域網路雙向通信(socket)

如果想要實作兩不同區域網路之間的主機程序通信,即實作區域網路内兩個電腦之間的資料傳輸,那麼就不能通過管道或者命名管道的方式來實作,這裡的區域網路通信是通過一種叫做socket套接字的方式來實作。 首先想要與同一區域網路内部的另一個電腦進行資料傳輸,需要知道它的IP位址,因為IP是連接配接網絡之後配置設定給個人主機的唯一辨別,是以先找到想要建立連接配接的主機的位址,然後我們雙方共同約定一個類似于管道的唯一出入口(也就是端口号port),這裡的端口号一般分為公認端口号和注冊端口号,約定好端口号傳輸的時候雙方都需要遵守共同的網絡協定(TCP(SOCK_STREAM),UDP(SOCK_DRAM),ICMP(SOCK_RAW))。 公認端口号:知名端口即衆所周知的端口号,範圍從0到1023,這些端口号一般固定配置設定給一些服務。比如21端口配置設定給FTP(檔案傳輸協定)服務,25端口配置設定給SMTP(簡單郵件傳輸協定)服務,80端口配置設定給HTTP服務,135端口配置設定給RPC(遠端過程調用)服務等等 注冊端口号:端口号從1025到49151。它們松散地綁定于一些服務。也是說有許多服務綁定于這些端口,這些端口同樣用于許多其他目的。這些端口多數沒有明确的定義服務對象,不同程式可根據實際需要自己定義,如後面要介紹的遠端控制軟體和木馬程式中都會有這些端口的定義的。記住這些常見的程式端口在木馬程式的防護和清除上是非常有必要的。常見木馬所使用的端口在後面将有詳細的清單 一般選擇端口号都是選擇注冊端口号,沒有明确的定義 服務對象,不同的通信可以根據自己的需要進行定義。

實作過程如下: server: [cpp]  view plain  copy

  1. #include <arpa/inet.h>//包含socket函數使用的各種協定族,send(),recv()  
  2. #include <unistd.h>//調用linux系統函數的頭檔案(read(),write(),send(),select())  
  3. #include <iostream>  
  4. #include <thread>  
  5. #include <list>  
  6. #define PORT 7000  
  7. #define IP "127.0.0.1"  
  8. int s;  
  9. struct sockaddr_in servaddr;  
  10. socklen_t len;  
  11. std::list<int> li;  
  12. void getConn() {  
  13.     while(1){  
  14.         int conn = accept(s, (struct sockaddr*)&servaddr, &len);//第二個參數儲存用戶端套接字對應的IP位址和port 端口資訊  
  15.         li.push_back(conn);  
  16.         printf("%d\n", conn);  
  17.     }  
  18. }  
  19. void getData() {  
  20.     struct timeval tv;  
  21.     tv.tv_sec = 2;  
  22.     tv.tv_usec = 0;  
  23.     while(1) {  
  24.         std::list<int>::iterator it;  
  25.         for(it=li.begin(); it!=li.end(); ++it){  
  26.             fd_set rfds;  
  27.             FD_ZERO(&rfds);  
  28.             int maxfd = 0;  
  29.             int retval = 0;  
  30.             FD_SET(*it, &rfds);  
  31.             if(maxfd < *it){  
  32.                 maxfd = *it;  
  33.             }  
  34.             retval = select(maxfd+1, &rfds, NULL, NULL, &tv);//實作非阻塞式的通信,即需要等待時間的發生,一旦執行一定傳回,傳回的結果不同以表示函數執行的結果  
  35.             if(retval == -1){  
  36.                 printf("select error\n");  
  37.             }else if(retval == 0) {  
  38.             }else{  
  39.                 char buf[1024];  
  40.                 memset(buf, 0 ,sizeof(buf));  
  41.                 long len = recv(*it, buf, sizeof(buf), 0);  
  42.                 printf("%s", buf);  
  43.             }  
  44.         }  
  45.         sleep(1);  
  46.     }  
  47. }  
  48. void sendMess() {  
  49.     while(1) {  
  50.         char buf[1024];  
  51.         fgets(buf, sizeof(buf), stdin);//從檔案流讀取一行,送到緩沖區,使用時注意以下幾點  
  52.         std::list<int>::iterator it;  
  53.         for(it=li.begin(); it!=li.end(); ++it){  
  54.             send(*it, buf, sizeof(buf), 0);  
  55.         }  
  56.     }  
  57. }  
  58. int main() {  
  59.     s = socket(AF_INET, SOCK_STREAM, 0);  
  60.     memset(&servaddr, 0, sizeof(servaddr));  
  61.     servaddr.sin_family = AF_INET;  
  62.     servaddr.sin_port = htons(PORT);  
  63.     servaddr.sin_addr.s_addr = inet_addr(IP);  
  64.     if(bind(s, (struct sockaddr* ) &servaddr, sizeof(servaddr))==-1) {  
  65.         perror("bind");  
  66.         exit(1);  
  67.     }  
  68.     if(listen(s, 20) == -1) {  
  69.         perror("listen");  
  70.         exit(1);  
  71.     }  
  72.     len = sizeof(servaddr);  
  73.     std::thread t(getConn);  
  74.     t.detach();  
  75.     std::thread t1(sendMess);  
  76.     t1.detach();  
  77.     std::thread t2(getData);  
  78.     t2.detach();  
  79.     while(1){  
  80.     }  
  81.     return 0;  
  82. }  

client: [cpp]  view plain  copy

  1. #include <arpa/inet.h>  
  2. #include <unistd.h>  
  3. #include <iostream>  
  4. #define MYPORT  7000  
  5. #define BUFFER_SIZE 1024  
  6. int main(int argc,char *argv[])  
  7. {  
  8.     int sock_cli;  
  9.     fd_set rfds;  
  10.     struct timeval tv;//設定時間  
  11.     int retval, maxfd;  
  12.     ///定義sockfd  
  13.     sock_cli = socket(AF_INET,SOCK_STREAM, 0);  
  14.     ///定義sockaddr_in  
  15.     struct sockaddr_in servaddr;  
  16.     memset(&servaddr, 0, sizeof(servaddr));  
  17.     servaddr.sin_family = AF_INET;  
  18.     char s[1024];  
  19.     int a;  
  20.     std::cout << "輸入想要建立連接配接的端口号以及IP位址:" << std::endl;  
  21.     scanf("%d",&a);  
  22.     getchar();  
  23.     scanf("%s",s);  
  24.     servaddr.sin_port = htons(a);  ///伺服器端口,利用htons将主機位元組順序轉換為網路位元組數序進而進行資料包的傳送  
  25.     servaddr.sin_addr.s_addr = inet_addr(s);  ///伺服器ip  
  26.     //連接配接伺服器,成功傳回0,錯誤傳回-1  
  27.     if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)  
  28.     {  
  29.         perror("connect");  
  30.         exit(1);  
  31.     }  
  32.     while(1){  
  33.         FD_ZERO(&rfds);  
  34.         FD_SET(0, &rfds);  
  35.         maxfd = 0;  
  36.         FD_SET(sock_cli, &rfds);  
  37.         if(maxfd < sock_cli)  
  38.             maxfd = sock_cli;  
  39.         tv.tv_sec = 5;  
  40.         tv.tv_usec = 0;  
  41.         retval = select(maxfd+1, &rfds, NULL, NULL, &tv);//int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout);  監視我們需要的檔案的檔案描述符的變化情況——讀寫或是異常  
  42.         if(retval == -1){  
  43.             printf("select出錯,用戶端程式退出\n");  
  44.             break;  
  45.         }else if(retval == 0){//逾時  
  46.             printf("用戶端沒有任何輸入資訊,并且伺服器也沒有資訊到來,waiting...\n");  
  47.             continue;  
  48.         }else{//檔案可進行讀寫或者出錯  
  49.             if(FD_ISSET(sock_cli,&rfds)){  
  50.                 char recvbuf[BUFFER_SIZE];  
  51.                 long len;  
  52.                 len = recv(sock_cli, recvbuf, sizeof(recvbuf),0);  
  53.                 printf("%s", recvbuf);  
  54.                 memset(recvbuf, 0, sizeof(recvbuf));  
  55.             }  
  56.             if(FD_ISSET(0, &rfds)){  
  57.                 char sendbuf[1024];  
  58. //                scanf("%s",sendbuf);  
  59.                 fgets(sendbuf, sizeof(sendbuf), stdin);  
  60.                 send(sock_cli, sendbuf, strlen(sendbuf),0); //發送  
  61.                 memset(sendbuf, 0, sizeof(sendbuf));  
  62.             }  
  63.         }  
  64.     }  
  65.     close(sock_cli);  
  66.     return 0;  
  67. }