Linux下用C编写WebSocet服务以响应HTML5的WebSocket请求
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
-
在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+
4
,
4
);
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[] = {
0x5A827999
,
0x6ED9EBA1
,
0x8F1BBCDC
,
0xCA62C1D6
};
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,
0
,
4
);
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 年前
更多推荐
已为社区贡献19条内容
所有评论(0)