网易首页 > 网易号 > 正文 申请入驻

UDS 统一诊断服务详解与 C++ 实战:基于 ISO 14229 与 ISO-TP 的车辆 ECU 诊断通信示例

0
分享至


这是一份关于UDS协议的详细讲解与C++代码示例,包含协议核心机制说明及一个完整的可编译模拟实现,帮助您直观理解诊断通信流程。

// ============================================================================
// uds_demo.cpp —— UDS (ISO 14229-1) + ISO-TP (ISO 15765-2) 教学实现
// 单文件可直接编译: g++ -std=c++17 -O2 uds_demo.cpp -o uds_demo
// ============================================================================
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

namespace uds {

using Byte = std::uint8_t;
using Bytes = std::vector ;

// ============================================================================
// 1. 协议常量
// ============================================================================
enum class Service : Byte {
DiagnosticSessionControl = 0x10,
ECUReset = 0x11,
ClearDiagnosticInfo = 0x14,
ReadDTCInformation = 0x19,
ReadDataByIdentifier = 0x22,
SecurityAccess = 0x27,
CommunicationControl = 0x28,
WriteDataByIdentifier = 0x2E,
RoutineControl = 0x31,
TesterPresent = 0x3E,
};

constexpr Byte kNegativeResponseSid = 0x7F;

enum class Nrc : Byte {
GeneralReject = 0x10,
ServiceNotSupported = 0x11,
SubFunctionNotSupported = 0x12,
IncorrectMessageLength = 0x13,
ConditionsNotCorrect = 0x22,
RequestSequenceError = 0x24,
RequestOutOfRange = 0x31,
SecurityAccessDenied = 0x33,
InvalidKey = 0x35,
ExceedNumberOfAttempts = 0x36,
RequiredTimeDelayNotExpired = 0x37,
ResponsePending = 0x78,
SubFunctionNotSupportedInSession = 0x7E,
ServiceNotSupportedInSession = 0x7F,
};

enum class Session : Byte {
Default = 0x01,
Programming = 0x02,
Extended = 0x03,
};

// 正 / 负响应构造
inline Bytes positiveResponse(Byte sid, const Bytes& data = {}) {
Bytes r;
r.reserve(1 + data.size());
r.push_back(static_cast (sid + 0x40)); // 正响应 SID = 请求 SID + 0x40
r.insert(r.end(), data.begin(), data.end());
return r;
}

inline Bytes negativeResponse(Byte sid, Nrc nrc) {
return Bytes{ kNegativeResponseSid, sid, static_cast (nrc) };
}

// 安全访问算法(⚠ 真实 OEM 为保密算法,此处仅用于演示握手流程)
inline std::uint16_t computeKey(std::uint16_t seed) {
std::uint32_t k = (static_cast(seed) << 3) ^ 0x5A5Au;
return static_cast(k & 0xFFFFu);
}

// ============================================================================
// 2. ISO 15765-2 (ISO-TP):把 UDS 报文切分 / 重组为 8 字节 CAN 帧
// ============================================================================
class IsoTp {
public:
static constexpr std::size_t CAN_DL = 8; // 经典 CAN 数据段
static constexpr std::size_t SF_MAX = CAN_DL - 1; // 单帧最多 7 字节
static constexpr std::size_t FF_MAX = CAN_DL - 2; // 首帧数据 6 字节
static constexpr std::size_t CF_MAX = CAN_DL - 1; // 连续帧数据 7 字节

// ---- 发送侧:UDS 报文 -> CAN 帧序列 ----
static std::vector segment(const Bytes& payload) {
std::vector frames;

if (payload.size() <= SF_MAX) { // 单帧 SF
Bytes f(CAN_DL, 0x00);
f[0] = static_cast (payload.size() & 0x0F);
std::copy(payload.begin(), payload.end(), f.begin() + 1);
frames.push_back(std::move(f));
return frames;
}

Bytes ff(CAN_DL, 0x00); // 首帧 FF
ff[0] = static_cast ( 0x10 | ((payload.size() >> 8) & 0x0F));
ff[1] = static_cast (payload.size() & 0xFF);
std::copy(payload.begin(), payload.begin() + FF_MAX, ff.begin() + 2);
frames.push_back(std::move(ff));

std::size_t off = FF_MAX; // 连续帧 CF
Byte sn = 1;
while (off < payload.size()) {
Bytes cf(CAN_DL, 0x00);
cf[0] = static_cast ( 0x20 | (sn & 0x0F));
const std::size_t n = std::min(CF_MAX, payload.size() - off);
std::copy(payload.begin() + off, payload.begin() + off + n, cf.begin() + 1);
frames.push_back(std::move(cf));
off += n;
sn = static_cast ((sn + 1) & 0x0F);
}
return frames;
}

// ---- 接收侧:CAN 帧 -> UDS 报文 ----
class Reassembler {
public:
// 返回 nullopt 表示尚未收全(或收到非法帧)
std::optional push(const Bytes& frame) {
if (frame.empty()) return std::nullopt;
const Byte pci = static_cast (frame[ 0] >> 4);

switch (pci) {
case 0x0: { // 单帧
const std::size_t len = frame[0] & 0x0F;
if (len == 0 || len > SF_MAX || frame.size() < len + 1)
return std::nullopt;
return Bytes(frame.begin() + 1, frame.begin() + 1 + len);
}
case 0x1: { // 首帧
if (frame.size() < 2) return std::nullopt;
total_ = ((static_cast(frame[0]) & 0x0F) << 8) | frame[1];
buffer_.assign(frame.begin() + 2, frame.end());
expectedSn_ = 1;
return tryFinish();
}
case 0x2: { // 连续帧
if (total_ == 0) return std::nullopt; // 没有首帧先到
if ((frame[0] & 0x0F) != expectedSn_) { reset(); return std::nullopt; }
expectedSn_ = static_cast ((expectedSn_ + 1) & 0x0F);
buffer_.insert(buffer_.end(), frame.begin() + 1, frame.end());
return tryFinish();
}
default:
return std::nullopt; // 流控帧 FC,本示例不处理
}
}

void reset() { buffer_.clear(); total_ = 0; expectedSn_ = 1; }

private:
std::optional tryFinish() {
if (total_ == 0 || buffer_.size() < total_) return std::nullopt;
Bytes out(buffer_.begin(), buffer_.begin() + total_);
reset();
return out;
}

Bytes buffer_;
std::size_t total_ = 0;
Byte expectedSn_ = 1;
};
};

// ============================================================================
// 3. UDS 服务端(ECU 侧)
// ============================================================================
struct Dtc {
std::uint32_t code; // 3 字节 DTC
Byte status; // 状态掩码(bit3 = confirmedDTC)
};

class UdsServer {
public:
using TxFn = std::function;

explicit UdsServer(TxFn tx) : tx_(std::move(tx)) {
// 预置数据
const char* vin = "LSVAA1234567890AB"; // 17 位 VIN
dataStore_[0xF190] = Bytes(vin, vin + 17);
dataStore_[0xF18C] = Bytes{0x01, 0x02, 0x03, 0x04}; // ECU 序列号

dtcs_.push_back({0x00A001, 0x08}); // confirmedDTC
dtcs_.push_back({0x00B002, 0x09}); // confirmed + testFailed
}

// 入口:喂入一帧 CAN 报文
void onCanFrame(const Bytes& frame) {
auto req = rx_.push(frame);
if (!req) return; // 还没收全

Bytes resp = handleRequest(*req);
if (resp.empty()) return; // 被抑制或无响应

for (const auto& f : IsoTp::segment(resp)) tx_(f);
}

private:
// ---------------- 服务分发 ----------------
Bytes handleRequest(const Bytes& req) {
if (req.empty()) return {};

const Byte sid = req[0];
Bytes resp;

switch (sid) {
case 0x10: resp = svcSessionControl(req); break;
case 0x11: resp = svcEcuReset(req); break;
case 0x14: resp = svcClearDtc(req); break;
case 0x19: resp = svcReadDtc(req); break;
case 0x22: resp = svcReadDataById(req); break;
case 0x27: resp = svcSecurityAccess(req); break;
case 0x2E: resp = svcWriteDataById(req); break;
case 0x3E: resp = svcTesterPresent(req); break;
default:
return negativeResponse(sid, Nrc::ServiceNotSupported);
}

// 统一的“抑制正响应位”处理(子功能 bit7)
if (!resp.empty() && resp[0] != kNegativeResponseSid && suppressPosRsp(req))
return {};
return resp;
}

bool suppressPosRsp(const Bytes& req) const {
if (req.size() < 2) return false;
switch (req[0]) {
case 0x10: case 0x11: case 0x19: case 0x27:
case 0x28: case 0x31: case 0x3E:
return (req[1] & 0x80u) != 0;
default:
return false;
}
}

// ---------------- 0x10 诊断会话控制 ----------------
Bytes svcSessionControl(const Bytes& req) {
if (req.size() != 2) return negativeResponse(req[0], Nrc::IncorrectMessageLength);

const Byte sub = static_cast (req[ 1] & 0x7F);
Session s;
switch (sub) {
case 0x01: s = Session::Default; break;
case 0x02: s = Session::Programming; break;
case 0x03: s = Session::Extended; break;
default: return negativeResponse(req[0], Nrc::SubFunctionNotSupported);
}

session_ = s;
securityLevel_ = 0; // 切会话必须重新做安全访问
seed_ = 0;
restartS3Timer();

// P2 = 50 ms (0x0032),P2* = 5000 ms = 500 × 10 ms (0x01F4)
return positiveResponse(req[0], { sub, 0x00, 0x32, 0x01, 0xF4 });
}

// ---------------- 0x11 ECU 复位 ----------------
Bytes svcEcuReset(const Bytes& req) {
if (req.size() != 2) return negativeResponse(req[0], Nrc::IncorrectMessageLength);
const Byte sub = static_cast (req[ 1] & 0x7F);
if (sub < 0x01 || sub > 0x03)
return negativeResponse(req[0], Nrc::SubFunctionNotSupported);

session_ = Session::Default; // 复位后回到默认会话
securityLevel_ = 0;
return positiveResponse(req[0], { sub }); // 真实 ECU 随后会重启
}

// ---------------- 0x14 清除诊断信息 ----------------
Bytes svcClearDtc(const Bytes& req) {
if (req.size() != 4) return negativeResponse(req[0], Nrc::IncorrectMessageLength);

const std::uint32_t group =
(static_cast(req[1]) << 16) |
(static_cast(req[2]) << 8) |
static_cast(req[3]);

if (group == 0xFFFFFFu) {
dtcs_.clear();
} else {
dtcs_.erase(std::remove_if(dtcs_.begin(), dtcs_.end(),
[group](const Dtc& d) { return d.code == group; }),
dtcs_.end());
}
return positiveResponse(req[0]);
}

// ---------------- 0x19 读取 DTC 信息(子功能 0x02) ----------------
Bytes svcReadDtc(const Bytes& req) {
if (req.size() != 3) return negativeResponse(req[0], Nrc::IncorrectMessageLength);

const Byte sub = static_cast (req[ 1] & 0x7F);
const Byte mask = req[2];
if (sub != 0x02) return negativeResponse(req[0], Nrc::SubFunctionNotSupported);

Bytes data;
data.push_back(sub);
data.push_back(0xFF); // DTCStatusAvailabilityMask
for (const auto& d : dtcs_) {
if ((d.status & mask) == 0) continue;
data.push_back(static_cast ((d.code >> 16) & 0xFF));
data.push_back(static_cast ((d.code >> 8) & 0xFF));
data.push_back(static_cast ( d.code & 0xFF));
data.push_back(d.status);
}
return positiveResponse(req[0], data);
}

// ---------------- 0x22 按标识符读数据 ----------------
Bytes svcReadDataById(const Bytes& req) {
if (req.size() < 3 || ((req.size() - 1) % 2) != 0)
return negativeResponse(req[0], Nrc::IncorrectMessageLength);

Bytes data;
for (std::size_t i = 1; i + 1 < req.size(); i += 2) {
const std::uint16_t did =
static_cast((req[i] << 8) | req[i + 1]);

auto it = dataStore_.find(did);
if (it == dataStore_.end())
return negativeResponse(req[0], Nrc::RequestOutOfRange);

data.push_back(req[i]);
data.push_back(req[i + 1]);
data.insert(data.end(), it->second.begin(), it->second.end());
}
return positiveResponse(req[0], data);
}

// ---------------- 0x2E 按标识符写数据 ----------------
Bytes svcWriteDataById(const Bytes& req) {
if (req.size() < 4)
return negativeResponse(req[0], Nrc::IncorrectMessageLength);

if (securityLevel_ == 0) // 未解锁 -> 拒绝
return negativeResponse(req[0], Nrc::SecurityAccessDenied);

const std::uint16_t did =
static_cast((req[1] << 8) | req[2]);

dataStore_[did] = Bytes(req.begin() + 3, req.end());
return positiveResponse(req[0], { req[1], req[2] });
}

// ---------------- 0x27 安全访问(Seed / Key) ----------------
Bytes svcSecurityAccess(const Bytes& req) {
if (req.size() < 2) return negativeResponse(req[0], Nrc::IncorrectMessageLength);

const Byte sub = static_cast (req[ 1] & 0x7F);
const bool isSeedReq = (sub % 2 == 1); // 奇数 = 请求种子

if (session_ == Session::Default) // 默认会话不允许安全访问
return negativeResponse(req[0], Nrc::ServiceNotSupportedInSession);

// ---- 请求种子 ----
if (isSeedReq) {
if (req.size() != 2)
return negativeResponse(req[0], Nrc::IncorrectMessageLength);

seed_ = nextSeed();
expectedKey_ = computeKey(seed_);

return positiveResponse(req[0], {
sub,
static_cast (seed_ >> 8),
static_cast (seed_ & 0xFF)
});
}

// ---- 发送密钥 ----
if (req.size() != 4)
return negativeResponse(req[0], Nrc::IncorrectMessageLength);
if (seed_ == 0) // 没先要种子
return negativeResponse(req[0], Nrc::RequestSequenceError);

const std::uint16_t key =
static_cast((req[2] << 8) | req[3]);

if (key != expectedKey_) {
seed_ = 0; // 密钥错必须重新取种子
if (++failedAttempts_ >= 3)
return negativeResponse(req[0], Nrc::ExceedNumberOfAttempts);
return negativeResponse(req[0], Nrc::InvalidKey);
}

seed_ = 0;
failedAttempts_ = 0;
securityLevel_ = static_cast ((sub + 1) / 2); // 0x02 -> level 1
return positiveResponse(req[0], { sub });
}

// ---------------- 0x3E Tester Present ----------------
Bytes svcTesterPresent(const Bytes& req) {
if (req.size() != 2)
return negativeResponse(req[0], Nrc::IncorrectMessageLength);
restartS3Timer(); // 保活,防止 S3 超时回落
return positiveResponse(req[0], { static_cast (req[ 1] & 0x7F) });
}

// ---------------- 工具函数 ----------------
void restartS3Timer() { s3Tick_ = 0; } // 真实实现为 5s 定时器

static std::uint16_t nextSeed() {
// 教学用确定性伪随机;真实 ECU 必须使用硬件随机数
static std::uint32_t s = 0xDEADBEEFu;
s = s * 1103515245u + 12345u;
return static_cast((s >> 16) & 0xFFFFu);
}

TxFn tx_;
IsoTp::Reassembler rx_;

Session session_ = Session::Default;
Byte securityLevel_ = 0;
std::uint16_t seed_ = 0;
std::uint16_t expectedKey_ = 0;
int failedAttempts_= 0;
int s3Tick_ = 0;

std::map dataStore_;
std::vector dtcs_;
};

// ============================================================================
// 4. 虚拟 CAN 总线 + 测试仪(客户端)演示
// ============================================================================
struct Bus {
std::function toEcu;
std::function toTester;
void testerSend(const Bytes& f) const { if (toEcu) toEcu(f); }
void ecuSend (const Bytes& f) const { if (toTester) toTester(f); }
};

} // namespace uds

// ============================================================================
// main
// ============================================================================
int main() {
using namespace uds;

// ---------- 搭一条虚拟 CAN 总线 ----------
Bus bus;
UdsServer ecu([&bus](const Bytes& f) { bus.ecuSend(f); });

IsoTp::Reassembler testerRx;
std::vector rxQueue;

bus.toEcu = [&ecu](const Bytes& f) { ecu.onCanFrame(f); };
bus.toTester = [&testerRx, &rxQueue](const Bytes& f) {
if (auto msg = testerRx.push(f)) rxQueue.push_back(std::move(*msg));
};

// ---------- 工具 ----------
auto hex = [](const Bytes& b) {
std::ostringstream os;
for (std::size_t i = 0; i < b.size(); ++i) {
if (i) os << ' ';
os << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
<< static_cast(b[i]);
}
return os.str();
};

auto transact = [&](const Bytes& req) -> Bytes {
rxQueue.clear();
testerRx.reset();
for (const auto& f : IsoTp::segment(req)) bus.testerSend(f); // ISO-TP 切分发送
return rxQueue.empty() ? Bytes{} : rxQueue.back();
};

auto step = [&](const std::string& title, const Bytes& req) -> Bytes {
Bytes rsp = transact(req);
std::cout << " " << title << "\n"
<< " TX: " << hex(req) << "\n"
<< " RX: " << (rsp.empty() ? std::string("(无响应/被抑制)") : hex(rsp))
<< "\n";
return rsp;
};

std::cout << "=============== UDS 诊断交互演示 ===============\n\n";

// ---------------------------------------------------------------- [1]
std::cout << "[1] 会话控制与保活\n";
step("TesterPresent (3E 00)", {0x3E, 0x00});
step("进入扩展会话 (10 03)", {0x10, 0x03});
step("进入编程会话 (10 02)", {0x10, 0x02});
step("回到默认会话 (10 01)", {0x10, 0x01});

// ---------------------------------------------------------------- [2]
std::cout << "\n[2] 读数据(默认会话即可,注意多帧响应)\n";
step("读 VIN (22 F1 90)", {0x22, 0xF1, 0x90});
step("读 ECU SN (22 F1 8C)", {0x22, 0xF1, 0x8C});
step("读不存在的 DID", {0x22, 0x12, 0x34});

// ---------------------------------------------------------------- [3]
std::cout << "\n[3] 写数据被安全访问拦截\n";
step("默认会话写 VIN", {0x2E, 0xF1, 0x90, 0x41});

// ---------------------------------------------------------------- [4]
std::cout << "\n[4] 安全访问 0x27 Seed/Key 握手\n";
step("默认会话请求种子(应拒绝)", {0x27, 0x01});
step("进入扩展会话 (10 03)", {0x10, 0x03});

Bytes rsp = step("请求种子 (27 01)", {0x27, 0x01});
std::uint16_t seed = 0;
if (rsp.size() >= 4 && rsp[0] == 0x67)
seed = static_cast((rsp[2] << 8) | rsp[3]);
std::cout << " → 解析出种子 = 0x" << std::hex << std::uppercase << seed
<< std::dec << "\n";

step("故意发送错误密钥", {0x27, 0x02, 0x00, 0x00});

rsp = step("重新请求种子", {0x27, 0x01});
seed = static_cast((rsp[2] << 8) | rsp[3]);
const std::uint16_t key = computeKey(seed);
std::cout << " → 本地算出密钥 = 0x" << std::hex << std::uppercase << key
<< std::dec << "\n";
step("发送正确密钥", {0x27, 0x02,
static_cast (key >> 8),
static_cast (key & 0xFF)});

// ---------------------------------------------------------------- [5]
std::cout << "\n[5] 写入数据(20 字节请求,走 ISO-TP 多帧)\n";
const std::string newVin = "LSVAA0000000000123";
Bytes writeReq{0x2E, 0xF1, 0x90};
writeReq.insert(writeReq.end(), newVin.begin(), newVin.end());
step("写入 VIN (2E F1 90 ...)", writeReq);

rsp = step("读回 VIN 验证", {0x22, 0xF1, 0x90});
if (rsp.size() > 3) {
std::string vin(rsp.begin() + 3, rsp.end());
std::cout << " → VIN = " << vin << "\n";
}

// ---------------------------------------------------------------- [6]
std::cout << "\n[6] 故障码 DTC\n";
step("读取全部 DTC (19 02 FF)", {0x19, 0x02, 0xFF});
step("只读 testFailed 的 DTC", {0x19, 0x02, 0x01});
step("清除全部 DTC (14 FFFFFF)",{0x14, 0xFF, 0xFF, 0xFF});
step("再次读取 DTC", {0x19, 0x02, 0xFF});

// ---------------------------------------------------------------- [7]
std::cout << "\n[7] 异常与边界路径\n";
step("未实现的服务 0x28", {0x28, 0x00, 0x03});
step("长度非法的 0x22", {0x22, 0xF1});
step("抑制正响应 (3E 80)", {0x3E, 0x80});

std::cout << "\n================= 演示结束 =================\n";
return 0;
}

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
下月起,日本“106 万円の壁”正式取消!在日打工人规则大变

下月起,日本“106 万円の壁”正式取消!在日打工人规则大变

东京在线
2026-09-29 00:21:26
田曦薇,绣花黑丝大肉腿

田曦薇,绣花黑丝大肉腿

东方不败然多多
2026-09-30 02:42:59
真的有人喜欢微胖吗?一个人的时候,常常会感到不自信

真的有人喜欢微胖吗?一个人的时候,常常会感到不自信

娱你同欢
2026-07-31 23:28:29
普京再签扩军令俄军增至244万人,今年以来已第4次扩军

普京再签扩军令俄军增至244万人,今年以来已第4次扩军

澎湃新闻
2026-09-29 01:54:46
菲防长祸从口出,现在后悔为时已晚,中国军舰直接堵死菲律宾门口

菲防长祸从口出,现在后悔为时已晚,中国军舰直接堵死菲律宾门口

起喜电影
2026-09-30 08:36:24
英语书中“抱吉他女孩”爆火,本人发声:三年前学校安排拍摄,不存在找关系花钱上书,也没有稿费酬劳

英语书中“抱吉他女孩”爆火,本人发声:三年前学校安排拍摄,不存在找关系花钱上书,也没有稿费酬劳

都市快报橙柿互动
2026-09-27 21:38:03
刘欢:住德式别墅,不请保姆,自己做饭,专为岳父改良红烧肉做法

刘欢:住德式别墅,不请保姆,自己做饭,专为岳父改良红烧肉做法

王糬自驾
2026-09-28 22:08:42
双色球26113期:一等奖10注分落8地 二等奖井喷165注 奖金13.9万

双色球26113期:一等奖10注分落8地 二等奖井喷165注 奖金13.9万

有态度的网友624
2026-09-30 07:32:05
河南郑州一对父子常年在工地干活,每天不吃饭不喝水只喝啤酒,一天能喝十几瓶,均查出股骨头坏死

河南郑州一对父子常年在工地干活,每天不吃饭不喝水只喝啤酒,一天能喝十几瓶,均查出股骨头坏死

台州交通广播
2026-09-29 20:30:40
曾获封全球最美脸蛋,“韩国阿娇”整容翻车,网友:那么美干嘛瞎折腾?!

曾获封全球最美脸蛋,“韩国阿娇”整容翻车,网友:那么美干嘛瞎折腾?!

英国那些事儿
2026-09-30 00:57:06
全世界都被普京骗了?打乌克兰只是幌子,真正目标其实已悄悄布局四年

全世界都被普京骗了?打乌克兰只是幌子,真正目标其实已悄悄布局四年

扶苏聊历史
2026-08-27 16:15:02
WTT中国大满贯10月1日揭幕:国乒主力轮空休整,小将冲击正赛席位

WTT中国大满贯10月1日揭幕:国乒主力轮空休整,小将冲击正赛席位

林子说事
2026-09-30 03:22:15
斩获生涯第54冠,安洗莹超越王莲香独居羽毛球女单历史第一

斩获生涯第54冠,安洗莹超越王莲香独居羽毛球女单历史第一

懂球帝
2026-09-29 16:06:06
原来很多父母从来不教生活常识!网友:什么都是自己慢慢摸索!

原来很多父母从来不教生活常识!网友:什么都是自己慢慢摸索!

另子维爱读史
2026-09-29 21:06:47
上千辆导弹发射车频繁机动,数百个弹道导弹发射井全部启封,谁敢动?

上千辆导弹发射车频繁机动,数百个弹道导弹发射井全部启封,谁敢动?

聚峰军评
2026-09-29 11:40:09
张继科:我和马龙樊振东是男乒最强3人!复出打奥运会?打一两场还行

张继科:我和马龙樊振东是男乒最强3人!复出打奥运会?打一两场还行

念洲
2026-09-29 12:14:09
千万陪嫁轰动全网!泗洪姑娘出嫁,爸妈588万,三哥哥每人出 100万

千万陪嫁轰动全网!泗洪姑娘出嫁,爸妈588万,三哥哥每人出 100万

小鹿姐姐情感说
2026-09-30 06:34:45
再见!勇士,又被交易了!巴特勒乐疯了……

再见!勇士,又被交易了!巴特勒乐疯了……

体育新角度
2026-09-28 10:51:50
英超官方:认定曼城严重违反英超联赛财务规则的指控均成立

英超官方:认定曼城严重违反英超联赛财务规则的指控均成立

懂球帝
2026-09-30 00:11:08
白衫黑裤,都市街头的熟女氛围感穿搭

白衫黑裤,都市街头的熟女氛围感穿搭

只要高兴就好
2026-09-30 08:19:07
2026-09-30 10:43:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1016文章数 348关注度
往期回顾 全部

科技要闻

OpenAI凌晨大上新!新助手dots迎战Muse

头条要闻

媒体:菲方新海图包含南海多岛 可否把日本列岛也划入

头条要闻

媒体:菲方新海图包含南海多岛 可否把日本列岛也划入

体育要闻

石雨豪:亚运金牌与背后的十年

娱乐要闻

金鹰这夜,演员争辉,有惊喜,反差

财经要闻

中央财政首次贴息房贷 定向支持首套刚需

汽车要闻

5.1米大车跑云南盘山路,海狮08试驾体验超预期

态度原创

数码
教育
旅游
家居
亲子

数码要闻

手机能玩的,大屏也能玩:华为智慧屏MateTV 2重新定义电视可玩性

教育要闻

已知∠BEC为60度,求三角形BCE的面积是多少?

旅游要闻

人海·微光丨不只面朝黄土 更能仰望星空

家居要闻

2026建博会(广州) 公装联探展交流活动

亲子要闻

超长长长长蛋挞店的规则~老板也太有爱心啦!

无障碍浏览 进入关怀版