一、主要目的

        自定义一些C语言网络TCP协议的读写函数,方便输入和输出基本类型。

        在内部需要调用sys/socket.h库中的recv()接收和send()发送函数。

 

      本文约定:都是按照大端序来转换取值的。

 

二、读取函数设计如下

  (一)读满数组

// sock是套接字,buff是缓冲数组

// size是目标字节数

// 返回值:读取的字节总数

int readfull(int sock, char buff[], int size){

    // MSG_WAITALL是读满才返回

    return  recv(sock, buff, size,  MSG_WAITALL);

}

 

 (二)读1个字节

// sock是套接字

// k是存放字节的变量指针

// 返回值:成功为1,失败为0

 int readByte(int sock, int* k){

    char buff[2];

 

    // 读取1个字节

    int code = readfull(sock, buff, 1);

 

    // 给指针空间赋值

    *k = buff[0] & 0xFF;

 

    // 如果个数为1,返回1,否则为0

    if(code == 1){

        return 1;

     }

     return 0;

}

 

 (三)读2个字节,转成整数

int read_2byte(int sock, short* k){

     char buff[2];

     int code = readfull(sock, buff, 2);

     // 计算取值

     short t = ((0xFF &buff[0]) << 8) | (0xFF & buff[1]);

 

    // 赋值

    *k = t;

    if(code == 2){

       return 1;

    }

    return 0;

}

 

 (四)读4个字节转成整数

int read_4byte(int sock,  int* k){

     char buff[5];

     int code = readfull(sock, buff, 4);

     // 计算取值

     int t = 0;

     t = t | ((0xFF &buff[0]) << 24);

     t = t | ((0xFF & buff[1]) << 16);

     t = t | ((0xFF & buff[2]) << 8);

     t = t | (0xFF & buff[3]);

 

     // 赋值

     *k = t;

 

    if(code == 4){

       return 1;

    }

    return 0;

}

 

 (五)读8个字节,转成整数

int read_long(int sock, long long* k){

     char buff[8];

     int code = readfull(sock, buff, 8);

 

     long long t = 0;

     t = t | ((0xFF & buff[0]) << 56);

     t = t | ((0xFF & buff[1]) << 48);

     t = t | ((0xFF & buff[2]) << 40);

     t = t | ((0xFF & buff[3]) << 32);

     t = t | ((0xFF & buff[4]) << 24);

     t = t | ((0xFF & buff[5]) << 16);

     t = t | ((0xFF & buff[6]) << 8);

     t = t | (0xFF & buff[7]);

 

     // 赋值

     *k = t;

 

   if(code == 8){

     return 1;

   }

    return 0;

}

 

  (六)读8个字节,转成浮点数

int read_double(int sock, double* k){

     char buff[8];

     int code = readfull(sock, buff, 8);

     

     long long t = 0;

     t = t | ((0xFF & buff[0]) << 56);

     t = t | ((0xFF & buff[1]) << 48);

     t = t | ((0xFF & buff[2]) << 40);

     t = t | ((0xFF & buff[3]) << 32);

     t = t | ((0xFF & buff[4]) << 24);

     t = t | ((0xFF & buff[5]) << 16);

     t = t | ((0xFF & buff[6]) << 8);

     t = t | (0xFF & buff[7]);

 

    // 强制把long long*类型转成double*类型

    double* p = (double*)&t;

 

    // 赋值

    *k = *p;

 

    if(code == 8){

       return 1;

     }

     return 0;

}

 

三、发送工具函数

 (一)发送char变量

int send_1byte(int sock, char k){

    return send(sock, &k, 1, 0);

}

 

 (二)发送short变量

int send_2byte(int sock, short k){

   char* p = (char*)&k;

   return send(sock,  p, sizeof(k), 0);

}

 

 (三)发送int整型变量

// sock是套接字, k是整型

// 返回值:成功为1,失败为0

int send_4byte(int sock, int k){

     char* p = (char*)&k;

     return send(sock,  p,  sizeof(k),  0);

}

 

// 第二种方法

int send_4byte(int sock,   int k){

     char buff[4];

     buff[0] = (0xFF000000 & k) >>> 24;

     buff[1] = (0xFF0000 & k) >>> 16;

     buff[2] = (0xFF00 & k) >>> 8;

     buff[3] = (0xFF & k);

 

     // 发送buff中的字节,个数为4

     return send(sock,  buff,  4,  0);

}

 

  (四)发送long long类型变量

// 返回值:成功为1,失败为0

int send_8byte(int sock, long long k){

     char* p = (char*)&k;

     return send(sock,  p, sizeof(k), 0);

}

 

  (五)发送double类型变量

int send_double(int sock, double k){

     char* p = (char*)&k;

     return send(sock,  p, sizeof(k), 0);

}

 

  (六)发送前缀字符串

  格式为: 2字节长度  +  字符串的字节序列

// sock是套接字

// buff存放字符串的字节序列

// size存放长度

// 返回值:发送的字节总数

int send_string(int sock, char buff[], int size){

     char temp[2];

 

     // 获得2字节长度

     temp[0] = (0xFF00 & size) >>> 8;

     temp[1] = (0xFF & size);

 

     // 发送2字节长度

     int count = send(sock, temp, 2,  0);

 

     // 发送buff中的字节序列,个数为size

     return send(sock,  buff,  size,  0) + count;

}

 

四、颠倒一次字节顺序

// buff是字节序列数组

// size是数组元素个数

// 返回值:默认为1

int reverse(char buff[], int size){

    char temp = 0;

    int k;

    for(k = 0; k < size / 2; k++){

       temp = buff[k];

       buff[k] = buff[size - k - 1];

       buff[size - k - 1] = temp;

    }

    return 1;

}

 

五、切换字节顺序

 (一)把主机序转为网络大端序

// k是被转换的变量

// 返回值:转为大端序的结果

short   little_to_big(short k){

    // 定义默认值

    short temp = 0x0001;

 

    // 转为指针char类型

    char* p = (char*)&temp;

 

    // 判断主机的字节顺序

    if(*(p+0) == 1){

        // 低位地址存放低位字节,是小端序

        // 交换一次顺序

        short h = k & 0xFF00;

        h = h >>> 8;

        h = h | ((k & 0xFF) << 8);

        return h;

    } else {

       // 低位地址存放高位字节,是大端序

       // 原样返回

       return k;   

    }

}

        如果主机本身是小端序就要转换;如果是大端序,就不要转换。

 

 (二)把网络大端序转成主机序

// k是被转换的变量

// 返回值:转为小端序的结果

short   big_to_little(short k){

    // 定义默认值

    short temp = 0x0001;

 

    // 转为指针char类型

    char* p = (char*)&temp;

 

    // 判断主机的字节顺序

    if(*(p+0) == 1){

        // 低位地址存放低位字节,是小端序

        // 交换一次顺序

        short h = k & 0xFF00;

        h = h >>> 8;

        h = h | ((k & 0xFF) << 8);

        return h;

    } else {

       // 低位地址存放高位字节,是大端序

       // 原样返回

       return k;   

    }

}

        说明:两个函数的内部代码是相同的,但是函数名不一样。

 

 

 

Logo

纵情码海钱塘涌,杭州开发者创新动! 属于杭州的开发者社区!致力于为杭州地区的开发者提供学习、合作和成长的机会;同时也为企业交流招聘提供舞台!

更多推荐