linux---tcp通信流程以及代碼實現

TCP通信特性:(在網絡版塊詳細講解)
面向連接
可靠
面向字節流

TCP通信過程
在這裏插入圖片描述

c++封裝TCP通信

  1 #include <iostream>
  2 #include <arpa/inet.h>
  3 #include <unistd.h>
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <string>
  8 #include <errno.h>
  9 #include <netinet/in.h>
 10 #include <sys/socket.h>
 11 #define CHECK(T) if((T) == false) {return -1;}
 12 class TcpSocket{
 13     public:
 14         bool Close(){
 15             int ret = close(_sock);
 16             if(ret < 0){
 17                 perror("close error\n");
 18                 return false;
 19             }
 20             _sock = -1;
 21             return true;
 22         }
 23         TcpSocket():_sock(-1){
 24         };
 25         ~TcpSocket(){
 26         };
 27         bool Socket(){
 28             int ret = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 29             if(ret < 0){
 30                 perror("socket error\n");
 31                 return false;
 32             }
 33             _sock = ret;
 34             return true;
 35         }
 36         bool Bind(std::string& ip,uint16_t port){
 37             struct sockaddr_in  ser_addr;
 38             ser_addr.sin_family = AF_INET;
 39             ser_addr.sin_port = htons(port);
 40             ser_addr.sin_addr.s_addr = inet_addr(ip.c_str());
 41             socklen_t len = sizeof(ser_addr);
 42             int ret = bind(_sock,(struct sockaddr*)&ser_addr,len);
 43             if(ret < 0){
 44                 perror("bind error\n");
 45                 return false;
 46             }
 47             return true;
 48         }
 49         bool Listen(int backlog = 10){
 50             int ret = listen(_sock,backlog);
 51             if(ret < 0){
 52                 perror("listen error\n");
 53                 return false;
 54             }
 55             return true;
 56         }
 57         bool Connect(std::string& ip,uint16_t port){
 58             //給定服務器端的地址
 59             struct sockaddr_in addr;
 60             addr.sin_family = AF_INET;
 61             addr.sin_port = htons(port);
 62             addr.sin_addr.s_addr = inet_addr(ip.c_str());
 63             socklen_t len = sizeof(addr);
 64             int ret = connect(_sock,(struct sockaddr*)&addr,len);
 65             if(ret < 0){
 66                 perror("connect error\n");
 67                 return false;
 68             }
 69             return true;
 70         }
 71         bool Accept(TcpSocket& csock,struct sockaddr_in *cli = NULL){
 72             struct sockaddr_in _addr;
 73             socklen_t len = sizeof(_addr);
 74             int newfd = accept(_sock,(struct sockaddr*)&_addr,&len);
 75             if(newfd < 0){
 76                 perror("accept error\n");
 77                 return false;
 78             }
 79             //需要將獲取的客戶端的信息拷貝出去
 80             memcpy(cli,&_addr,len);
 81             csock.setSock(newfd);
 82             return true;
 83 
 84         }
 85         void setSock(int sock){
 86             _sock = sock;
 87         }
 88         bool Recv(std::string& str){
 89             char temp[1024] = {0};
 90             //設置成0默認是阻塞的
 91             int ret = recv(_sock,temp,1024,0);
 92             //返回-1出錯,返回0客戶端關閉,其餘返回接受到的數據大小
 93             if(ret < 0){
 94                 perror("recv error\n");
 95                 return false;
 96             }
 97             if(ret == 0){
 98                 std::cout << "客戶端已經斷開了連接" << std::endl;
 99                 return false;
100             }
101             str.assign(temp,ret);
102             return true;
103         }
104         bool Send(std::string& str){
105             int ret = send(_sock,str.c_str(),str.size(),0);
106             if(ret < 0){
107                 perror("send error\n");
108                 return false;
109             }
110             return true;
111         }
112     private:
113         int  _sock;
114 };

**重點:**我們tcp通信時需要使用多線程或者多進程來進行多個客戶端的連接請求,不然只能連接一個請求。

多進程服務端版本

  1 #include "tcpsocket.hpp"
  2 #include <signal.h>
  3 #include <sys/wait.h>
  4 
  5 void sigbc(int num){
  6     while(waitpid(-1,NULL,WNOHANG)>0);
  7 }
  8 
  9 int main(int argc,char* argv[]){
 10     if(argc != 3){
 11         perror("tcp_ser ip port\n");
 12         return -1;
 13     }
 14     std::string ip = argv[1];
 15     uint16_t port = atoi(argv[2]);
 16     signal(SIGCHLD,sigbc);
 17     TcpSocket sock;
 18     CHECK(sock.Socket());
 19     CHECK(sock.Bind(ip,port));
 20     CHECK(sock.Listen(10));
 21     while(1){
 22         //創建一個通信
 23         TcpSocket com;
 24         struct sockaddr_in cli;
 25         if(sock.Accept(com,&cli) == false){
 26             continue;
 27         }
 28         std::cout<<"新的連接Ip:"<<inet_ntoa(cli.sin_addr);
 29         std::cout<<"端口port:"<<ntohs(cli.sin_port)<<std::endl;
 30         int pid = fork();
 31         if(pid == 0){
 32             while(1){
 33                 std::string buf;
 34                 com.Recv(buf);
 35                 std::cout<<"client said:"<<buf<<std::endl;
 36                 buf.clear();
 37                 std::cout<<"server say:";
 38                 std::cin>>buf;
 39                 fflush(stdout);
 40                 com.Send(buf);
 41             }
 42         }
 43         com.Close();
 44     }
 45     sock.Close();
 46     return 0;
 47 }

多線程服務端版本

 1 #include "tcpsocket.hpp"
  2 #include <pthread.h>
  3 void* start_thr(void* arg){
  4     TcpSocket* sock = (TcpSocket*)arg;
  5     while(1){
  6         std::string str;
  7         sock->Recv(str);
  8         std::cout<<"client said:"<<str<<std::endl;
  9         str.clear();
 10         
 11         std::cout<<"server say:";
 12         fflush(stdout);
 13         std::cin>>str;
 14         sock->Send(str);
 15     }
 16     delete sock;
 17     sock->Close();
 18     return NULL;
 19 }
 20 int main(int argc,char* argv[]){
 21     if(argc != 3){
 22         perror("./pro ip port\n");
 23         return -1;
 24     }
 25     std::string ip = argv[1];
 26     uint16_t port = atoi(argv[2]);
 27 
 28     TcpSocket sock;
 29     CHECK(sock.Socket());
 30     CHECK(sock.Bind(ip,port));
 31     CHECK(sock.Listen(10));
 32     while(1){
 33         struct sockaddr_in cli;
 34         //這裏在堆上開闢空間,是線程共用
 35         TcpSocket* csock = new TcpSocket();
 36         if(sock.Accept(*csock,&cli) == false){
 37             continue;
 38         }
 39         std::cout<<"新的客戶端IP:"<<inet_ntoa(cli.sin_addr);
 40         std::cout<<"  端口:"<<ntohs(cli.sin_port)<<std::endl;
 41         pthread_t pid;
 42         pthread_create(&pid,NULL,start_thr,(void*)csock);
 43         pthread_detach(pid);
 44     }
 45     sock.Close();
 46     return 0;
 47 }

客戶端代碼實現

1 #include "tcpsocket.hpp"
  2 
  3 int main(int argc,char* argv[]){
  4     if(argc != 3){
  5         perror("./tcp_cli ip port\n");
  6         return -1;
  7     }
  8     std::string ip = argv[1];
  9     uint16_t port = atoi(argv[2]);
 10 
 11     TcpSocket sock;
 12     CHECK(sock.Socket());
 13     CHECK(sock.Connect(ip,port));
 14     while(1){
 15         std::string buf;
 16         std::cout<<"client say:";
 17         fflush(stdout);
 18         std::cin>>buf;
 19         sock.Send(buf);
 20 
 21         buf.clear();
 22         sock.Recv(buf);
 23         std::cout<<"server said:"<<buf<<std::endl;
 24     }
 25     sock.Close();
 26     return 0;
 27 } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章