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

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

    \

    \

    下面是实现的步骤

    1.建立SOCKET监听

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

     

    01. /* server.c */
    02. #include <stdio.h>
    03. #include <stdlib.h>
    04. #include <string.h>
    05. #include <unistd.h>
    06. #include <sys socket.h="">
    07. #include <netinet in.h="">
    08.  
    09. #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)
    48. ",port,0xFFFF);
    49. return;
    50. }
    51. listenfd = socket(AF_INET, SOCK_STREAM, 0);
    52.  
    53. bzero(&servaddr, sizeof(servaddr));
    54. servaddr.sin_family = AF_INET;
    55. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    56. servaddr.sin_port = htons(port);
    57.  
    58. bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    59.  
    60. listen(listenfd, 20);
    61.  
    62. printf("Listen %d
    63. Accepting connections ...
    64. ",port);
    65. cliaddr_len = sizeof(cliaddr);
    66. connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
    67. printf("From %s at PORT %d
    68. ",
    69. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
    70. ntohs(cliaddr.sin_port));
    71.  
    72. while (1)
    73. {
    74.  
    75. memset(buf,0,REQUEST_LEN_MAX);
    76. n = read(connfd, buf, REQUEST_LEN_MAX);
    77. printf("---------------------
    78. ");
    79.  
    80.  
    81. if(0==connected)
    82. {
    83. printf("read:%d
    84. %s
    85. ",n,buf);
    86. secWebSocketKey=computeAcceptKey(buf); 
    87. shakeHand(connfd,secWebSocketKey);
    88. connected=1;
    89. continue;
    90. }
    91.  
    92. data=analyData(buf,n);
    93. response(connfd,data);
    94. }
    95. close(connfd);
    96. }</netinet></sys></unistd.h></string.h></stdlib.h></stdio.h>

     

    2.握手

     

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

     

    001. char * fetchSecKey(const char * buf)
    002. {
    003. char *key;
    004. char *keyBegin;
    005. char *flag="Sec-WebSocket-Key: ";
    006. int i=0, bufLen=0;
    007.  
    008. key=(char *)malloc(WEB_SOCKET_KEY_LEN_MAX);
    009. memset(key,0, WEB_SOCKET_KEY_LEN_MAX);
    010. if(!buf)
    011. {
    012. return NULL;
    013. }
    014.  
    015. keyBegin=strstr(buf,flag);
    016. if(!keyBegin)
    017. {
    018. return NULL;
    019. }
    020. keyBegin+=strlen(flag);
    021.  
    022. bufLen=strlen(buf);
    023. for(i=0;i<buflen;i++) 1.1="" 101="" char="" clientkey="(char" const="" guid="258EAFA5-E914-47DA-95CA-C5AB0DC85B11" http="" i="" int="" n="" pre="" protocols="" response=""responseheader="" return="" s="" sconnection:="" serverkey="base64_encode(sha1Data,"sha1data="(char" sha1datatemp="sha1_hash(clientKey);" short="" ssec-websocket-accept:="" supgrade:="" switching="" upgrade="" void="" websocket="">
    024.  
    025.  
    026. 注意:<p> </p><p>1.Connection后面的值与HTTP通信时的不一样了,是Upgrade,而Upgrade又对应到了websocket,这样就标识了该通信协议是websocket的方式。</p><p>2.在sha1加密后进行base64编码时,使用sha1加密后的串必须将其当成16进制的字符串,将每两个字符合成一个新的码(0-0xFF间)来进一步计算后,才可以进行base64换算(我开始时就在这里折腾了很久,后面才弄明白还要加上这一步),如果是直接就base64,那就会握手失败。</p><p>3.对于sha1和base64网上有很多,后面也附上我所使用的代码。</p><h3>3.数据传输</h3><p>握手成功后就可以进行数据传输了,只要按照WebSocket的协议来解就可以了。下面是实现的代码</p><p> </p><pre class="brush:java;">char * analyData(const char * buf,const int bufLen)
    027. {
    028. char * data;
    029. char fin, maskFlag,masks[4];
    030. char * payloadData;
    031. char temp[8];
    032. unsigned long n, payloadLen=0;
    033. unsigned short usLen=0;
    034. int i=0;
    035.  
    036.  
    037. if (bufLen < 2)
    038. {
    039. return NULL;
    040. }
    041.  
    042. fin = (buf[0] & 0x80) == 0x80// 1bit,1表示最后一帧 
    043. if (!fin)
    044. {
    045. return NULL;// 超过一帧暂不处理
    046. }
    047.  
    048. maskFlag = (buf[1] & 0x80) == 0x80// 是否包含掩码 
    049. if (!maskFlag)
    050. {
    051. return NULL;// 不包含掩码的暂不处理
    052. }
    053.  
    054. payloadLen = buf[1] & 0x7F// 数据长度
    055. if (payloadLen == 126)
    056. {     
    057. memcpy(masks,buf+44);     
    058. payloadLen =(buf[2]&0xFF) << 8 | (buf[3]&0xFF); 
    059. payloadData=(char *)malloc(payloadLen);
    060. memset(payloadData,0,payloadLen);
    061. memcpy(payloadData,buf+8,payloadLen);
    062. }
    063. else if (payloadLen == 127)
    064. {
    065. memcpy(masks,buf+10,4); 
    066. for ( i = 0; i < 8; i++)
    067. {
    068. temp[i] = buf[9 - i];
    069. }
    070.  
    071. memcpy(&n,temp,8); 
    072. payloadData=(char *)malloc(n);
    073. memset(payloadData,0,n);
    074. memcpy(payloadData,buf+14,n);//toggle error(core dumped) if data is too long.
    075. payloadLen=n;   
    076. }
    077. else
    078. {  
    079. memcpy(masks,buf+2,4);   
    080. payloadData=(char *)malloc(payloadLen);
    081. memset(payloadData,0,payloadLen);
    082. memcpy(payloadData,buf+6,payloadLen);
    083. }
    084.  
    085. for (i = 0; i < payloadLen; i++)
    086. {
    087. payloadData[i] = (char)(payloadData[i] ^ masks[i % 4]);
    088. }
    089.  
    090. printf("data(%d):%s
    091. ",payloadLen,payloadData);
    092. return payloadData;
    093. }
    094.  
    095. char *  packData(const char * message,unsigned long * len)
    096. {
    097. char * data=NULL;
    098. unsigned long n;
    099.  
    100. n=strlen(message);
    101. if (n < 126)
    102. {
    103. data=(char *)malloc(n+2);
    104. memset(data,0,n+2);   
    105. data[0] = 0x81;
    106. data[1] = n;
    107. memcpy(data+2,message,n);
    108. *len=n+2;
    109. }
    110. else if (n < 0xFFFF)
    111. {
    112. data=(char *)malloc(n+4);
    113. memset(data,0,n+4);
    114. data[0] = 0x81;
    115. data[1] = 126;
    116. data[2] = (n>>8 0xFF);
    117. data[3] = (n & 0xFF);
    118. memcpy(data+4,message,n);   
    119. *len=n+4;
    120. }
    121. else
    122. {
    123.  
    124. // 暂不处理超长内容 
    125. *len=0;
    126. }
    127.  
    128.  
    129. return data;
    130. }
    131.  
    132. void response(int connfd,const char * message)
    133. {
    134. char * data;
    135. unsigned long n=0;
    136. int i;
    137. if(!connfd)
    138. {
    139. return;
    140. }
    141.  
    142. if(!data)
    143. {
    144. return;
    145. }
    146. data=packData(message,&n);
    147.  
    148. if(!data||n<=0)
    149. {
    150. printf("data is empty!
    151. ");
    152. return;
    153. }
    154.  
    155. write(connfd,data,n);
    156.  
    157. }</pre>
    158. <br>
    159. 注意:
    160. <p> </p>
    161. <p>1.对于超过0xFFFF长度的数据在分析数据部分虽然作了处理,但是在memcpy时会报core dumped的错误,没有解决,请过路的大牛帮忙指点。在packData部分也未对这一部分作处理。</p>
    162. <p>2.在这里碰到了一个郁闷的问题,在命名函数时,将函数名写的过长了(fetchSecWebSocketAcceptkey),结果导致编译通过,但在运行时却莫名其妙的报core dumped的错误,试了很多方法才发现是这个原因,后将名字改短后就OK了。</p>
    163. <p>3.在回复数据时,只要按websocket的协议进行回应就可以了。</p>
    164. <p>附上sha1、base64和intLib的代码(sha1和base64是从网上摘来的)</p>
    165. <p>sha1.h</p>
    166. <p> </p>
    167. <pre class="brush:java;">//sha1.h:对字符串进行sha1加密
    168. #ifndef _SHA1_H_
    169. #define _SHA1_H_
    170.  
    171. #include <stdio.h>
    172. #include <stdlib.h>
    173. #include <string.h>
    174.  
    175.  
    176. typedef struct SHA1Context{
    177. unsigned Message_Digest[5];     
    178. unsigned Length_Low;            
    179. unsigned Length_High;           
    180. unsigned char Message_Block[64];
    181. int Message_Block_Index;        
    182. int Computed;                   
    183. int Corrupted;                  
    184. } SHA1Context;
    185.  
    186. void SHA1Reset(SHA1Context *);
    187. int SHA1Result(SHA1Context *);
    188. void SHA1Input( SHA1Context *,const char *,unsigned);
    189. #endif
    190.  
    191.  
    192. #define SHA1CircularShift(bits,<a href="http://www.it165.net/edu/ebg/" target="_blank"class="keylink">word</a>) ((((<a href="http://www.it165.net/edu/ebg/" target="_blank"class="keylink">word</a>) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
    193.  
    194. void SHA1ProcessMessageBlock(SHA1Context *);
    195. void SHA1PadMessage(SHA1Context *);
    196.  
    197. void SHA1Reset(SHA1Context *context){// 初始化动作
    198. context->Length_Low             = 0;
    199. context->Length_High            = 0;
    200. context->Message_Block_Index    = 0;
    201.  
    202. context->Message_Digest[0]      = 0x67452301;
    203. context->Message_Digest[1]      = 0xEFCDAB89;
    204. context->Message_Digest[2]      = 0x98BADCFE;
    205. context->Message_Digest[3]      = 0x10325476;
    206. context->Message_Digest[4]      = 0xC3D2E1F0;
    207.  
    208. context->Computed   = 0;
    209. context->Corrupted  = 0;
    210. }
    211.  
    212.  
    213. int SHA1Result(SHA1Context *context){// 成功返回1,失败返回0
    214. if (context->Corrupted) {
    215. return 0;
    216. }
    217. if (!context->Computed) {
    218. SHA1PadMessage(context);
    219. context->Computed = 1;
    220. }
    221. return 1;
    222. }
    223.  
    224.  
    225. void SHA1Input(SHA1Context *context,const char *message_array,unsigned length){
    226. if (!length) return;
    227.  
    228. if (context->Computed || context->Corrupted){
    229. context->Corrupted = 1;
    230. return;
    231. }
    232.  
    233. while(length-- && !context->Corrupted){
    234. context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);
    235.  
    236. context->Length_Low += 8;
    237.  
    238. context->Length_Low &= 0xFFFFFFFF;
    239. if (context->Length_Low == 0){
    240. context->Length_High++;
    241. context->Length_High &= 0xFFFFFFFF;
    242. if (context->Length_High == 0) context->Corrupted = 1;
    243. }
    244.  
    245. if (context->Message_Block_Index == 64){
    246. SHA1ProcessMessageBlock(context);
    247. }
    248. message_array++;
    249. }
    250. }
    251.  
    252. void SHA1ProcessMessageBlock(SHA1Context *context){
    253. const unsigned K[] = {0x5A8279990x6ED9EBA10x8F1BBCDC0xCA62C1D6 };
    254. int         t;               
    255. unsigned    temp;            
    256. unsigned    W[80];           
    257. unsigned    A, B, C, D, E;   
    258.  
    259. for(t = 0; t < 16; t++) {
    260. W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
    261. W[t] |= ((unsigned) context->Message_Block[t * 4 1]) << 16;
    262. W[t] |= ((unsigned) context->Message_Block[t * 4 2]) << 8;
    263. W[t] |= ((unsigned) context->Message_Block[t * 4 3]);
    264. }
    265.  
    266. for(t = 16; t < 80; t++)  W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
    267.  
    268. A = context->Message_Digest[0];
    269. B = context->Message_Digest[1];
    270. C = context->Message_Digest[2];
    271. D = context->Message_Digest[3];
    272. E = context->Message_Digest[4];
    273.  
    274. for(t = 0; t < 20; t++) {
    275. temp =  SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
    276. temp &= 0xFFFFFFFF;
    277. E = D;
    278. D = C;
    279. C = SHA1CircularShift(30,B);
    280. B = A;
    281. A = temp;
    282. }
    283. for(t = 20; t < 40; t++) {
    284. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
    285. temp &= 0xFFFFFFFF;
    286. E = D;
    287. D = C;
    288. C = SHA1CircularShift(30,B);
    289. B = A;
    290. A = temp;
    291. }
    292. for(t = 40; t < 60; t++) {
    293. temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
    294. temp &= 0xFFFFFFFF;
    295. E = D;
    296. D = C;
    297. C = SHA1CircularShift(30,B);
    298. B = A;
    299. A = temp;
    300. }
    301. for(t = 60; t < 80; t++) {
    302. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
    303. temp &= 0xFFFFFFFF;
    304. E = D;
    305. D = C;
    306. C = SHA1CircularShift(30,B);
    307. B = A;
    308. A = temp;
    309. }
    310. context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
    311. context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
    312. context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
    313. context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
    314. context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;
    315. context->Message_Block_Index = 0;
    316. }
    317.  
    318. void SHA1PadMessage(SHA1Context *context){
    319. if (context->Message_Block_Index > 55) {
    320. context->Message_Block[context->Message_Block_Index++] = 0x80;
    321. while(context->Message_Block_Index < 64)  context->Message_Block[context->Message_Block_Index++] = 0;
    322. SHA1ProcessMessageBlock(context);
    323. while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
    324. else {
    325. context->Message_Block[context->Message_Block_Index++] = 0x80;
    326. while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
    327. }
    328. context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;
    329. context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;
    330. context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;
    331. context->Message_Block[59] = (context->Length_High) & 0xFF;
    332. context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;
    333. context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;
    334. context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;
    335. context->Message_Block[63] = (context->Length_Low) & 0xFF;
    336.  
    337. SHA1ProcessMessageBlock(context);
    338. }
    339.  
    340. /*
    341. int sha1_hash(const char *source, char *lrvar){// Main
    342. SHA1Context sha;
    343. char buf[128];
    344.  
    345. SHA1Reset(&sha);
    346. SHA1Input(&sha, source, strlen(source));
    347.  
    348. if (!SHA1Result(&sha)){
    349. printf("SHA1 ERROR: Could not compute message digest");
    350. return -1;
    351. } else {
    352. memset(buf,0,sizeof(buf));
    353. sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
    354. sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
    355. //lr_save_string(buf, lrvar);
    356.  
    357. return strlen(buf);
    358. }
    359. }
    360. */
    361.  
    362. char * sha1_hash(const char *source){// Main
    363. SHA1Context sha;
    364. char *buf;//[128];
    365.  
    366. SHA1Reset(&sha);
    367. SHA1Input(&sha, source, strlen(source));
    368.  
    369. if (!SHA1Result(&sha)){
    370. printf("SHA1 ERROR: Could not compute message digest");
    371. return NULL;
    372. else {
    373. buf=(char *)malloc(128);
    374. memset(buf,0,sizeof(buf));
    375. sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
    376. sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
    377. //lr_save_string(buf, lrvar);
    378.  
    379. //return strlen(buf);
    380. return buf;
    381. }
    382. }
    383. </string.h></stdlib.h></stdio.h></pre>
    384. <br>
    385. base64.h
    386. <p> </p>
    387. <p> </p>
    388. <pre class="brush:java;">#ifndef _BASE64_H_
    389. #define _BASE64_H_
    390.  
    391. #include <stdio.h>
    392. #include <stdlib.h>
    393. #include <string.h>
    394.  
    395. const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    396. char* base64_encode(const char* data, int data_len);
    397. char *base64_decode(const char* data, int data_len);
    398. static char find_pos(char ch);
    399.  
    400. /* */
    401. char *base64_encode(const char* data, int data_len)
    402. {
    403. //int data_len = strlen(data);
    404. int prepare = 0;
    405. int ret_len;
    406. int temp = 0;
    407. char *ret = NULL;
    408. char *f = NULL;
    409. int tmp = 0;
    410. char changed[4];
    411. int i = 0;
    412. ret_len = data_len / 3;
    413. temp = data_len % 3;
    414. if (temp > 0)
    415. {
    416. ret_len += 1;
    417. }
    418. ret_len = ret_len*4 1;
    419. ret = (char *)malloc(ret_len);
    420.  
    421. if ( ret == NULL)
    422. {
    423. printf("No enough memory.
    424. ");
    425. exit(0);
    426. }
    427. memset(ret, 0, ret_len);
    428. f = ret;
    429. while (tmp < data_len)
    430. {
    431. temp = 0;
    432. prepare = 0;
    433. memset(changed, ''4);
    434. while (temp < 3)
    435. {
    436. //printf("tmp = %d
    437. ", tmp);
    438. if (tmp >= data_len)
    439. {
    440. break;
    441. }
    442. prepare = ((prepare << 8) | (data[tmp] & 0xFF));
    443. tmp++;
    444. temp++;
    445. }
    446. prepare = (prepare<<((3-temp)*8));
    447. //printf("before for : temp = %d, prepare = %d
    448. ", temp, prepare);
    449. for (i = 0; i < 4 ;i++ )
    450. {
    451. if (temp < i)
    452. {
    453. changed[i] = 0x40;
    454. }
    455. else
    456. {
    457. changed[i] = (prepare>>((3-i)*6)) & 0x3F;
    458. }
    459. *f = base[changed[i]];
    460. //printf("%.2X", changed[i]);
    461. f++;
    462. }
    463. }
    464. *f = '';
    465.  
    466. return ret;
    467.  
    468. }
    469. /* */
    470. static char find_pos(char ch)  
    471. {
    472. char *ptr = (char*)strrchr(base, ch);//the last position (the only) in base[]
    473. return (ptr - base);
    474. }
    475. /* */
    476. char *base64_decode(const char *data, int data_len)
    477. {
    478. int ret_len = (data_len / 4) * 3;
    479. int equal_count = 0;
    480. char *ret = NULL;
    481. char *f = NULL;
    482. int tmp = 0;
    483. int temp = 0;
    484. char need[3];
    485. int prepare = 0;
    486. int i = 0;
    487. if (*(data + data_len - 1) == '=')
    488. {
    489. equal_count += 1;
    490. }
    491. if (*(data + data_len - 2) == '=')
    492. {
    493. equal_count += 1;
    494. }
    495. if (*(data + data_len - 3) == '=')
    496. {//seems impossible
    497. equal_count += 1;
    498. }
    499. switch (equal_count)
    500. {
    501. case 0:
    502. ret_len += 4;//3 + 1 [1 for NULL]
    503. break;
    504. case 1:
    505. ret_len += 4;//Ceil((6*3)/8)+1
    506. break;
    507. case 2:
    508. ret_len += 3;//Ceil((6*2)/8)+1
    509. break;
    510. case 3:
    511. ret_len += 2;//Ceil((6*1)/8)+1
    512. break;
    513. }
    514. ret = (char *)malloc(ret_len);
    515. if (ret == NULL)
    516. {
    517. printf("No enough memory.
    518. ");
    519. exit(0);
    520. }
    521. memset(ret, 0, ret_len);
    522. f = ret;
    523. while (tmp < (data_len - equal_count))
    524. {
    525. temp = 0;
    526. prepare = 0;
    527. memset(need, 04);
    528. while (temp < 4)
    529. {
    530. if (tmp >= (data_len - equal_count))
    531. {
    532. break;
    533. }
    534. prepare = (prepare << 6) | (find_pos(data[tmp]));
    535. temp++;
    536. tmp++;
    537. }
    538. prepare = prepare << ((4-temp) * 6);
    539. for (i=0; i<3 ;i++ )
    540. {
    541. if (i == temp)
    542. {
    543. break;
    544. }
    545. *f = (char)((prepare>>((2-i)*8)) & 0xFF);
    546. f++;
    547. }
    548. }
    549. *f = '';
    550. return ret;
    551. }
    552.  
    553. #endif
    554. </string.h></stdlib.h></stdio.h></pre>
    555. <br>
    556. intLib.h
    557. <p> </p>
    558. <p> </p>
    559. <pre class="brush:java;">#ifndef _INT_LIB_H_
    560. #define _INT_LIB_H_
    561. int tolower(int c)
    562. {
    563. if (c >= 'A' && c <= 'Z')
    564. {
    565. return c + 'a' 'A';
    566. }
    567. else
    568. {
    569. return c;
    570. }
    571. }
    572.  
    573. int htoi(const char s[],int start,int len)
    574. {
    575. int i,j;
    576. int n = 0;
    577. if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X
    578. {
    579. i = 2;
    580. }
    581. else
    582. {
    583. i = 0;
    584. }
    585. i+=start;
    586. j=0;
    587. for (; (s[i] >= '0' && s[i] <= '9')
    588. || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i)
    589. {  
    590. if(j>=len)
    591. {
    592. break;
    593. }
    594. if (tolower(s[i]) > '9')
    595. {
    596. n = 16 * n + (10 + tolower(s[i]) - 'a');
    597. }
    598. else
    599. {
    600. n = 16 * n + (tolower(s[i]) - '0');
    601. }
    602. j++;
    603. }
    604. return n;
    605. }
    606.  
    607.  
    608. #endif
    609. </pre>
    610. <br>
    611. 出处http://blog.csdn.net/xxdddail/article/details/19070149
    612. <p> </p>
    613. </buflen;i++)>
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:23 天前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐