之前写了一个python版本的 现在给上一个c的版本

需求:服务端 接收客户端数据存入到本地 数据包格式 包头前4个字节是一个int 解析出来指的是后面跟随的数据的大小 (字节数)

这里我们就要解析包头 存入数据

其实这个思路很简单 就是用socket接收4个字节 解析出int 数据包的大小为x 再去接收x个字节的数据存入到本地就可以了

注意: 由于网络可能会有延迟 recv不一定能完全接收到相应大小的数据 比如 要接收2000个数据 结果只接收了1900个 所以要写个循环判断不断接收到相应字节数为止 包头的那4个字节也要写相同的判断 虽然4个字节漏的概率很小 但是考虑到安全性

下面我给出的是c代码

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>

#define MYPORT  9999
#define QUEUE   20
#define BUFFER_SIZE 1024
#define HEAD_LEN 4

//函数提前声明 不然按编译器 要看调用解析顺序去排列函数位置 这样就避免了这个问题
int read_head_value(int conn);
void read_data(int conn,int t,FILE *f);

int main()
{
    FILE *f  = fopen("test.pcm","wa");
    int packet_head = 0; //报头值
//    char* packet_head_data = (char *)malloc(HEAD_LEN*sizeof(char));

    ///定义sockfd
    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);

    ///定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(MYPORT);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    ///bind,成功返回0,出错返回-1
    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    {
        perror("bind");
        exit(1);
    }

    ///listen,成功返回0,出错返回-1
    if(listen(server_sockfd,QUEUE) == -1)
    {
        perror("listen");
        exit(1);
    }

    ///客户端套接字
  //  char buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);

    ///成功返回非负描述字,出错返回-1
    int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
    if(conn<0)
    {
        perror("connect");
        exit(1);
    }

    int t;
    // c 中没有 true 会报错 true 属于 C++
    while(1){
        t = read_head_value(conn);
        read_data(conn,t,f);
    }
    fclose(f);
    close(conn);
    close(server_sockfd);
    return 0;
}

// 用int解析报头 返回报头值 有返回值的函数不一定必须要有个参数来接收返回值 可以直接使用 比如 read_head_value(conn)直接使用是可以的
int read_head_value(int conn)
{
    char *p = (char *)malloc(HEAD_LEN * sizeof(char));
    int *q = p;
    int t;
    int len,add;
    len = recv(conn,p,HEAD_LEN,0);
    while(len < HEAD_LEN){
    add = recv(conn,p,HEAD_LEN-len,0);
    len = len + add;
    }
    printf("len is %d\n",len);
    printf("packet head len is %d\n",*q);
    t = *q;
    free(q);
    // p释放了 也就是说q和p所指向的那块内存释放了 事实如果后面return *q 返回的结果为0 其实释放p,q都是释放那段内存空间 free(p)释放4个char free(q)释放1个int 在这个机器上是等价的
    return t;
}

// 读取数据 recv 第二个参数是buffer 接收数据的字节数
void read_data(int conn,int t,FILE *f)
{
    char *p = (char *)malloc(t * sizeof(char));
    memset(p,0,t); //清空内存数据 防止数据出错
    int len,add;
    len = recv(conn,p,t,0);
    printf("first get len is %d\n",len);
    fwrite(p,sizeof(char),len,f);
    while(len < t){
    memset(p,0,t); //清空内存数据 防止数据出错
    add = recv(conn,p,t-len,0);
    fwrite(p,sizeof(char),add,f);
    printf("add is %d\n",add);
    len = len + add;
    }
    printf("packet data len is %d\n",len);

    printf("the packet data first addr %d\n",p);
    free(p);
}

c代码总感觉有时候会有奇妙的错误,望大家实时改进,指出不足。

posted on 2021-12-31 16:34  Rabbit_XIN  阅读(252)  评论(0)    收藏  举报