zoukankan      html  css  js  c++  java
  • Linux下用C编写WebSocet服务以响应HTML5的WebSocket请求

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

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



    下面是实现的步骤

    1.建立SOCKET监听

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

    /* server.c */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    #include "base64.h"
    #include "sha1.h"
    #include "intLib.h"
    
    
    #define REQUEST_LEN_MAX 1024
    #define DEFEULT_SERVER_PORT 8000
    #define WEB_SOCKET_KEY_LEN_MAX 256
    #define RESPONSE_HEADER_LEN_MAX 1024
    #define LINE_MAX 256
    
    
    void shakeHand(int connfd,const char *serverKey);
    char * fetchSecKey(const char * buf);
    char * computeAcceptKey(const char * buf);
    char * analyData(const char * buf,const int bufLen);
    char * packData(const char * message,unsigned long * len);
    void response(const int connfd,const char * message);
    
    int main(int argc, char *argv[])
    {
    	struct sockaddr_in servaddr, cliaddr;
    	socklen_t cliaddr_len;
    	int listenfd, connfd;
    	char buf[REQUEST_LEN_MAX];
    	char *data;
    	char str[INET_ADDRSTRLEN];
    	char *secWebSocketKey;
    	int i,n;
    	int connected=0;//0:not connect.1:connected.
    	int port= DEFEULT_SERVER_PORT;
    
    	if(argc>1)
    	  {
    	    port=atoi(argv[1]);
    	  }
    	if(port<=0||port>0xFFFF)
    	  {
    	    printf("Port(%d) is out of range(1-%d)
    ",port,0xFFFF);
    	    return;
    	  }
    	listenfd = socket(AF_INET, SOCK_STREAM, 0);
    
    	bzero(&servaddr, sizeof(servaddr));
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    	servaddr.sin_port = htons(port);
        
    	bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    
    	listen(listenfd, 20);
    
    	printf("Listen %d
    Accepting connections ...
    ",port);
    	cliaddr_len = sizeof(cliaddr);
    	connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
    	printf("From %s at PORT %d
    ",
    		       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
    		       ntohs(cliaddr.sin_port));
    
    	while (1)
    	  {
    	
    		memset(buf,0,REQUEST_LEN_MAX);
    		n = read(connfd, buf, REQUEST_LEN_MAX);	
    		printf("---------------------
    ");
    	
    	
    		if(0==connected)
    		  {
    		    printf("read:%d
    %s
    ",n,buf);
    		    secWebSocketKey=computeAcceptKey(buf);	
    		    shakeHand(connfd,secWebSocketKey);
    		    connected=1;
    		    continue;
    		  }
    
    		data=analyData(buf,n);
    		response(connfd,data);
    	}
    	close(connfd);
    }

    2.握手

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

    char * fetchSecKey(const char * buf)
    {
      char *key;
      char *keyBegin;
      char *flag="Sec-WebSocket-Key: ";
      int i=0, bufLen=0;
    
      key=(char *)malloc(WEB_SOCKET_KEY_LEN_MAX);
      memset(key,0, WEB_SOCKET_KEY_LEN_MAX);
      if(!buf)
        {
          return NULL;
        }
     
      keyBegin=strstr(buf,flag);
      if(!keyBegin)
        {
          return NULL;
        }
      keyBegin+=strlen(flag);
    
      bufLen=strlen(buf);
      for(i=0;i<bufLen;i++)
        {
          if(keyBegin[i]==0x0A||keyBegin[i]==0x0D)
    	{
    	  break;
    	}
          key[i]=keyBegin[i];
        }
      
      return key;
    }
    
    char * computeAcceptKey(const char * buf)
    {
      char * clientKey;
      char * serverKey; 
      char * sha1DataTemp;
      char * sha1Data;
      short temp;
      int i,n;
      const char * GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     
    
      if(!buf)
        {
          return NULL;
        }
      clientKey=(char *)malloc(LINE_MAX);
      memset(clientKey,0,LINE_MAX);
      clientKey=fetchSecKey(buf);
     
      if(!clientKey)
        {
          return NULL;
        }
    
     
      strcat(clientKey,GUID);
    
      sha1DataTemp=sha1_hash(clientKey);
      n=strlen(sha1DataTemp);
    
    
      sha1Data=(char *)malloc(n/2+1);
      memset(sha1Data,0,n/2+1);
     
      for(i=0;i<n;i+=2)
        {      
          sha1Data[i/2]=htoi(sha1DataTemp,i,2);    
        } 
    
      serverKey = base64_encode(sha1Data, strlen(sha1Data)); 
    
      return serverKey;
    }
    
    void shakeHand(int connfd,const char *serverKey)
    {
      char responseHeader [RESPONSE_HEADER_LEN_MAX];
    
      if(!connfd)
        {
          return;
        }
    
      if(!serverKey)
        {
          return;
        }
    
      memset(responseHeader,'',RESPONSE_HEADER_LEN_MAX);
    
      sprintf(responseHeader, "HTTP/1.1 101 Switching Protocols
    ");
      sprintf(responseHeader, "%sUpgrade: websocket
    ", responseHeader);
      sprintf(responseHeader, "%sConnection: Upgrade
    ", responseHeader);
      sprintf(responseHeader, "%sSec-WebSocket-Accept: %s
    
    ", responseHeader, serverKey);
     
      printf("Response Header:%s
    ",responseHeader);
    
      write(connfd,responseHeader,strlen(responseHeader));
    }

    注意:

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

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

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


    3.数据传输

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

    char * analyData(const char * buf,const int bufLen)
    {
      char * data;
      char fin, maskFlag,masks[4];
      char * payloadData;
      char temp[8];
      unsigned long n, payloadLen=0;
      unsigned short usLen=0;
      int i=0; 
    
    
     if (bufLen < 2) 
       {
         return NULL;
       }
    
      fin = (buf[0] & 0x80) == 0x80; // 1bit,1表示最后一帧  
      if (!fin)
       {
           return NULL;// 超过一帧暂不处理 
       }
    
       maskFlag = (buf[1] & 0x80) == 0x80; // 是否包含掩码  
       if (!maskFlag)
       {
           return NULL;// 不包含掩码的暂不处理
       }
    
       payloadLen = buf[1] & 0x7F; // 数据长度 
       if (payloadLen == 126)
       {      
         memcpy(masks,buf+4, 4);      
         payloadLen =(buf[2]&0xFF) << 8 | (buf[3]&0xFF);  
         payloadData=(char *)malloc(payloadLen);
         memset(payloadData,0,payloadLen);
         memcpy(payloadData,buf+8,payloadLen);
        }
        else if (payloadLen == 127)
        {
         memcpy(masks,buf+10,4);  
         for ( i = 0; i < 8; i++)
         {
             temp[i] = buf[9 - i];
         } 
    
         memcpy(&n,temp,8);  
         payloadData=(char *)malloc(n); 
         memset(payloadData,0,n); 
         memcpy(payloadData,buf+14,n);//toggle error(core dumped) if data is too long.
         payloadLen=n;    
         }
         else
         {   
          memcpy(masks,buf+2,4);    
          payloadData=(char *)malloc(payloadLen);
          memset(payloadData,0,payloadLen);
          memcpy(payloadData,buf+6,payloadLen); 
         }
    
         for (i = 0; i < payloadLen; i++)
         {
           payloadData[i] = (char)(payloadData[i] ^ masks[i % 4]);
         }
     
         printf("data(%d):%s
    ",payloadLen,payloadData);
         return payloadData;
    }
    
    char *  packData(const char * message,unsigned long * len)
     {
             char * data=NULL;
    	 unsigned long n;
    
    	 n=strlen(message);
                if (n < 126)
                {
    	      data=(char *)malloc(n+2);
    	      memset(data,0,n+2);	 
    	      data[0] = 0x81;
    	      data[1] = n;
    	      memcpy(data+2,message,n);
    	      *len=n+2;
                }
                else if (n < 0xFFFF)
                {
    	      data=(char *)malloc(n+4);
    	      memset(data,0,n+4);
    	      data[0] = 0x81;
    	      data[1] = 126;
    	      data[2] = (n>>8 & 0xFF);
    	      data[3] = (n & 0xFF);
    	      memcpy(data+4,message,n);    
    	      *len=n+4;
                }
                else
                {
    	 
                    // 暂不处理超长内容  
    	      *len=0;
                }
      
    
            return data;
     }
    
    void response(int connfd,const char * message)
    {
      char * data;
      unsigned long n=0;
      int i;
      if(!connfd)
        {
          return;
        }
    
      if(!data)
        {
          return;
        }
      data=packData(message,&n); 
     
      if(!data||n<=0)
        {
          printf("data is empty!
    ");
          return;
        } 
     
      write(connfd,data,n);
      
    }

    注意:

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

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

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

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

    sha1.h

    //sha1.h:对字符串进行sha1加密
    #ifndef _SHA1_H_
    #define _SHA1_H_
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    typedef struct SHA1Context{
    	unsigned Message_Digest[5];      
    	unsigned Length_Low;             
    	unsigned Length_High;            
    	unsigned char Message_Block[64]; 
    	int Message_Block_Index;         
    	int Computed;                    
    	int Corrupted;                   
    } SHA1Context;
    
    void SHA1Reset(SHA1Context *);
    int SHA1Result(SHA1Context *);
    void SHA1Input( SHA1Context *,const char *,unsigned);
    #endif
    
    
    #define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
    
    void SHA1ProcessMessageBlock(SHA1Context *);
    void SHA1PadMessage(SHA1Context *);
    
    void SHA1Reset(SHA1Context *context){// 初始化动作
    	context->Length_Low             = 0;
    	context->Length_High            = 0;
    	context->Message_Block_Index    = 0;
    
    	context->Message_Digest[0]      = 0x67452301;
    	context->Message_Digest[1]      = 0xEFCDAB89;
    	context->Message_Digest[2]      = 0x98BADCFE;
    	context->Message_Digest[3]      = 0x10325476;
    	context->Message_Digest[4]      = 0xC3D2E1F0;
    
    	context->Computed   = 0;
    	context->Corrupted  = 0;
    }
    
    
    int SHA1Result(SHA1Context *context){// 成功返回1,失败返回0
    	if (context->Corrupted) {
    		return 0;
    	}
    	if (!context->Computed) {
    		SHA1PadMessage(context);
    		context->Computed = 1;
    	}
    	return 1;
    }
    
    
    void SHA1Input(SHA1Context *context,const char *message_array,unsigned length){
    	if (!length) return;
    
    	if (context->Computed || context->Corrupted){
    		context->Corrupted = 1;
    		return;
    	}
    
    	while(length-- && !context->Corrupted){
    		context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF);
    
    		context->Length_Low += 8;
    
    		context->Length_Low &= 0xFFFFFFFF;
    		if (context->Length_Low == 0){
    			context->Length_High++;
    			context->Length_High &= 0xFFFFFFFF;
    			if (context->Length_High == 0) context->Corrupted = 1;
    		}
    
    		if (context->Message_Block_Index == 64){
    			SHA1ProcessMessageBlock(context);
    		}
    		message_array++;
    	}
    }
    
    void SHA1ProcessMessageBlock(SHA1Context *context){
    	const unsigned K[] = {0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
    	int         t;                
    	unsigned    temp;             
    	unsigned    W[80];            
    	unsigned    A, B, C, D, E;    
    
    	for(t = 0; t < 16; t++) {
    	W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
    	W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
    	W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
    	W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
    	}
    	
    	for(t = 16; t < 80; t++)  W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
    
    	A = context->Message_Digest[0];
    	B = context->Message_Digest[1];
    	C = context->Message_Digest[2];
    	D = context->Message_Digest[3];
    	E = context->Message_Digest[4];
    
    	for(t = 0; t < 20; t++) {
    		temp =  SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
    		temp &= 0xFFFFFFFF;
    		E = D;
    		D = C;
    		C = SHA1CircularShift(30,B);
    		B = A;
    		A = temp;
    	}
    	for(t = 20; t < 40; t++) {
    		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
    		temp &= 0xFFFFFFFF;
    		E = D;
    		D = C;
    		C = SHA1CircularShift(30,B);
    		B = A;
    		A = temp;
    	}
    	for(t = 40; t < 60; t++) {
    		temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
    		temp &= 0xFFFFFFFF;
    		E = D;
    		D = C;
    		C = SHA1CircularShift(30,B);
    		B = A;
    		A = temp;
    	}
    	for(t = 60; t < 80; t++) {
    		temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
    		temp &= 0xFFFFFFFF;
    		E = D;
    		D = C;
    		C = SHA1CircularShift(30,B);
    		B = A;
    		A = temp;
    	}
    	context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
    	context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
    	context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
    	context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
    	context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;
    	context->Message_Block_Index = 0;
    }
    
    void SHA1PadMessage(SHA1Context *context){
    	if (context->Message_Block_Index > 55) {
    		context->Message_Block[context->Message_Block_Index++] = 0x80;
    		while(context->Message_Block_Index < 64)  context->Message_Block[context->Message_Block_Index++] = 0;
    		SHA1ProcessMessageBlock(context);
    		while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
    	} else {
    		context->Message_Block[context->Message_Block_Index++] = 0x80;
    		while(context->Message_Block_Index < 56) context->Message_Block[context->Message_Block_Index++] = 0;
    	}
    	context->Message_Block[56] = (context->Length_High >> 24 ) & 0xFF;
    	context->Message_Block[57] = (context->Length_High >> 16 ) & 0xFF;
    	context->Message_Block[58] = (context->Length_High >> 8 ) & 0xFF;
    	context->Message_Block[59] = (context->Length_High) & 0xFF;
    	context->Message_Block[60] = (context->Length_Low >> 24 ) & 0xFF;
    	context->Message_Block[61] = (context->Length_Low >> 16 ) & 0xFF;
    	context->Message_Block[62] = (context->Length_Low >> 8 ) & 0xFF;
    	context->Message_Block[63] = (context->Length_Low) & 0xFF;
    
    	SHA1ProcessMessageBlock(context);
    }
    
    /*
    int sha1_hash(const char *source, char *lrvar){// Main
    	SHA1Context sha;
    	char buf[128];
    
    	SHA1Reset(&sha);
    	SHA1Input(&sha, source, strlen(source));
    
    	if (!SHA1Result(&sha)){
    		printf("SHA1 ERROR: Could not compute message digest");
    		return -1;
    	} else {
    		memset(buf,0,sizeof(buf));
    		sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
    		sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
    		//lr_save_string(buf, lrvar);
    		
    		return strlen(buf);
    	}
    }
    */
    
    char * sha1_hash(const char *source){// Main
    	SHA1Context sha;
    	char *buf;//[128];
    
    	SHA1Reset(&sha);
    	SHA1Input(&sha, source, strlen(source));
    
    	if (!SHA1Result(&sha)){
    		printf("SHA1 ERROR: Could not compute message digest");
    		return NULL;
    	} else {
    	  buf=(char *)malloc(128);
    		memset(buf,0,sizeof(buf));
    		sprintf(buf, "%08X%08X%08X%08X%08X", sha.Message_Digest[0],sha.Message_Digest[1],
    		sha.Message_Digest[2],sha.Message_Digest[3],sha.Message_Digest[4]);
    		//lr_save_string(buf, lrvar);
    		
    		//return strlen(buf);
    		return buf;
    	}
    }
    

    base64.h

    #ifndef _BASE64_H_
    #define _BASE64_H_
     
    #include <stdio.h> 
    #include <stdlib.h>
    #include <string.h>
    
    const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 
    char* base64_encode(const char* data, int data_len); 
    char *base64_decode(const char* data, int data_len); 
    static char find_pos(char ch); 
    
    /* */ 
    char *base64_encode(const char* data, int data_len) 
    { 
        //int data_len = strlen(data); 
        int prepare = 0; 
        int ret_len; 
        int temp = 0; 
        char *ret = NULL; 
        char *f = NULL; 
        int tmp = 0; 
        char changed[4]; 
        int i = 0; 
        ret_len = data_len / 3; 
        temp = data_len % 3; 
        if (temp > 0) 
        { 
            ret_len += 1; 
        } 
        ret_len = ret_len*4 + 1; 
        ret = (char *)malloc(ret_len); 
          
        if ( ret == NULL) 
        { 
            printf("No enough memory.
    "); 
            exit(0); 
        } 
        memset(ret, 0, ret_len); 
        f = ret; 
        while (tmp < data_len) 
        { 
            temp = 0; 
            prepare = 0; 
            memset(changed, '', 4); 
            while (temp < 3) 
            { 
                //printf("tmp = %d
    ", tmp); 
                if (tmp >= data_len) 
                { 
                    break; 
                } 
                prepare = ((prepare << 8) | (data[tmp] & 0xFF)); 
                tmp++; 
                temp++; 
            } 
            prepare = (prepare<<((3-temp)*8)); 
            //printf("before for : temp = %d, prepare = %d
    ", temp, prepare); 
            for (i = 0; i < 4 ;i++ ) 
            { 
                if (temp < i) 
                { 
                    changed[i] = 0x40; 
                } 
                else 
                { 
                    changed[i] = (prepare>>((3-i)*6)) & 0x3F; 
                } 
                *f = base[changed[i]]; 
                //printf("%.2X", changed[i]); 
                f++; 
            } 
        } 
        *f = ''; 
          
        return ret; 
          
    } 
    /* */ 
    static char find_pos(char ch)   
    { 
        char *ptr = (char*)strrchr(base, ch);//the last position (the only) in base[] 
        return (ptr - base); 
    } 
    /* */ 
    char *base64_decode(const char *data, int data_len) 
    { 
        int ret_len = (data_len / 4) * 3; 
        int equal_count = 0; 
        char *ret = NULL; 
        char *f = NULL; 
        int tmp = 0; 
        int temp = 0; 
        char need[3]; 
        int prepare = 0; 
        int i = 0; 
        if (*(data + data_len - 1) == '=') 
        { 
            equal_count += 1; 
        } 
        if (*(data + data_len - 2) == '=') 
        { 
            equal_count += 1; 
        } 
        if (*(data + data_len - 3) == '=') 
        {//seems impossible 
            equal_count += 1; 
        } 
        switch (equal_count) 
        { 
        case 0: 
            ret_len += 4;//3 + 1 [1 for NULL] 
            break; 
        case 1: 
            ret_len += 4;//Ceil((6*3)/8)+1 
            break; 
        case 2: 
            ret_len += 3;//Ceil((6*2)/8)+1 
            break; 
        case 3: 
            ret_len += 2;//Ceil((6*1)/8)+1 
            break; 
        } 
        ret = (char *)malloc(ret_len); 
        if (ret == NULL) 
        { 
            printf("No enough memory.
    "); 
            exit(0); 
        } 
        memset(ret, 0, ret_len); 
        f = ret; 
        while (tmp < (data_len - equal_count)) 
        { 
            temp = 0; 
            prepare = 0; 
            memset(need, 0, 4); 
            while (temp < 4) 
            { 
                if (tmp >= (data_len - equal_count)) 
                { 
                    break; 
                } 
                prepare = (prepare << 6) | (find_pos(data[tmp])); 
                temp++; 
                tmp++; 
            } 
            prepare = prepare << ((4-temp) * 6); 
            for (i=0; i<3 ;i++ ) 
            { 
                if (i == temp) 
                { 
                    break; 
                } 
                *f = (char)((prepare>>((2-i)*8)) & 0xFF); 
                f++; 
            } 
        } 
        *f = ''; 
        return ret; 
    }
    
    #endif
    

    intLib.h

    #ifndef _INT_LIB_H_
    #define _INT_LIB_H_
    int tolower(int c) 
    { 
        if (c >= 'A' && c <= 'Z') 
        { 
            return c + 'a' - 'A'; 
        } 
        else 
        { 
            return c; 
        } 
    } 
    
    int htoi(const char s[],int start,int len) 
    { 
      int i,j; 
        int n = 0; 
        if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X
        { 
            i = 2; 
        } 
        else 
        { 
            i = 0; 
        } 
        i+=start;
        j=0;
        for (; (s[i] >= '0' && s[i] <= '9') 
    	   || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >='A' && s[i] <= 'F');++i) 
        {   
            if(j>=len)
    	{
    	  break;
    	}
            if (tolower(s[i]) > '9') 
            { 
                n = 16 * n + (10 + tolower(s[i]) - 'a'); 
            } 
            else 
            { 
                n = 16 * n + (tolower(s[i]) - '0'); 
            } 
    	j++;
        } 
        return n; 
    } 
    
    
    #endif
    

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






  • 相关阅读:
    my first android test
    VVVVVVVVVV
    my first android test
    my first android test
    my first android test
    ini文件
    ZZZZ
    Standard Exception Classes in Python 1.5
    Python Module of the Week Python Module of the Week
    my first android test
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7605042.html
Copyright © 2011-2022 走看看