C语言实现doip客户端

//    C语言写一个doip客户端,您可能需要以下几个步骤
//    创建一个套接字,指定TCP或UDP协议,并设置目标服务器的IP地址和端口号。
//    使用connect函数主动向服务器发起连接请求,与服务器的accept函数实现三次握手建立连接。
//    连接成功后,使用send和recv函数发送和接收doip报文,根据doip报文的格式和类型进行相应的处理。
//    使用close函数关闭套接字,结束通信。


#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define IP "192.168.102.175" //服务器的IP地址
#define PORT 7000 //服务器的端口号
#define UDP_DISCOVERY 13400 //DoIP UDP发现端口号
#define TCP_DATA 13400 //DoIP TCP数据端口号

//定义DoIP报文结构体
struct doip_message {
    unsigned char protocol_version; //协议版本号
    unsigned char inverse_version; //协议版本号取反
    unsigned short payload_type; //有效载荷类型
    unsigned long payload_length; //有效载荷长度
    unsigned char *payload; //有效载荷数据
};

//打印错误信息并退出程序
void print_err(char *str, int line, int err_no) {
    printf("%d, %s :%s\n",line,str,strerror(err_no));
    exit(-1);
}

//创建一个UDP套接字并返回
int create_udp_socket() {
    int skfd = -1;
    skfd = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字
    if ( -1 == skfd) {
        print_err("socket failed",__LINE__,errno);
    }
    return skfd;
}

//创建一个TCP套接字并返回
int create_tcp_socket() {
    int skfd = -1;
    skfd = socket(AF_INET, SOCK_STREAM, 0); //创建TCP套接字
    if ( -1 == skfd) {
        print_err("socket failed",__LINE__,errno);
    }
    return skfd;
}

//向服务器发送UDP报文,并接收响应报文
void send_udp_message(int skfd, struct doip_message *msg) {
    int ret = -1;
    struct sockaddr_in addr; //服务器的地址结构体
    addr.sin_family = AF_INET; //设置协议族为IPv4
    addr.sin_port = htons(UDP_DISCOVERY); //设置端口号为DoIP UDP发现端口号
    addr.sin_addr.s_addr = inet_addr(IP); //设置IP地址为服务器的IP地址

    //计算DoIP报文的总长度(包括报头和有效载荷)
    int msg_len = 8 + msg->payload_length;

    //将DoIP报文结构体转换为字节数组,方便发送
    unsigned char buf[msg_len];
    buf[0] = msg->protocol_version;
    buf[1] = msg->inverse_version;
    buf[2] = (msg->payload_type >> 8) & 0xFF;
    buf[3] = msg->payload_type & 0xFF;
    buf[4] = (msg->payload_length >> 24) & 0xFF;
    buf[5] = (msg->payload_length >> 16) & 0xFF;
    buf[6] = (msg->payload_length >> 8) & 0xFF;
buf[7] = msg->payload_length & 0xFF;
    memcpy(buf + 8, msg->payload, msg->payload_length);

    //发送DoIP报文到服务器
    ret = sendto(skfd, buf, msg_len, 0, (struct sockaddr*)&addr, sizeof(addr));
    if (-1 == ret) {
        print_err("sendto failed", __LINE__, errno);
    }

    //接收服务器的响应报文
    bzero(&buf, sizeof(buf));
    ret = recvfrom(skfd, buf, sizeof(buf), 0, NULL, NULL);
    if (-1 == ret) {
        print_err("recvfrom failed", __LINE__, errno);
    }
    else if (ret > 0) {
        //将字节数组转换为DoIP报文结构体,方便处理
        struct doip_message res;
        res.protocol_version = buf[0];
        res.inverse_version = buf[1];
        res.payload_type = (buf[2] << 8) | buf[3];
        res.payload_length = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
        res.payload = buf + 8;

        //根据响应报文的类型和内容进行相应的处理
        switch (res.payload_type) {
            case 0x0001: //DoIP报头否定应答
                printf("DoIP header negative acknowledge: %02X\n", res.payload[0]);
                break;
            case 0x0002: //车辆声明及标识
                printf("Vehicle identification and announcement: %s\n", res.payload);
                break;
            case 0x0004: //路由激活响应
                printf("Routing activation response: %02X\n", res.payload[4]);
                break;
            case 0x0006: //在线检查响应
                printf("Alive check response\n");
                break;
            default:
                printf("Unknown payload type: %04X\n", res.payload_type);
                break;
        }
    }
}
//向服务器发送TCP报文,并接收响应报文
void send_tcp_message(int skfd, struct doip_message *msg) {
    int ret = -1;

    //计算DoIP报文的总长度(包括报头和有效载荷)
    int msg_len = 8 + msg->payload_length;

    //将DoIP报文结构体转换为字节数组,方便发送
    unsigned char buf[msg_len];
    buf[0] = msg->protocol_version;
    buf[1] = msg->inverse_version;
    buf[2] = (msg->payload_type >> 8) & 0xFF;
    buf[3] = msg->payload_type & 0xFF;
    buf[4] = (msg->payload_length >> 24) & 0xFF;
    buf[5] = (msg->payload_length >> 16) & 0xFF;
    buf[6] = (msg->payload_length >> 8) & 0xFF;
    buf[7] = msg->payload_length & 0xFF;
    memcpy(buf + 8, msg->payload, msg->payload_length);

    //发送DoIP报文到服务器
    ret = send(skfd, buf, msg_len, 0);
    if (-1 == ret) {
        print_err("send failed", __LINE__, errno);
    }

    //接收服务器的响应报文
    bzero(&buf, sizeof(buf));
    ret = recv(skfd, buf, sizeof(buf), 0);
    if (-1 == ret) {
        print_err("recv failed", __LINE__, errno);
    }
    else if (ret > 0) {
        //将字节数组转换为DoIP报文结构体,方便处理
        struct doip_message res;
        res.protocol_version = buf[0];
        res.inverse_version = buf[1];
        res.payload_type = (buf[2] << 8) | buf[3];
        res.payload_length = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
        res.payload = buf + 8;

        //根据响应报文的类型和内容进行相应的处理
        switch (res.payload_type) {
            case 0x8001: //诊断报文响应
                printf("Diagnostic message response: %s\n", res.payload);
                break;
            default:
                printf("Unknown payload type: %04X\n", res.payload_type);
                break;
        }
    }
}

//主函数,创建套接字,连接服务器,发送和接收报文
int main() {
    int skfd_udp = -1; //UDP套接字
    int skfd_tcp = -1; //TCP套接字
    int ret = -1;

    //创建UDP套接字
    skfd_udp = create_udp_socket();

    //创建TCP套接字
    skfd_tcp = create_tcp_socket();

    //设置服务器的地址结构体
    struct sockaddr_in addr;
    addr.sin_family = AF_INET; //设置协议族为IPv4
    addr.sin_port = htons(TCP_DATA); //设置端口号为DoIP TCP数据端口号
    addr.sin_addr.s_addr = inet_addr(IP); //设置IP地址为服务器的IP地址

    //使用connect函数主动向服务器发起连接请求,与服务器的accept函数实现三次握手建立连接
    ret = connect(skfd_tcp, (struct sockaddr*)&addr, sizeof(addr));
    if (-1 == ret) {
        print_err("connect failed", __LINE__, errno);
    }

    //构造一个车辆信息请求报文
    struct doip_message msg1;
    msg1.protocol_version = 0x02; //协议版本号为0x02
    msg1.inverse_version = 0xFD; //协议版本号取反为0xFD
    msg1.payload_type = 0x0001; //有效载荷类型为0x0001,表示车辆信息请求
    msg1.payload_length = 0x00000000; //有效载荷长度为0,表示没有有效载荷数据
    msg1.payload = NULL; //有效载荷数据为空

    //向服务器发送车辆信息请求报文,并接收响应报文
    send_udp_message(skfd_udp, &msg1);

    //构造一个路由激活请求报文
    struct doip_message msg2;
    msg2.protocol_version = 0x02; //协议版本号为0x02
    msg2.inverse_version = 0xFD; //协议版本号取反为0xFD
    msg2.payload_type = 0x0005; //有效载荷类型为0x0005,表示路由激活请求
    msg2.payload_length = 0x00000007; //有效载荷长度为7,表示有7个字节的有效载荷数据
    unsigned char payload2[7] = {0xE0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x01}; //有效载荷数据,包括源地址、目标地址和激活类型
    msg2.payload = payload2;

    //向服务器发送路由激活请求报文,并接收响应报文
    send_udp_message(skfd_udp, &msg2);

    //构造一个诊断报文请求报文
    struct doip_message msg3;
    msg3.protocol_version = 0x02; //协议版本号为0x02
    msg3.inverse_version = 0xFD; //协议版本号取反为0xFD
    msg3.payload_type = 0x8001; //有效载荷类型为0x8001,表示诊断报文请求
    msg3.payload_length = 0x00000006; //有效载荷长度为6,表示有6个字节的有效载荷数据
    unsigned char payload3[6] = {0xE0, 0x11, 0x22, 0x33, 0xAA, 0xBB}; //有效载荷数据,包括源地址、目标地址和诊断数据
    msg3.payload = payload3;

    //向服务器发送诊断报文请求报文,并接收响应报文
    send_tcp_message(skfd_tcp, &msg3);

    //关闭套接字,结束通信
    close(skfd_udp);
    close(skfd_tcp);

    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值