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

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


HTML5 websocket  linux/c server_C#


HTML5 websocket  linux/c server_websocket_02

下面是实现的步骤

1.建立SOCKET监听

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


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. "Port(%d) is out of range(1-%d)\n",port,0xFFFF);  
48. return;  
49.       }  
50.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
51.   
52. 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. struct sockaddr *)&servaddr, sizeof(servaddr));  
58.   
59.     listen(listenfd, 20);  
60.   
61. "Listen %d\nAccepting connections ...\n",port);  
62. sizeof(cliaddr);  
63. struct sockaddr *)&cliaddr, &cliaddr_len);  
64. "From %s at PORT %d\n",  
65. 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. "---------------------\n");  
74.       
75.       
76. if(0==connected)  
77.           {  
78. "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的版本,其他版本的可能会有所不同。下面是实现的代码。


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. 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. 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. 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. '\0',RESPONSE_HEADER_LEN_MAX);  
94.   
95. "HTTP/1.1 101 Switching Protocols\r\n");  
96. "%sUpgrade: websocket\r\n", responseHeader);  
97. "%sConnection: Upgrade\r\n", responseHeader);  
98. "%sSec-WebSocket-Accept: %s\r\n\r\n", responseHeader, serverKey);  
99.    
100. "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的协议来解就可以了。下面是实现的代码


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. long n, payloadLen=0;  
8. short usLen=0;  
9. int i=0;   
10.   
11.   
12. if (bufLen < 2)   
13.    {  
14. return NULL;  
15.    }  
16.   
17. // 1bit,1表示最后一帧    
18. if (!fin)  
19.    {  
20. return NULL;// 超过一帧暂不处理   
21.    }  
22.   
23. // 是否包含掩码    
24. if (!maskFlag)  
25.    {  
26. return NULL;// 不包含掩码的暂不处理  
27.    }  
28.   
29. // 数据长度   
30. if (payloadLen == 126)  
31.    {        
32.      memcpy(masks,buf+4, 4);        
33.      payloadLen =(buf[2]&0xFF) << 8 | (buf[3]&0xFF);    
34. 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. char *)malloc(n);   
48.      memset(payloadData,0,n);   
49. //toggle error(core dumped) if data is too long.  
50.      payloadLen=n;      
51.      }  
52. else  
53.      {     
54.       memcpy(masks,buf+2,4);      
55. 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. char)(payloadData[i] ^ masks[i % 4]);  
63.      }  
64.    
65. "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. long n;  
73.   
74.      n=strlen(message);  
75. if (n < 126)  
76.             {  
77. 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. 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. 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. "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


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. 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. "SHA1 ERROR: Could not compute message digest");  
205. return NULL;  
206. else {  
207. char *)malloc(128);  
208. sizeof(buf));  
209. "%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

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. char *)malloc(ret_len);   
33.         
34. if ( ret == NULL)   
35.     {   
36. "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. '\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. '\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. //3 + 1 [1 for NULL]   
113. break;   
114. case 1:   
115. //Ceil((6*3)/8)+1   
116. break;   
117. case 2:   
118. //Ceil((6*2)/8)+1   
119. break;   
120. case 3:   
121. //Ceil((6*1)/8)+1   
122. break;   
123.     }   
124. char *)malloc(ret_len);   
125. if (ret == NULL)   
126.     {   
127. "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. char)((prepare>>((2-i)*8)) & 0xFF);   
155.             f++;   
156.         }   
157.     }   
158. '\0';   
159. return ret;   
160. }  
161.   
162. #endif


intLib.h


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. '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. 'a');   
39.         }   
40. else   
41.         {   
42. '0');   
43.         }   
44.     j++;  
45.     }   
46. return n;   
47. }   
48.   
49.   
50. #endif  
51.