C语言实现someip的客户端

// someip_client.h
// 定义一些常量和结构体
#define SOMEIP_MSG_ID_SD 0xFFFF8100 // someip-sd的报文ID
#define SOMEIP_MSG_TYPE_REQUEST 0x00 // 请求类型
#define SOMEIP_MSG_TYPE_REQUEST_NO_RETURN 0x01 // 不期待响应的请求类型
#define SOMEIP_MSG_TYPE_NOTIFICATION 0x02 // 通知类型
#define SOMEIP_MSG_TYPE_RESPONSE 0x80 // 响应类型
#define SOMEIP_MSG_TYPE_ERROR 0x81 // 错误类型

// someip报文头结构体
struct someip_header {
  uint32_t msg_id; // 报文ID,由服务ID、方法ID、事件ID和会话ID组成
  uint32_t len; // 报文长度,不包括报文头本身
  uint8_t ver; // 版本号,默认为1
  uint8_t iface_ver; // 接口版本号,默认为1
  uint8_t msg_type; // 报文类型
  uint8_t retcode; // 返回码,仅在响应或错误类型时有效
};

// someip负载数据结构体
struct someip_payload {
  uint8_t *data; // 负载数据指针
  uint32_t len; // 负载数据长度
};

// someip报文段结构体
struct someip_packet {
  struct someip_header header; // 报文头
  struct someip_payload payload; // 负载数据
};

// someip客户端结构体
struct someip_client {
  int sock; // 套接字描述符
  struct sockaddr_in server_addr; // 服务器地址结构体
  uint8_t session_id; // 会话ID,用于区分不同的请求或响应
};

// someip_client.c
// 实现一些函数

#include "someip_client.h"

// 创建一个someip客户端,并连接到指定的服务器地址和端口
struct someip_client *create_someip_client(char *server_ip, int server_port) {
  struct someip_client *client = malloc(sizeof(struct someip_client)); // 分配内存空间
  if (client == NULL) {
    perror("malloc failed");
    return NULL;
  }
  client->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建TCP套接字
  if (client->sock < 0) {
    perror("socket failed");
    free(client);
    return NULL
    }
  client->server_addr.sin_family = AF_INET; // 设置地址族为IPv4
  client->server_addr.sin_port = htons(server_port); // 设置端口号
  client->server_addr.sin_addr.s_addr = inet_addr(server_ip); // 设置IP地址
  if (connect(client->sock, (struct sockaddr *)&client->server_addr, sizeof(client->server_addr)) < 0) { // 连接到服务器
    perror("connect failed");
    close(client->sock);
    free(client);
    return NULL;
  }
  client->session_id = 0; // 初始化会话ID为0
  return client; // 返回客户端指针
}

// 销毁一个someip客户端,关闭套接字并释放内存空间
void destroy_someip_client(struct someip_client *client) {
  if (client == NULL) {
    return;
  }
  close(client->sock); // 关闭套接字
  free(client); // 释放内存空间
}

// 构造一个someip报文段,根据参数设置报文头和负载数据
struct someip_packet *create_someip_packet(uint32_t msg_id, uint8_t msg_type, uint8_t retcode, uint8_t *data, uint32_t len) {
  struct someip_packet *packet = malloc(sizeof(struct someip_packet)); // 分配内存空间
  if (packet == NULL) {
    perror("malloc failed");
    return NULL;
  }
  packet->header.msg_id = htonl(msg_id); // 设置报文ID,并转换为网络字节序
  packet->header.len = htonl(len); // 设置报文长度,并转换为网络字节序
  packet->header.ver = 0x01; // 设置版本号为1
  packet->header.iface_ver = 0x01; // 设置接口版本号为1
  packet->header.msg_type = msg_type; // 设置报文类型
  packet->header.retcode = retcode; // 设置返回码
  packet->payload.data = data; // 设置负载数据指针
  packet->payload.len = len; // 设置负载数据长度
  return packet; // 返回报文段指针
}

// 销毁一个someip报文段,释放内存空间
void destroy_someip_packet(struct someip_packet *packet) {
  if (packet == NULL) {
    return;
  }
  free(packet); // 释放内存空间
}

// 发送一个someip报文段,通过套接字将报文头和负载数据发送出去,并更新会话ID
int send_someip_packet(struct someip_client *client, struct someip_packet *packet) {
  if (client == NULL || packet == NULL) {
    return -1;
  }
  client->session_id++; // 更新会话ID
  if (client->session_id == 0) { // 防止会话ID溢出
    client->session_id++;
  }
  packet->header.msg_id = (packet->header.msg_id & 0xFFFFFF00) | client->session_id; // 将会话ID写入报文ID的最低字节
  int n = send(client->sock, &packet->header, sizeof(packet->header), 0); // 发送报文头
  if (n < 0) {
    perror("send failed");
    return -1;
  }
  if (packet->payload.len > 0 && packet->payload.data != NULL) { // 如果有负载数据
    n = send(client->sock, packet->payload.data, packet->payload.len, 0); // 发送负载数据
    if (n < 0) {
      perror("send failed");
      return -1;
    }
  }
  return 0; // 返回成功
}

// 接收一个someip报文段,通过套接字接收报文头和负载数据,并解析出报文头和负载数据
struct someip_packet *recv_someip_packet(struct someip_client *client) {
  if (client == NULL) {
    return NULL;
  }
  struct someip_packet *packet = malloc(sizeof(struct someip_packet)); // 分配内存空间
  if (packet == NULL) {
    perror("malloc failed");
    return NULL;
  }
  int n = recv(client->sock, &packet->header, sizeof(packet->header), MSG_WAITALL); // 接收报文头
  if (n < 0) {
    perror("recv failed");
    free(packet);
    return NULL;
  }
  if (n == 0) { // 如果对方关闭了连接
    free(packet);
    return NULL;
  }
  packet->header.msg_id = ntohl(packet->header.msg_id); // 将报文ID转换为主机字节序
  packet->header.len = ntohl(packet->header.len); // 将报文长度转换为主机字节序
  if (packet->header.len > 0) { // 如果有负载数据
    packet->payload.data = malloc(packet->header.len); // 分配内存空间
    if (packet->payload.data == NULL) {
      perror("malloc failed");
      free(packet);
      return NULL;
    }
    packet->payload.len = packet->header.len; // 设置负载数据长度
    n = recv(client->sock, packet->payload.data, packet->payload.len, MSG_WAITALL); // 接收负载数据
    if (n < 0) {
      perror("recv failed");
      free(packet->payload.data);
      free(packet);
      return NULL;
    }
    if (n == 0) { // 如果对方关闭了连接
      free(packet->payload.data);
      free(packet);
      return NULL;
    }
     } else { // 如果没有负载数据
    packet->payload.data = NULL; // 设置负载数据指针为NULL
    packet->payload.len = 0; // 设置负载数据长度为0
  }
  return packet; // 返回报文段指针
}

// 处理一个someip报文段,根据报文类型进行相应的处理或反馈
int handle_someip_packet(struct someip_client *client, struct someip_packet *packet) {
  if (client == NULL || packet == NULL) {
    return -1;
  }
  switch (packet->header.msg_type) { // 根据报文类型
    case SOMEIP_MSG_TYPE_REQUEST: // 如果是请求类型
      // TODO: 根据报文ID和负载数据,执行相应的服务,并返回响应或错误类型的报文段
      break;
    case SOMEIP_MSG_TYPE_REQUEST_NO_RETURN: // 如果是不期待响应的请求类型
      // TODO: 根据报文ID和负载数据,执行相应的服务,无需返回报文段
      break;
    case SOMEIP_MSG_TYPE_NOTIFICATION: // 如果是通知类型
      // TODO: 根据报文ID和负载数据,处理相应的事件,无需返回报文段
      break;
    case SOMEIP_MSG_TYPE_RESPONSE: // 如果是响应类型
      // TODO: 根据报文ID和负载数据,验证返回码,并处理相应的结果,无需返回报文段
      break;
    case SOMEIP_MSG_TYPE_ERROR: // 如果是错误类型
      // TODO: 根据报文ID和负载数据,验证返回码,并处理相应的错误,无需返回报文段
      break;
    default: // 如果是其他类型
      fprintf(stderr, "invalid message type\n");
      return -1;
  }
  return 0; // 返回成功
}
// someip_client_test.c
// 测试someip客户端的功能

#include "someip_client.h"

int main() {
  // 创建一个someip客户端,并连接到服务器的1234端口
  struct someip_client *client = create_someip_client("127.0.0.1", 1234);
  if (client == NULL) {
    return -1;
  }
  // 构造一个请求类型的someip报文段,报文ID为0x01020304,负载数据为"hello"
  struct someip_packet *packet = create_someip_packet(0x01020304, SOMEIP_MSG_TYPE_REQUEST, 0x00, "hello", 5);
  if (packet == NULL) {
    destroy_someip_client(client);
    return -1;
  }
  // 发送该报文段
  if (send_someip_packet(client, packet) < 0) {
    destroy_someip_packet(packet);
    destroy_someip_client(client);
    return -1;
  }
  // 销毁该报文段
  destroy_someip_packet(packet);
  // 接收一个报文段
  packet = recv_someip_packet(client);
  if (packet == NULL) {
    destroy_someip_client(client);
    return -1;
  }
  // 处理该报文段
  if (handle_someip_packet(client, packet) < 0) {
    destroy_someip_packet(packet);
    destroy_someip_client(client);
    return -1;
  }
  // 销毁该报文段
  destroy_someip_packet(packet);
  // 销毁someip客户端
  destroy_someip_client(client);
  return 0;
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值