Linux下用C编写WebSocet服务以响应HTML5的WebSocket请求

来源:互联网 发布:ubuntu 16.04 分区方案 编辑:程序博客网 时间:2024/04/28 10:46

转自http://blog.csdn.net/xxdddail/article/details/19070149


在HTML5中新增了WebSocket,使得通讯变得更加方便。这样一来,Web与硬件的交互除了CGI和XHR的方式外,又有了一个新的方式。那么使用WebSocket又如何与下层通信呢?看看WebSocket的相关介绍就会发现,其类似于HTTP协议的通信,但又不同于HTTP协议通信,其最终使用的是TCP通信。具体的可以参照该文WebScoket 规范 + WebSocket 协议。

我们先来看看通信的效果图



下面是实现的步骤

1.建立SOCKET监听

WebSocket也是TCP通信,所以服务端需要先建立监听,下面是实现的代码。

[cpp] view plain copy
print?
  1. /* server.c */  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <unistd.h>  
  6. #include <sys/socket.h>  
  7. #include <netinet/in.h>  
  8.   
  9. #include "base64.h"  
  10. #include "sha1.h"  
  11. #include "intLib.h"  
  12.   
  13.   
  14. #define REQUEST_LEN_MAX 1024  
  15. #define DEFEULT_SERVER_PORT 8000  
  16. #define WEB_SOCKET_KEY_LEN_MAX 256  
  17. #define RESPONSE_HEADER_LEN_MAX 1024  
  18. #define LINE_MAX 256  
  19.   
  20.   
  21. void shakeHand(int connfd,const char *serverKey);  
  22. char * fetchSecKey(const char * buf);  
  23. char * computeAcceptKey(const char * buf);  
  24. char * analyData(const char * buf,const int bufLen);  
  25. char * packData(const char * message,unsigned long * len);  
  26. void response(const int connfd,const char * message);  
  27.   
  28. int main(int argc, char *argv[])  
  29. {  
  30.     struct sockaddr_in servaddr, cliaddr;  
  31.     socklen_t cliaddr_len;  
  32.     int listenfd, connfd;  
  33.     char buf[REQUEST_LEN_MAX];  
  34.     char *data;  
  35.     char str[INET_ADDRSTRLEN];  
  36.     char *secWebSocketKey;  
  37.     int i,n;  
  38.     int connected=0;//0:not connect.1:connected.  
  39.     int port= DEFEULT_SERVER_PORT;  
  40.   
  41.     if(argc>1)  
  42.       {  
  43.         port=atoi(argv[1]);  
  44.       }  
  45.     if(port<=0||port>0xFFFF)  
  46.       {  
  47.         printf("Port(%d) is out of range(1-%d)\n",port,0xFFFF);  
  48.         return;  
  49.       }  
  50.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  51.   
  52.     bzero(&servaddr, sizeof(servaddr));  
  53.     servaddr.sin_family = AF_INET;  
  54.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  55.     servaddr.sin_port = htons(port);  
  56.       
  57.     bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));  
  58.   
  59.     listen(listenfd, 20);  
  60.   
  61.     printf("Listen %d\nAccepting connections ...\n",port);  
  62.     cliaddr_len = sizeof(cliaddr);  
  63.     connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);  
  64.     printf("From %s at PORT %d\n",  
  65.                inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),  
  66.                ntohs(cliaddr.sin_port));  
  67.   
  68.     while (1)  
  69.       {  
  70.       
  71.         memset(buf,0,REQUEST_LEN_MAX);  
  72.         n = read(connfd, buf, REQUEST_LEN_MAX);   
  73.         printf("---------------------\n");  
  74.       
  75.       
  76.         if(0==connected)  
  77.           {  
  78.             printf("read:%d\n%s\n",n,buf);  
  79.             secWebSocketKey=computeAcceptKey(buf);    
  80.             shakeHand(connfd,secWebSocketKey);  
  81.             connected=1;  
  82.             continue;  
  83.           }  
  84.   
  85.         data=analyData(buf,n);  
  86.         response(connfd,data);  
  87.     }  
  88.     close(connfd);  
  89. }  

2.握手

在建立监听后,网页向服务端发现WebSocket请求,这时需要先进行握手。握手时,客户端会在协议中包含一个握手的唯一Key,服务端在拿到这个Key后,需要加入一个GUID,然后进行sha1的加密,再转换成base64,最后再发回到客户端。这样就完成了一次握手。此种握手方式是针对chrome websocket 13的版本,其他版本的可能会有所不同。下面是实现的代码。

[cpp] view plain copy
print?
  1. char * fetchSecKey(const char * buf)  
  2. {  
  3.   char *key;  
  4.   char *keyBegin;  
  5.   char *flag="Sec-WebSocket-Key: ";  
  6.   int i=0, bufLen=0;  
  7.   
  8.   key=(char *)malloc(WEB_SOCKET_KEY_LEN_MAX);  
  9.   memset(key,0, WEB_SOCKET_KEY_LEN_MAX);  
  10.   if(!buf)  
  11.     {  
  12.       return NULL;  
  13.     }  
  14.    
  15.   keyBegin=strstr(buf,flag);  
  16.   if(!keyBegin)  
  17.     {  
  18.       return NULL;  
  19.     }  
  20.   keyBegin+=strlen(flag);  
  21.   
  22.   bufLen=strlen(buf);  
  23.   for(i=0;i<bufLen;i++)  
  24.     {  
  25.       if(keyBegin[i]==0x0A||keyBegin[i]==0x0D)  
  26.     {  
  27.       break;  
  28.     }  
  29.       key[i]=keyBegin[i];  
  30.     }  
  31.     
  32.   return key;  
  33. }  
  34.   
  35. char * computeAcceptKey(const char * buf)  
  36. {  
  37.   char * clientKey;  
  38.   char * serverKey;   
  39.   char * sha1DataTemp;  
  40.   char * sha1Data;  
  41.   short temp;  
  42.   int i,n;  
  43.   const char * GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";  
  44.    
  45.   
  46.   if(!buf)  
  47.     {  
  48.       return NULL;  
  49.     }  
  50.   clientKey=(char *)malloc(LINE_MAX);  
  51.   memset(clientKey,0,LINE_MAX);  
  52.   clientKey=fetchSecKey(buf);  
  53.    
  54.   if(!clientKey)  
  55.     {  
  56.       return NULL;  
  57.     }  
  58.   
  59.    
  60.   strcat(clientKey,GUID);  
  61.   
  62.   sha1DataTemp=sha1_hash(clientKey);  
  63.   n=strlen(sha1DataTemp);  
  64.   
  65.   
  66.   sha1Data=(char *)malloc(n/2+1);  
  67.   memset(sha1Data,0,n/2+1);  
  68.    
  69.   for(i=0;i<n;i+=2)  
  70.     {        
  71.       sha1Data[i/2]=htoi(sha1DataTemp,i,2);      
  72.     }   
  73.   
  74.   serverKey = base64_encode(sha1Data, strlen(sha1Data));   
  75.   
  76.   return serverKey;  
  77. }  
  78.   
  79. void shakeHand(int connfd,const char *serverKey)  
  80. {  
  81.   char responseHeader [RESPONSE_HEADER_LEN_MAX];  
  82.   
  83.   if(!connfd)  
  84.     {  
  85.       return;  
  86.     }  
  87.   
  88.   if(!serverKey)  
  89.     {  
  90.       return;  
  91.     }  
  92.   
  93.   memset(responseHeader,'\0',RESPONSE_HEADER_LEN_MAX);  
  94.   
  95.   sprintf(responseHeader, "HTTP/1.1 101 Switching Protocols\r\n");  
  96.   sprintf(responseHeader, "%sUpgrade: websocket\r\n", responseHeader);  
  97.   sprintf(responseHeader, "%sConnection: Upgrade\r\n", responseHeader);  
  98.   sprintf(responseHeader, "%sSec-WebSocket-Accept: %s\r\n\r\n", responseHeader, serverKey);  
  99.    
  100.   printf("Response Header:%s\n",responseHeader);  
  101.   
  102.   write(connfd,responseHeader,strlen(responseHeader));  
  103. }  

注意:

1.Connection后面的值与HTTP通信时的不一样了,是Upgrade,而Upgrade又对应到了websocket,这样就标识了该通信协议是websocket的方式。

2.在sha1加密后进行base64编码时,使用sha1加密后的串必须将其当成16进制的字符串,将每两个字符合成一个新的码(0-0xFF间)来进一步计算后,才可以进行base64换算(我开始时就在这里折腾了很久,后面才弄明白还要加上这一步),如果是直接就base64,那就会握手失败。

3.对于sha1和base64网上有很多,后面也附上我所使用的代码。


3.数据传输

握手成功后就可以进行数据传输了,只要按照WebSocket的协议来解就可以了。下面是实现的代码

[cpp] view plain copy
print?
  1. char * analyData(const char * buf,const int bufLen)  
  2. {  
  3.   char * data;  
  4.   char fin, maskFlag,masks[4];  
  5.   char * payloadData;  
  6.   char temp[8];  
  7.   unsigned long n, payloadLen=0;  
  8.   unsigned short usLen=0;  
  9.   int i=0;   
  10.   
  11.   
  12.  if (bufLen < 2)   
  13.    {  
  14.      return NULL;  
  15.    }  
  16.   
  17.   fin = (buf[0] & 0x80) == 0x80; // 1bit,1表示最后一帧    
  18.   if (!fin)  
  19.    {  
  20.        return NULL;// 超过一帧暂不处理   
  21.    }  
  22.   
  23.    maskFlag = (buf[1] & 0x80) == 0x80; // 是否包含掩码    
  24.    if (!maskFlag)  
  25.    {  
  26.        return NULL;// 不包含掩码的暂不处理  
  27.    }  
  28.   
  29.    payloadLen = buf[1] & 0x7F; // 数据长度   
  30.    if (payloadLen == 126)  
  31.    {        
  32.      memcpy(masks,buf+4, 4);        
  33.      payloadLen =(buf[2]&0xFF) << 8 | (buf[3]&0xFF);    
  34.      payloadData=(char *)malloc(payloadLen);  
  35.      memset(payloadData,0,payloadLen);  
  36.      memcpy(payloadData,buf+8,payloadLen);  
  37.     }  
  38.     else if (payloadLen == 127)  
  39.     {  
  40.      memcpy(masks,buf+10,4);    
  41.      for ( i = 0; i < 8; i++)  
  42.      {  
  43.          temp[i] = buf[9 - i];  
  44.      }   
  45.   
  46.      memcpy(&n,temp,8);    
  47.      payloadData=(char *)malloc(n);   
  48.      memset(payloadData,0,n);   
  49.      memcpy(payloadData,buf+14,n);//toggle error(core dumped) if data is too long.  
  50.      payloadLen=n;      
  51.      }  
  52.      else  
  53.      {     
  54.       memcpy(masks,buf+2,4);      
  55.       payloadData=(char *)malloc(payloadLen);  
  56.       memset(payloadData,0,payloadLen);  
  57.       memcpy(payloadData,buf+6,payloadLen);   
  58.      }  
  59.   
  60.      for (i = 0; i < payloadLen; i++)  
  61.      {  
  62.        payloadData[i] = (char)(payloadData[i] ^ masks[i % 4]);  
  63.      }  
  64.    
  65.      printf("data(%d):%s\n",payloadLen,payloadData);  
  66.      return payloadData;  
  67. }  
  68.   
  69. char *  packData(const char * message,unsigned long * len)  
  70.  {  
  71.          char * data=NULL;  
  72.      unsigned long n;  
  73.   
  74.      n=strlen(message);  
  75.             if (n < 126)  
  76.             {  
  77.           data=(char *)malloc(n+2);  
  78.           memset(data,0,n+2);      
  79.           data[0] = 0x81;  
  80.           data[1] = n;  
  81.           memcpy(data+2,message,n);  
  82.           *len=n+2;  
  83.             }  
  84.             else if (n < 0xFFFF)  
  85.             {  
  86.           data=(char *)malloc(n+4);  
  87.           memset(data,0,n+4);  
  88.           data[0] = 0x81;  
  89.           data[1] = 126;  
  90.           data[2] = (n>>8 & 0xFF);  
  91.           data[3] = (n & 0xFF);  
  92.           memcpy(data+4,message,n);      
  93.           *len=n+4;  
  94.             }  
  95.             else  
  96.             {  
  97.        
  98.                 // 暂不处理超长内容    
  99.           *len=0;  
  100.             }  
  101.     
  102.   
  103.         return data;  
  104.  }  
  105.   
  106. void response(int connfd,const char * message)  
  107. {  
  108.   char * data;  
  109.   unsigned long n=0;  
  110.   int i;  
  111.   if(!connfd)  
  112.     {  
  113.       return;  
  114.     }  
  115.   
  116.   if(!data)  
  117.     {  
  118.       return;  
  119.     }  
  120.   data=packData(message,&n);   
  121.    
  122.   if(!data||n<=0)  
  123.     {  
  124.       printf("data is empty!\n");  
  125.       return;  
  126.     }   
  127.    
  128.   write(connfd,data,n);  
  129.     
  130. }  

注意:

1.对于超过0xFFFF长度的数据在分析数据部分虽然作了处理,但是在memcpy时会报core dumped的错误,没有解决,请过路的大牛帮忙指点。在packData部分也未对这一部分作处理。

2.在这里碰到了一个郁闷的问题,在命名函数时,将函数名写的过长了(fetchSecWebSocketAcceptkey),结果导致编译通过,但在运行时却莫名其妙的报core dumped的错误,试了很多方法才发现是这个原因,后将名字改短后就OK了。

3.在回复数据时,只要按websocket的协议进行回应就可以了。

附上sha1、base64和intLib的代码(sha1和base64是从网上摘来的)

sha1.h

[cpp] view plain copy
print?
  1. //sha1.h:对字符串进行sha1加密  
  2. #ifndef _SHA1_H_  
  3. #define _SHA1_H_  
  4.   
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <string.h>  
  8.   
  9.   
  10. typedef struct SHA1Context{  
  11.     unsigned Message_Digest[5];        
  12.     unsigned Length_Low;               
  13.     unsigned Length_High;              
  14.     unsigned char Message_Block[64];   
  15.     int Message_Block_Index;           
  16.     int Computed;                      
  17.     int Corrupted;                     
  18. } SHA1Context;  
  19.   
  20. void SHA1Reset(SHA1Context *);  
  21. int SHA1Result(SHA1Context *);  
  22. void SHA1Input( SHA1Context *,const char *,unsigned);  
  23. #endif  
  24.   
  25.   
  26. #define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))  
  27.   
  28. void SHA1ProcessMessageBlock(SHA1Context *);  
  29. void SHA1PadMessage(SHA1Context *);  
  30.   
  31. void SHA1Reset(SHA1Context *context){// 初始化动作  
  32.     context->Length_Low             = 0;  
  33.     context->Length_High            = 0;  
  34.     context->Message_Block_Index    = 0;  
  35.   
  36.     context->Message_Digest[0]      = 0x67452301;  
  37.     context->Message_Digest[1]      = 0xEFCDAB89;  
  38.     context->Message_Digest[2]      = 0x98BADCFE;  
  39.     context->Message_Digest[3]      = 0x10325476;  
  40.     context->Message_Digest[4]      = 0xC3D2E1F0;  
  41.   
  42.     context->Computed   = 0;  
  43.     context->Corrupted  = 0;  
  44. }  
  45.   
  46.   
  47. int SHA1Result(SHA1Context *context){// 成功返回1,失败返回0  
  48.     if (context->Corrupted) {  
  49.         return 0;  
  50.     }  
  51.     if (!context->Computed) {  
  52.         SHA1PadMessage(context);  
  53.         context->Computed = 1;  
  54.     }  
  55.     return 1;  
  56. }  
  57.   
  58.   
  59. void SHA1Input(SHA1Context *context,const char *message_array,unsigned length){  
  60.     if (!length) return;  
  61.   
  62.     if (context->Computed || context->Corrupted){  
  63.         context->Corrupted = 1;  
  64.         return;  
  65.     }  
  66.   
  67.     while(length-- && !context->Corrupted){  
  68.         context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);  
  69.   
  70.         context->Length_Low += 8;  
  71.   
  72.         context->Length_Low &= 0xFFFFFFFF;  
  73.         if (context->Length_Low == 0){  
  74.             context->Length_High++;  
  75.             context->Length_High &= 0xFFFFFFFF;  
  76.             if (context->Length_High == 0) context->Corrupted = 1;  
  77.         }  
  78.   
  79.         if (context->Message_Block_Index == 64){  
  80.             SHA1ProcessMessageBlock(context);  
  81.         }  
  82.         message_array++;  
  83.     }  
  84. }  
  85.   
  86. void SHA1ProcessMessageBlock(SHA1Context *context){  
  87.     const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };  
  88.     int         t;                  
  89.     unsigned    temp;               
  90.     unsigned    W[80];              
  91.     unsigned    A, B, C, D, E;      
  92.   
  93.     for(t = 0; t < 16; t++) {  
  94.     W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;  
  95.     W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;  
  96.     W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;  
  97.     W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);  
  98.     }  
  99.       
  100.     for(t = 16; t < 80; t++)  W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);  
  101.   
  102.     A = context->Message_Digest[0];  
  103.     B = context->Message_Digest[1];  
  104.     C = context->Message_Digest[2];  
  105.     D = context->Message_Digest[3];  
  106.     E = context->Message_Digest[4];  
  107.   
  108.     for(t = 0; t < 20; t++) {  
  109.         temp =  SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];  
  110.         temp &= 0xFFFFFFFF;  
  111.         E = D;  
  112.         D = C;  
  113.         C = SHA1CircularShift(30,B);  
  114.         B = A;  
  115.         A = temp;  
  116.     }  
  117.     for(t = 20; t < 40; t++) {  
  118.         temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];  
  119.         temp &= 0xFFFFFFFF;  
  120.         E = D;  
  121.         D = C;  
  122.         C = SHA1CircularShift(30,B);  
  123.         B = A;  
  124.         A = temp;  
  125.     }  
  126.     for(t = 40; t < 60; t++) {  
  127.         temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];  
  128.         temp &= 0xFFFFFFFF;  
  129.         E = D;  
  130.         D = C;  
  131.         C = SHA1CircularShift(30,B);  
  132.         B = A;  
  133.         A = temp;  
  134.     }  
  135.     for(t = 60; t < 80; t++) {  
  136.         temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];  
  137.         temp &= 0xFFFFFFFF;  
  138.         E = D;  
  139.         D = C;  
  140.         C = SHA1CircularShift(30,B);  
  141.         B = A;  
  142.         A = temp;  
  143.     }  
  144.     context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;  
  145.     context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;  
  146.     context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;  
  147.     context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;  
  148.     context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;  
  149.     context->Message_Block_Index = 0;  
  150. }  
  151.   
  152. void SHA1PadMessage(SHA1Context *context){  
  153.     if (context->Message_Block_Index > 55) {  
  154.         context->Message_Block[context->Message_Block_Index++] = 0x80;  
  155.         while(context->Message_Block_Index < 64)  context->Message_Block[context->Message_Block_Index++] = 0;  
  156.         SHA1ProcessMessageBlock(context);  
  157.         while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;  
  158.     } else {  
  159.         context->Message_Block[context->Message_Block_Index++] = 0x80;  
  160.         while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;  
  161.     }  
  162.     context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;  
  163.     context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;  
  164.     context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;  
  165.     context->Message_Block[59] = (context->Length_High) & 0xFF;  
  166.     context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;  
  167.     context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;  
  168.     context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;  
  169.     context->Message_Block[63] = (context->Length_Low) & 0xFF;  
  170.   
  171.     SHA1ProcessMessageBlock(context);  
  172. }  
  173.   
  174. /* 
  175. int sha1_hash(const char *source, char *lrvar){// Main 
  176.     SHA1Context sha; 
  177.     char buf[128]; 
  178.  
  179.     SHA1Reset(&sha); 
  180.     SHA1Input(&sha, source, strlen(source)); 
  181.  
  182.     if (!SHA1Result(&sha)){ 
  183.         printf("SHA1 ERROR: Could not compute message digest"); 
  184.         return -1; 
  185.     } else { 
  186.         memset(buf,0,sizeof(buf)); 
  187.         sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1], 
  188.         sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]); 
  189.         //lr_save_string(buf, lrvar); 
  190.          
  191.         return strlen(buf); 
  192.     } 
  193. } 
  194. */  
  195.   
  196. char * sha1_hash(const char *source){// Main  
  197.     SHA1Context sha;  
  198.     char *buf;//[128];  
  199.   
  200.     SHA1Reset(&sha);  
  201.     SHA1Input(&sha, source, strlen(source));  
  202.   
  203.     if (!SHA1Result(&sha)){  
  204.         printf("SHA1 ERROR: Could not compute message digest");  
  205.         return NULL;  
  206.     } else {  
  207.       buf=(char *)malloc(128);  
  208.         memset(buf,0,sizeof(buf));  
  209.         sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],  
  210.         sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);  
  211.         //lr_save_string(buf, lrvar);  
  212.           
  213.         //return strlen(buf);  
  214.         return buf;  
  215.     }  
  216. }  

base64.h

[cpp] view plain copy
print?
  1. #ifndef _BASE64_H_  
  2. #define _BASE64_H_  
  3.    
  4. #include <stdio.h>   
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7.   
  8. const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";   
  9. char* base64_encode(const char* data, int data_len);   
  10. char *base64_decode(const char* data, int data_len);   
  11. static char find_pos(char ch);   
  12.   
  13. /* */   
  14. char *base64_encode(const char* data, int data_len)   
  15. {   
  16.     //int data_len = strlen(data);   
  17.     int prepare = 0;   
  18.     int ret_len;   
  19.     int temp = 0;   
  20.     char *ret = NULL;   
  21.     char *f = NULL;   
  22.     int tmp = 0;   
  23.     char changed[4];   
  24.     int i = 0;   
  25.     ret_len = data_len / 3;   
  26.     temp = data_len % 3;   
  27.     if (temp > 0)   
  28.     {   
  29.         ret_len += 1;   
  30.     }   
  31.     ret_len = ret_len*4 + 1;   
  32.     ret = (char *)malloc(ret_len);   
  33.         
  34.     if ( ret == NULL)   
  35.     {   
  36.         printf("No enough memory.\n");   
  37.         exit(0);   
  38.     }   
  39.     memset(ret, 0, ret_len);   
  40.     f = ret;   
  41.     while (tmp < data_len)   
  42.     {   
  43.         temp = 0;   
  44.         prepare = 0;   
  45.         memset(changed, '\0', 4);   
  46.         while (temp < 3)   
  47.         {   
  48.             //printf("tmp = %d\n", tmp);   
  49.             if (tmp >= data_len)   
  50.             {   
  51.                 break;   
  52.             }   
  53.             prepare = ((prepare << 8) | (data[tmp] & 0xFF));   
  54.             tmp++;   
  55.             temp++;   
  56.         }   
  57.         prepare = (prepare<<((3-temp)*8));   
  58.         //printf("before for : temp = %d, prepare = %d\n", temp, prepare);   
  59.         for (i = 0; i < 4 ;i++ )   
  60.         {   
  61.             if (temp < i)   
  62.             {   
  63.                 changed[i] = 0x40;   
  64.             }   
  65.             else   
  66.             {   
  67.                 changed[i] = (prepare>>((3-i)*6)) & 0x3F;   
  68.             }   
  69.             *f = base[changed[i]];   
  70.             //printf("%.2X", changed[i]);   
  71.             f++;   
  72.         }   
  73.     }   
  74.     *f = '\0';   
  75.         
  76.     return ret;   
  77.         
  78. }   
  79. /* */   
  80. static char find_pos(char ch)     
  81. {   
  82.     char *ptr = (char*)strrchr(base, ch);//the last position (the only) in base[]   
  83.     return (ptr - base);   
  84. }   
  85. /* */   
  86. char *base64_decode(const char *data, int data_len)   
  87. {   
  88.     int ret_len = (data_len / 4) * 3;   
  89.     int equal_count = 0;   
  90.     char *ret = NULL;   
  91.     char *f = NULL;   
  92.     int tmp = 0;   
  93.     int temp = 0;   
  94.     char need[3];   
  95.     int prepare = 0;   
  96.     int i = 0;   
  97.     if (*(data + data_len - 1) == '=')   
  98.     {   
  99.         equal_count += 1;   
  100.     }   
  101.     if (*(data + data_len - 2) == '=')   
  102.     {   
  103.         equal_count += 1;   
  104.     }   
  105.     if (*(data + data_len - 3) == '=')   
  106.     {//seems impossible   
  107.         equal_count += 1;   
  108.     }   
  109.     switch (equal_count)   
  110.     {   
  111.     case 0:   
  112.         ret_len += 4;//3 + 1 [1 for NULL]   
  113.         break;   
  114.     case 1:   
  115.         ret_len += 4;//Ceil((6*3)/8)+1   
  116.         break;   
  117.     case 2:   
  118.         ret_len += 3;//Ceil((6*2)/8)+1   
  119.         break;   
  120.     case 3:   
  121.         ret_len += 2;//Ceil((6*1)/8)+1   
  122.         break;   
  123.     }   
  124.     ret = (char *)malloc(ret_len);   
  125.     if (ret == NULL)   
  126.     {   
  127.         printf("No enough memory.\n");   
  128.         exit(0);   
  129.     }   
  130.     memset(ret, 0, ret_len);   
  131.     f = ret;   
  132.     while (tmp < (data_len - equal_count))   
  133.     {   
  134.         temp = 0;   
  135.         prepare = 0;   
  136.         memset(need, 0, 4);   
  137.         while (temp < 4)   
  138.         {   
  139.             if (tmp >= (data_len - equal_count))   
  140.             {   
  141.                 break;   
  142.             }   
  143.             prepare = (prepare << 6) | (find_pos(data[tmp]));   
  144.             temp++;   
  145.             tmp++;   
  146.         }   
  147.         prepare = prepare << ((4-temp) * 6);   
  148.         for (i=0; i<3 ;i++ )   
  149.         {   
  150.             if (i == temp)   
  151.             {   
  152.                 break;   
  153.             }   
  154.             *f = (char)((prepare>>((2-i)*8)) & 0xFF);   
  155.             f++;   
  156.         }   
  157.     }   
  158.     *f = '\0';   
  159.     return ret;   
  160. }  
  161.   
  162. #endif  

intLib.h

[cpp] view plain copy
print?
  1. #ifndef _INT_LIB_H_  
  2. #define _INT_LIB_H_  
  3. int tolower(int c)   
  4. {   
  5.     if (c >= 'A' && c <= 'Z')   
  6.     {   
  7.         return c + 'a' - 'A';   
  8.     }   
  9.     else   
  10.     {   
  11.         return c;   
  12.     }   
  13. }   
  14.   
  15. int htoi(const char s[],int start,int len)   
  16. {   
  17.   int i,j;   
  18.     int n = 0;   
  19.     if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X  
  20.     {   
  21.         i = 2;   
  22.     }   
  23.     else   
  24.     {   
  25.         i = 0;   
  26.     }   
  27.     i+=start;  
  28.     j=0;  
  29.     for (; (s[i] >= '0' && s[i] <= '9')   
  30.        || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)   
  31.     {     
  32.         if(j>=len)  
  33.     {  
  34.       break;  
  35.     }  
  36.         if (tolower(s[i]) > '9')   
  37.         {   
  38.             n = 16 * n + (10 + tolower(s[i]) - 'a');   
  39.         }   
  40.         else   
  41.         {   
  42.             n = 16 * n + (tolower(s[i]) - '0');   
  43.         }   
  44.     j++;  
  45.     }   
  46.     return n;   
  47. }   
  48.   
  49.   
  50. #endif  

转载请注明出处http://blog.csdn.net/xxdddail/article/details/19070149






阅读全文
0 0
原创粉丝点击