iT邦幫忙

2021 iThome 鐵人賽

DAY 2
0
Software Development

applicatio框架搭建,包含常用toolkit:ui,network,multithread,db,config,log,data structure系列 第 2

網絡框架

簡介:網絡分爲5層,軟體開發需要用到的主要是上面兩層:網絡層,和應用層;路由器系統開發的估計需要用到傳輸層;所以如果研究網絡的話,我們需要深入瞭解的是網絡層和應用層;
關鍵字:網絡層,應用層;
關鍵字解釋:網絡傳輸,可以想象成是快遞包裹一樣,快遞有運輸車(車裏有快遞箱,箱子裏面有快遞包裹,包裹表面有寄件單資訊,收件人根據這個來收到),這一層層的裹起來,就是不同層的職責所在,并非是爲了難爲我們這些學習網絡的人;那麽,接下來,解釋一下關鍵字:網絡層是tcp/ip包裹的那一層,我們把原來的要發的data看作是物品的話,那麽網絡層就是寄件單一樣的東西,可以標志誰寄的,誰來收;而應用層是什麽呢?應用層是爲了簡化或者說模式化網絡層而出現的,更加方便包裹的這一層;
實戰舉例:我做的項目都是服務業自動化系統,這裏會涉及到的最多的是socket,而通常socket編程就是針對網絡層的,也就是通訊協議雙方,制定protocol,這個protocol的内容是一些十六進制的編碼,比如:https://ithelp.ithome.com.tw/upload/images/20210910/20139212zhttwaZqBh.png
也就是在data的前面加上一些協議頭,不同的頭表示data所屬的内容是什麽,這樣拆包的那方就知道用什麽方式拆包了,比如我發了一個int過去,協議中説好了,這個是一個4byte的int,那麽對方就可以用int_32來把這個data轉成4byte的int了,就拿到數字了;深挖一下:網絡中的包都是二進制的,所以我們用十六進制來制定協議,因爲拆包的時候1個byte就是1個char;下面逐步講解如何發送socket:
關鍵字:socket,server,client,listen,connect;
建server:首先需要建立一個監聽用的server,server需要的是兩個ip+port,ip就是我們的網絡地址(分爲公網和局域網,往往我們看到的ip是局域網的,由路由器自動分配的,公網ip可以去google直接查,内部通訊可以用局域網ip,但是對外通訊需要用公網ip,一般與其他廠商通訊,都需要公網ip),port是監聽端口,這個是因爲我們電腦中有很多程序,到底哪個程序來處理從外部來的data呢?這個就出現了每個程序可以監聽一個或多個端口(port),端口從1到幾萬都可以,但是低位的(幾十幾百的)往往都是公約端口,這些已經被占了,請不要使用,也就是說,如果我自己寫一個程序來監聽某個端口的話,最好找個端口值設高一些,比如幾千幾萬等等;設定好之後,就監聽這個ip+port就好了;
建一個或者多個client:client端,直接connect到 server端;
收發訊息:read 和 write;一般實際處理的時候,是需要多綫程處理的,因爲主程序還是在跑,儅有資訊來的時候,就拆包,儅需要發資訊的時候,就封包;
下面看一下代碼(c++的,linux系統,vscode,cmake跑的):
server:
打開監聽端口:

void CallCarServer::Init()
{
  int listenfd;//萬物皆文件,請不要懷疑,所謂的監聽端口,就是一個文件標識符(最原始的就是個int喲)

  if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  {
      ERR_EXIT("ERROR");
  }
  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(CAR_DRIVING_SERVER_NETWORK_TARGET_PORT);
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  int on = 1;
  if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
  {
      ERR_EXIT("SETSOCKOPT");
  }
  if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
  {
      ERR_EXIT("ERROR");
  }
  if (listen(listenfd, SOMAXCONN) < 0)
  {
      ERR_EXIT("LISTEN");
  }
  struct sockaddr_in peeraddr;
  socklen_t peerlen = sizeof(peeraddr);
  int conn;
  char sendbuf[256];
  while (true)
  {
      conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen);
      if (conn < 0)
      {
          ERR_EXIT("accept");
      }

      printf("ip = %s, port = %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
      conn_ = conn;

      std::thread t_receive(&CallCarServer::thread_accept, this);
      t_receive.detach();
  }
  close(listenfd);
}

多執行緒處理數據:

void CallCarServer::thread_accept()
{
    char recvbuf[BUFF_SIZE];
    while (true)
    {
        sleep(1);

        memset(recvbuf, 0, sizeof(recvbuf));

        int num = read(conn_, recvbuf, sizeof(recvbuf));

        if (num <= 0)
        {
            continue;
        }
        printf("message length is %d\n", num);

        //take the length of message
        //int len = Lenth_Message(recvbuf);
        //len = num-4;

        char *message = new char(num - 4);
        for (int i = 0; i < len; i++)
        {
            message[i] = recvbuf[i + 4];
        }

        // DealMessage(message);

        ReceiveBuf *recvbuf = reinterpret_cast<ReceiveBuf *>(message);
        std::cout<< recvbuf->message.iCarID<<std::endl;

        delete (message);
        //SendCarGo(conn);
    }
    close(conn_);
}

client端:

int sock;
    if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
    {
        ERR_EXIT("ERROR");
    }
    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(2978);
    servaddr.sin_addr.s_addr = inet_addr("192.168.200.243");
    
    if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
    {
        ERR_EXIT("connect");
    }

    char sendbuf[1024] = {0};
    char recvbuf[1024] = {0};

    while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
    {
        write(sock,sendbuf,strlen(sendbuf));
        memset(sendbuf,0,sizeof(sendbuf));
    }
    close(sock);

上面是基本知識,實戰中,花更多時間的是制定protocol,下篇再講解如何制定protocol;
以及可能大部分人使用的是應用層的network program:比如mqtt,http post等;


上一篇
ui 框架説明
下一篇
網絡框架:如何制定protocol
系列文
applicatio框架搭建,包含常用toolkit:ui,network,multithread,db,config,log,data structure4
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言