1. 程式人生 > >Linux下網路程式設計之自定義協議進行併發多客戶端與伺服器的通訊(多程序處理併發)不足佔用資源太多

Linux下網路程式設計之自定義協議進行併發多客戶端與伺服器的通訊(多程序處理併發)不足佔用資源太多

自定義協議訊息體
*********msg.h*************
#ifndef _MSG_H_
#define _MSG_H_
struct msg
{
  char head[10]; //頭部
  char msg_chck; //效驗碼
  char buff[512];//體部
}Msg;
extern int write_msg(int socktf, char* buff, size_t len);
extern int read_msg(int socktf, char* buff, size_t len);

*****msg.c***************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <memory.h>
#include <unistd.h>

#include "msg.h"

/*計算校驗碼
*/
static unsigned char msg_check(Msg* message)
{
  //將頭部和體部進行累加
  unsigned char s = 0;
  int i;
  for(i = 0; i < sizeof(message->head); ++i)
  {
    s += message->head[i];
  }
  for(i = 0; i < sizeof(message->buff); ++i)
  {
    s += message->buff[i];
  }
  return s;
}

/*
 * 傳送一個基於自定義協議的message
 * 傳送的資料存放在buff中*/
 
int write_msg(int socktf, char* buff, size_t len)
{
  Msg message;
  memset(&message, 0, sizeof(message));
  strcpy(message.head, "wc2017000");
  memcpy(message.buff, buff, len);
  message.checknum = msg_check(&message);
  //傳送一個message訊息
  if(write(socktf, &message, sizeof(message)) != sizeof(message))
  {
    return -1;
  }
}


/*
 * 讀取一個基於茲定於協議的message
 * 讀取的資料存在在buff中
 */
int read_msg(int socktf, char* buff, size_t len)
{
  Msg message;
  memset(&message, 0, sizeof(message));
  size_t size;
  if(( size = read(socktf,
          &message, sizeof(message))) < 0 )
  {
    return -1;
  }
  else if(size == 0) //資料讀光了
  {
    return 0;
  }
  //進行效驗碼驗證,判斷接受到message資料是否完整
  unsigned char s = msg_check(&message);
  if(s == (unsigned char)message.checknum
      && (!strcmp("wc2017000", message.head)))
  {
    memcpy(buff, message.buff, len);
    return sizeof(message);
  }
  return -1;
}
客戶端:
/*
 *  文 件 名:time_tcp_client.cpp
 *  作    者:wc
 *  郵    件:[email protected]
 *  版    權:Copyright (c) 完全自由
 *  意    圖:
 */


#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>


int main(int argc, char* argv[])
{
  if(argc < 3)
   printf("usage: %s ip port\n", argv[0]);
   exit(1);
  
   /*步驟1:建立socket套接字
    *
    * */
  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(sockfd < 0)
  {
    perror("socket error");
    exit(1);
  }

  /*往serveraddr中填入ip,port和地址族型別 ipv4
   *
   */
  struct sockaddr_in  serveraddr;
  memset(&serveraddr, 0, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_port = htons(atoi(argv[2]));
  /*p地址轉換為網路位元組序後填入tuserveraddr中*/
  inet_pton(AF_INET, argv[1],  &serveraddr.sin_addr.s_addr);
  
  /*步驟2:客戶端呼叫connect函式連線到伺服器端
   * */
  if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
  {
   // perror("connect error);
    exit(1);
  }

  /*步驟3:呼叫IO函式(read/write)和伺服器端進行雙向通訊
   * */
  char buff[512];
  size_t size;
  char* prompt = ">";
  while(1)
  {
    memset(buff, 0, sizeof(buff));
    write(STDOUT_FILENO, prompt, 1); //連線提示服
    size = read(STDIN_FILENO, buff, sizeof(buff));
    if(size < 0) continue;
    buff[size-1] = '\0';
    if(write_msg(sockfd, buff, sizeof(buff)) < 0 )
    {
      perror("write msg error");
      continue;
    }
    else if(read_msg(sockfd, buff, sizeof(buff)) < 0)
      {
       perror("read msg error");
      }
    else
    {
      printf("buff:%s", buff);
    }
    }
  }

  /*步驟4:
   *關閉套接字socket
   * */
   close(sockfd);



  return 0;
}
伺服器:
/*
 *  文 件 名:time_tcp_server.cpp
 *  作    者:wc
  *  版    權:Copyright (c) 完全自由
 *  意    圖:study
 */
#include <netdb.h>
#include <sys/socket.h> 
#include<netinet/in.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>
#include <arpa/inet.h>
#include "msg.h"
#include <errno.h>
#include <wait.h>
int sockfd; 

void sig_handler(int signo)//訊號捕捉函式
{
  if(signo == SIGINT)
  {
   printf("server close\n");
   //關閉socket
   close(sockfd);
  // exit(1);
  }
  if(signo == SIGCHLD)
  {
      perror("sigchld deaed");
      wait(0);
  }

}

/*輸出連線上來的客戶端相關資訊
 *
 */
void out_addr(struct sockaddr_in* clientaddr)
{
  /*將埠從網路位元組序轉換成主機位元組序
   *
   */
  int port = ntohs(clientaddr->sin_port);
  char ip[16];
  memset(ip, 0, sizeof(ip));
  /*將ip地址從網路位元組序轉換成點分十進位制*/
  inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));
  printf("client: %s(%d) connectd\n", ip, port);
}

void do_service(int fd)
{
  /*和客戶端進行讀寫操作(雙向通訊)
   */
  char buff[512];
  while(1)
  {
    memset(buff, 0, sizeof(buff));
    printf("start read and wirte...\n");
    size_t size;
    if((size = read_msg(fd, buff, sizeof(buff))) < 0)
    {
      perror("protocal erorr");
      break;
    }
    else if(size == 0)
    {
      break;
    }
    else
    {
      printf("%s\n", buff);
      if(write_msg(fd, buff, sizeof(buff)) < 0)
      {
            //if(error == EPIPE)
           // break;
      }
      perror("protacal error");
    }
  }
}

int main(int argc, char* argv[])
{
  if(argc < 2) //外部輸入引數監聽 埠
  {
  printf("usage  %s #port\n", argv[0]);
 // exit(1);
  }

  if(signal(SIGINT, sig_handler) == SIG_ERR) //訊號處理函式
  {
    perror("signal sigint error");
   // exit(1);
  }
   if(signal(SIGCHLD, sig_handler) == SIG_ERR) //訊號處理函式
  {
    perror("signal sigchld  error");
   // exit(1);
  }

  /*步驟1:建立socket(套接字)
  *socket建立在核心中,是一個結構體
  *AF_INET:  IPV4
  *SOCK_STREAM:  tcp協議
   */

  sockfd = socket(AF_INET, SOCK_STREAM, 0);


  /*步驟2:呼叫bind函式將socket和地址
   * (包括ip、port)進行繫結
   */

  struct sockaddr_in serveraddr;    //網路基本地址族
  memset(&serveraddr, 0, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET; //ipv4
  serveraddr.sin_port = htons(atoi(argv[1]));//整數轉換為網路位元組序 prot
  serveraddr.sin_addr.s_addr = INADDR_ANY;  //獲取所有網絡卡客戶端對應連線的請求
  if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
  {
    perror("bind error");
    exit(1);
  }


  /*步驟3:呼叫listen函式啟動監聽(指定port監聽)
   * 通知系統去接受來自客戶端的連線請求
   * 將接收到的客戶端連線請求放置到對應的佇列中
   * 第二個引數 客戶端佇列的長度
   */
  if(listen(sockfd, 10) < 0)
  {
    perror("lisen error");
    exit(1);
  }

  /*步驟4:呼叫accept函式從佇列(先進先出)中獲
   * 取一個客戶端的請求連線,並返回新的socket描述符
   * 注意:若沒有客戶端連線,呼叫此函式後阻塞,直到獲得一個客戶端的連線
   */
  struct sockaddr_in clientaddr;
  socklen_t clientlen = sizeof(clientaddr);
  while(1)
  {
    int fd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientlen);//sockfd此時是新的客戶但套接字的描述符
    if(fd < 0)
    {
      perror("acdept error");
      continue;
    }

    /*步驟5:呼叫IO函式(read/write)和連線額度客戶端進行雙向的通訊
     *啟動子程序去呼叫IO函式(read/write)和連線的客戶端進行雙向的通訊
     (併發處理來自客戶端的請求啟動多程序  當一個新的客戶端父程序new出一個子程序,父程序繼續等待下個客戶端的連線  )
     */
    pid_t pid = fork(); //建立一個程序
    if(pid < 0)
      continue;
    else if(pid == 0)//子程序
    {
      out_addr(&clientaddr);
      do_service(fd);
      close(fd);//記憶體在有計數器的 根據close的數量達到2的時候記憶體會釋放的
      break;
    }
    else//父程序
      close(fd);
    }

  return 0;
}



相關推薦

Linux網路程式設計定義協議進行併發客戶伺服器通訊(程序處理併發)不足佔用資源

自定義協議訊息體*********msg.h*************#ifndef _MSG_H_#define _MSG_H_struct msg{ char head[10]; //頭部 char msg_chck; //效驗碼 char buff[512];/

linux 網路程式設計結構體定義對應的標頭檔案

netinet/if_ether.h   ether_arp的資料結構 netinet/ether.h    以太禎的網路位元組和ascii位元組的轉換,包括ether_ntoa(),ether_aton這樣的函式定義 netinet/ip.h   這個標頭檔案和linux/ip.h似乎很相似,也有iphd

(筆記)Linux網路程式設計,採用TCP協議實現的C/S架構

TCP/UDP介紹 TCP(Transfer Control Protocol)傳輸控制協議是一種面向連線的協議, 當我們的網路程式使用這個協議的時候,可以保證我們的客戶端和服務端的通訊是可靠的,安全的,適合於傳輸大批量資料的情況. UDP(User Da

Boost.Asio C++ 網路程式設計七:基於TCP的同步客戶

      從本篇開始,我們會深入學習怎樣使用Boost.Asio建立更加複雜的客戶端和服務端應用。你可以執行並測試它們,而且在理解之後,你可以把它們做為框架來構造自己的應用。在接下來的例子中:1.客戶

linuxsocket程式設計 select實現非阻塞模式客戶伺服器通訊

select函式原型如下: int select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); select系統呼叫是用來讓我們的程式

Boost.Asio C++ 網路程式設計九:基於TCP的非同步客戶

       現在,是比較有趣(也比較難)的非同步實現! 當檢視流程圖時,你需要知道Boost.Asio代表由Boost.Asio執行的一個非同步呼叫。例如do_read(),Boost.Asio和on_read()代表了從do_read()到on_read()的邏輯流程,

五、通過Protobuf整合Netty實現對協議訊息客戶伺服器通訊實戰

目錄 一、Protocol Buffers 是什麼? 二、Protocol Buffers 檔案和訊息詳解 三、專案實戰,直接掌握的protobuf應用。 一、Protocol Buffers 是什麼?         1、官網翻譯

OPC協議解析-OPC客戶伺服器通訊解析

1      OPC伺服器 OPC伺服器, 是指按照OPC基金組織規定的OPC規範群開發的軟體驅動。OPC伺服器作為中間媒介負責從資料來源讀取資料再跟另外一端的客戶端通訊。在 OPC客戶端/伺服器 的結構圖中, 通訊的發起端是, 也只能是OPC客戶端。客戶端

Onvif客戶伺服器通訊時鑑權的實現

OnvifDigest.h /** SHA1 digest size in octets */ #define SOAP_SMD_SHA1_SIZE (20) /** Size of the random nonce */ #define SOAP_WSSE_NONCELEN (20) #define

總結linux網路程式設計

1.有一篇好的文章,對Linux下socket程式設計的原理和要點說的很清楚: 2.一些windows網路程式設計的要點吧。包括大頭序,小頭序,網路位元組序。一些常用的函式等。。 3.《linux網路程式設計》宋斌寫的,這本書不錯。寫的清楚,容易懂。是一個比較好的參

linuxSNMP的extend--定義監控

linux snmp extend snmp除了具有系統默認的監控項,還提供了一個強大的功能,可自定義監控項。在snmpd.conf配置文件中的exec選項(高版本的snmp中,extend替代了exec)提供了自定義的監控功能,可以將命令或者腳本的執行結果添加到snmp的查詢中。格式為:extend

解決Linux網路程式設計(sendto send )出現 SIGPIPE 訊號導致程式異常終止的問題

引言 最近在Linux下網路程式設計時,出現SIGPIPE 訊號導致程式異常終止,本文記錄下解決的方法以及相應的知識。 SIGPIPE 訊號資料 什麼時候出現此訊號,APUE中有關此訊號的解釋如下: Linux man手冊有關此訊號的解釋: man 7 signal SI

python網路程式設計——osi7層協議

每層執行常見的物理裝置 網際網路=物理連線介質+網際網路協議 應用層:http協議等等 自己定義 傳輸層:tcp/udp協議 應用軟體埠協議 網路層: IP協議+子網掩碼 arp協議:地址解析協議,根據ip解析mac地址 資料報:報頭+內容

WPF程式設計定義Button控制元件樣式

自.NET Framework 3.0 以後,WPF程式設計框架可使開發人員開發出更加令人耳目一新的桌面應用程式。它使開發工作更加方便快捷,它將設計人員和程式設計人員的工作分離開來。至於WPF的背景歷史、框架特點、框架結構這裡就不再贅述。有興趣的同袍可在百度搜索關於WPF的相

linuxshell 程式設計擴充套件正則表示式

1. ‘+’ 限定字元 +限定符表示前面字元至少出現一次或者多次。與*不同在於0次或者多次 2. '?' 限定符 ?限定前面的字元最多出現一次。即出現0次或者1次 3. 數線 |和圓括號() 例如

Linux-C網路程式設計epoll函式

上文中說到如果從100的不同的地方取外賣,那麼epoll相當於一部手機,當外賣到達後,送貨員可以通知你,從而達到每去必得,少走很多路。 它是如何實現這些作用的呢? epoll的功能 epoll是select/poll的強化版,同是多路複用的函式,epoll

Ubuntu--(5)LinuxC++編譯生成定義靜態庫/動態庫

編譯生成靜態庫: 1.編寫CPP檔案test.h #include <iostream> using namespace std; class ADD_SUB{ public

flume-ng程式設計定義攔截器

     從攔截body開始自定義intercepter程式設計完成每個body字串的解析欄位的正則提取和拼接,我們自定義的這個類叫:LogAnalysis 如下: package com.besttone.interceptor; import com.g

IOS程式設計定義UICombox

我們在做IOS開發的時候,有時候會限制於系統自帶的一些控制元件,而無法做到更好的使用者體驗,今天我們就來介紹一下我們自己做的UICombox控制元件,先來看一下圖:   這是我們自定義的控制元件,實現了點選輸入框,彈出資料拾取器的效果 首先我們先來整理一下思路,UIComb

linuxc程式設計訊號量semget,semop,semctl函式

訊號量 今天去參加北京市的植樹志願者活動啦!早上起來的挺早的,6:10就被傑子給叫起來啦,帶著對春天的嚮往,我們坐著不花錢的大巴去做為市領導服務去啦!發了一個小紅帽還有一個紅色的制服。 唉。。。說好