閱讀285 返回首頁    go 阿裏雲 go 技術社區[雲棲]


基於流模式長連接的簡單實現

基於流模式的長連接我們可以做很多事情,比方說在局域網內,我們建立這種模式,可以時時傳輸數據,而不用每次傳輸數據是創建socket,傳輸完後,關閉socket。可以減少創建銷毀socket的時間。
基於流模式的下,數據一直在發送,我們需要知道,每次發送數據量,所以常見的方式時,我們在發送數據時,指定此次發送數據的長度,服務器讀取流數據時,先讀取數據長度,然後再按長度讀取此次發送的數據。
我使用select複用IO機製實現了一個簡單的client,server機製,希望對初學者有幫助
客戶端代碼:
  1. /*
  2.  * =====================================================================================
  3.  *
  4.  *       Filename:  client.cc
  5.  *    Description:  
  6.  *        Version:  1.0
  7.  *        Created:  2008年12月18日 09時50分36秒 CST
  8.  *       Revision:  none *
  9.  *         Author:  ugg (ugg_xchj@yahoo.com.cn)
  10.  *        Company:  
  11.  *
  12.  * =====================================================================================
  13.  */
  14. #include <string>
  15. #include <iostream>
  16. #include <netdb.h>
  17. #include <sys/socket.h>
  18. #include <sys/types.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. using namespace::std;
  22. // 默認內容設置
  23. string hostname="localhost";
  24. int    hostport=7763;
  25. string sendContents="this is client";
  26. void getCMD(int argc, char *argv[])
  27. {
  28.     switch(argc)
  29.     {
  30.         case 2:
  31.             hostname = argv[1];
  32.            break;
  33.         case 3:
  34.             hostname = argv[1];
  35.             hostport = atoi(argv[2]);   
  36.             if(hostport < 1024 || hostport >65535)
  37.             {
  38.                 cerr << "Error: port=" << hostport 
  39.                     << " Error, range 1024 - 65535" << endl;
  40.                 exit(0);
  41.             }
  42.             break;
  43.         case 4:
  44.             hostname = argv[1];
  45.             hostport = atoi(argv[2]);   
  46.             if(hostport < 1024 || hostport >65535)
  47.             {
  48.                 cerr << "Error: port=" << hostport 
  49.                     << " Error, range 1024 - 65535" << endl;
  50.                 exit(0);
  51.             }
  52.             sendContents = argv[3]; 
  53.             break;
  54.         default:
  55.             break;
  56.     }
  57. }   
  58. int
  59. main ( int argc, char *argv[] )
  60. {
  61.     getCMD(argc,argv);
  62.     
  63.     int fd; 
  64.     // create socket
  65.     if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
  66.     {
  67.         cerr << "Error: socket()" <<endl;
  68.         exit(0);
  69.     }
  70.     // 
  71.     struct hostent *he;
  72.     he = gethostbyname(hostname.c_str());
  73.     if(he == NULL ) {
  74.         cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
  75.         exit(0);
  76.     }
  77.     struct sockaddr_in serv_addr;
  78.     serv_addr.sin_family=AF_INET;
  79.     serv_addr.sin_port=htons(hostport);
  80.     serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
  81.     bzero( &(serv_addr.sin_zero),8);
  82.     // connction
  83.     if(connect(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
  84.         cerr<<"Error: connect() error"<<endl;
  85.         exit(0);
  86.     }
  87.     cout << "send contents to server(" << hostname 
  88.         << ":" << hostport << ")" << endl;
  89.     cout << sendContents << endl;
  90.     cout << "................" << endl;
  91.     // 增加此次發送消息的長度
  92.     char buffer[1024];      
  93.     sprintf(buffer,"%8d",sendContents.length());
  94.     sendContents = string(buffer,8)+sendContents;
  95.     
  96.     const char* content = sendContents.c_str();
  97.     int send=0;
  98.     int length = sendContents.length();
  99.     
  100.     // send
  101.     while(1)
  102.     {
  103.         int ret = write(fd,content+send,length-send);
  104.         if(ret == 0)
  105.         {
  106.             // server close
  107.             cerr << "Error: server close" << endl;
  108.             exit(0);
  109.         }
  110.         send += ret;
  111.         if(length == send)
  112.             break;
  113.     }
  114.     string contents;
  115.     // 先接受8字節,獲取服務返回長度
  116.     int ret = recv(fd,buffer,8,0);
  117.     // 服務器關閉
  118.     if(ret == 0)
  119.     {
  120.         cerr << "Error: server close" << endl;  
  121.         exit(0);
  122.     }
  123.     if(ret == 8)
  124.     {
  125.         buffer[8]='/0';
  126.         int len = atoi(buffer);
  127.         if(len < 1024){
  128.             int rets=0;
  129.             while((ret = recv(fd,buffer,len-rets,0))>0)
  130.             {
  131.                 contents.append(buffer,ret);
  132.                 rets += ret;
  133.                 if(len==rets)
  134.                     break;
  135.             }
  136.         }else{
  137.             int buflen=1024;
  138.             while( (ret = recv(fd,buffer,buflen,0)) > 0)
  139.             {
  140.                 contents.append(buffer,ret);
  141.                 len-=ret;
  142.                 if(len<2048){
  143.                     buflen=len;
  144.                 }
  145.                 if(len <= 0)
  146.                     break;
  147.             }
  148.         }
  149.     }else {
  150.         cerr << "Error: recv data Error " << endl;
  151.     }
  152.     cout << "recv: ";
  153.     cout << contents << endl;
  154.     return 0;
  155. }               /* ----------  end of function main  ---------- */
服務器端代碼

  1. /*
  2.  * =====================================================================================
  3.  *
  4.  *       Filename:  server.cc
  5.  *    Description:  
  6.  *        Version:  1.0
  7.  *        Created:  2008年12月18日 09時50分50秒 CST
  8.  *       Revision:  none *
  9.  *         Author:  ugg (ugg_xchj@yahoo.com.cn)
  10.  *        Company:  
  11.  *
  12.  * =====================================================================================
  13.  */
  14. #include <string>
  15. #include <iostream>
  16. #include <netdb.h>
  17. #include <sys/socket.h>
  18. #include <sys/types.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <errno.h>
  22. #include <map>
  23. using namespace::std;
  24. struct clientInfo
  25. {
  26.     string host;
  27.     int port;
  28. };
  29. typedef map<int, clientInfo> mapgroups;
  30. typedef map<int, clientInfo>::iterator mapgroupsor;
  31. typedef map<int, clientInfo>::const_iterator mapgroupscor;
  32. //  記錄客戶端的信息
  33. mapgroups groups;
  34. // 默認內容設置
  35. string hostname="localhost";
  36. int    hostport=7763;
  37. string serversendContents="this is server";
  38. void getCMD(int argc, char *argv[])
  39. {
  40.     switch(argc)
  41.     {
  42.         case 2:
  43.             hostname = argv[1];
  44.            break;
  45.         case 3:
  46.             hostname = argv[1];
  47.             hostport = atoi(argv[2]);   
  48.             if(hostport < 1024 || hostport >65535)
  49.             {
  50.                 cerr << "Error: port=" << hostport 
  51.                     << " Error, range 1024 - 65535" << endl;
  52.                 exit(0);
  53.             }
  54.             break;
  55.         case 4:
  56.             hostname = argv[1];
  57.             hostport = atoi(argv[2]);   
  58.             if(hostport < 1024 || hostport >65535)
  59.             {
  60.                 cerr << "Error: port=" << hostport 
  61.                     << " Error, range 1024 - 65535" << endl;
  62.                 exit(0);
  63.             }
  64.             serversendContents = argv[3];   
  65.             break;
  66.         default:
  67.             break;
  68.     }
  69. }   
  70. void clearfd(int fd,fd_set& rdfds)
  71. {
  72.     FD_CLR(fd,&rdfds);  
  73.     mapgroupsor it = groups.find(fd);
  74.     if(it != groups.end())
  75.     {
  76.         cerr << "client host=" << it->second.host << ", port=" << it->second.port 
  77.             << " close" << endl;
  78.         groups.erase(fd);
  79.     }
  80. }
  81. // recv and send message
  82. void recvandsend(int fd,fd_set& rdfds,string& contents, const string& texts)
  83. {
  84.     // 接受消息
  85.     char buffer[1024];
  86.     int rets=0;
  87.     int ret=0;
  88.     ret = recv(fd,buffer,8,0);
  89.     if(ret == 0)
  90.     {
  91.         clearfd(fd,rdfds);
  92.         return;
  93.     }
  94.     if(ret == 8)
  95.     {
  96.         buffer[8]='/0';
  97.         int len = atoi(buffer);
  98.         if(len < 1024){
  99.             while((ret = recv(fd,buffer,len,0))>0)
  100.             {
  101.                 contents.append(buffer,ret);
  102.                 rets += ret;
  103.                 len-=ret;
  104.                 if(len==0)
  105.                     break;
  106.             }
  107.             if(ret == 0){
  108.                 clearfd(fd,rdfds);
  109.                 return;
  110.             }
  111.         }else{
  112.             int buflen=1024;
  113.             while( (ret = recv(fd,buffer,buflen,0)) > 0)
  114.             {
  115.                 contents.append(buffer,ret);
  116.                 rets += ret;
  117.                 len-=ret;
  118.                 if(len<2048){
  119.                     buflen=len;
  120.                 }
  121.                 if(len <= 0)
  122.                     break;
  123.             }
  124.             if(ret == 0){
  125.                 clearfd(fd,rdfds);
  126.                 return;
  127.             }
  128.         }
  129.     }else{
  130.         clearfd(fd,rdfds);
  131.         return;
  132.     }
  133.     // 發送信息
  134.     sprintf(buffer,"%8d",texts.length());   
  135.     string sendContents = string(buffer,8);
  136.     sendContents += texts;
  137.     const char* content = sendContents.c_str();
  138.     int send=0;
  139.     int length = sendContents.length();
  140.     // send
  141.     while(1)
  142.     {
  143.         int ret = write(fd,content+send,length-send);
  144.         if(ret == 0)
  145.         {
  146.             // server close
  147.             cerr << "Error: server close" << endl;
  148.             clearfd(fd,rdfds);
  149.             return;
  150.         }
  151.         send += ret;
  152.         if(length == send)
  153.             break;
  154.     }
  155. }   
  156. int
  157. main ( int argc, char *argv[] )
  158. {
  159.     getCMD(argc,argv);
  160.     
  161.     int fd; 
  162.     // create socket
  163.     if((fd=socket(PF_INET,SOCK_STREAM,0)) == -1)
  164.     {
  165.         cerr << "Error: socket()" <<endl;
  166.         exit(0);
  167.     }
  168.     // 
  169.     struct hostent *he;
  170.     he = gethostbyname(hostname.c_str());
  171.     if(he == NULL ) {
  172.         cerr <<"Error: gethostbyname() error,hostname=" << hostname << endl;
  173.         exit(0);
  174.     }
  175.     struct sockaddr_in serv_addr;
  176.     serv_addr.sin_family=AF_INET;
  177.     serv_addr.sin_port=htons(hostport);
  178.     serv_addr.sin_addr=*((struct in_addr*)he->h_addr);
  179.     bzero( &(serv_addr.sin_zero),8);
  180.     // bind
  181.     if(bind(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) {
  182.         cerr<<"Error: bind() error"<<endl;
  183.         exit(0);
  184.     }
  185.     // listen
  186.     int ret_listen = listen(fd,5);
  187.     if(ret_listen < 0)
  188.     {
  189.         cerr << "Error: Listen port error,socket fd: " << fd << endl;
  190.         cerr << "Error: listen errno = " << ret_listen << endl;
  191.         exit(0);
  192.     }
  193.     fd_set rdfds;
  194.     int nfds;
  195.     // First poll the sockets
  196.     FD_ZERO(&rdfds);
  197.     FD_SET(fd, &rdfds);
  198.     while(1)
  199.     {
  200.         if ((nfds = select(FD_SETSIZE, &rdfds, NULL, NULL, NULL)) < 0) {
  201.             if (errno != EINTR) {
  202.                 cerr << "Error: select error" << endl;
  203.                 exit(3);
  204.             }
  205.         }
  206.         if(FD_ISSET(fd, &rdfds))
  207.         {
  208.             socklen_t len;
  209.             struct sockaddr_in client_addr;
  210.             len = sizeof(struct sockaddr);
  211.             int clientfd = accept(fd,(struct sockaddr *)&client_addr,&len);
  212.             if(clientfd == -1)
  213.             {
  214.                 cerr << "Error: accept client error" << endl;
  215.             }else{
  216.                 clientInfo info;    
  217.                 info.host = inet_ntoa(client_addr.sin_addr);
  218.                 info.port = ntohs(client_addr.sin_port);
  219.                 cerr << "server: got connection from "<< info.host 
  220.                     <<", port "<< info.port << endl;
  221.                 groups.insert(make_pair(clientfd,info));
  222.                 FD_SET(clientfd,&rdfds);
  223.             }
  224.         }else{
  225.             mapgroupscor it;
  226.             for(it = groups.begin(); it != groups.end(); ++it)
  227.             {
  228.                 if(FD_ISSET(it->first,&rdfds))
  229.                 {
  230.                     string strRev;
  231.                     recvandsend(it->first,rdfds,strRev,serversendContents);         
  232.                     break;
  233.                 }
  234.             }
  235.         }
  236.     }   
  237.     return 0;
  238. }               /* ----------  end of function main  ---------- */
上麵的代碼在linux下已經編譯通過

另外你可以到這裏下載源代碼

最後更新:2017-04-02 00:06:39

  上一篇:go 在C#中獲取Access數據庫中的所有表名和列名
  下一篇:go Reporting Service在Web Application中的應用