2. Android显示系统基础

做多屏互动,说白了就是让几块屏幕在局域网里互相"说话"。你想想看,手机投屏到电视、电脑扩展第二块显示器、会议室里多屏拼接——这些场景背后,都离不开网络通信。

我刚开始做这个项目时,觉得网络通信嘛,调个接口就行了。结果第一次联调,画面卡成PPT,声音断断续续。后来才发现,问题出在最基础的TCP/IP协议理解上。嗯,这一章我们就来把地基打牢。

2.1 TCP/IP协议栈——数据是怎么"打包"的?

先看一张整体图,帮你建立全局认知:

TCP/IP 协议栈与多屏互动数据流 应用层(HTTP / RTSP / WebSocket) 多屏互动:投屏指令、画面编码流、同步信令 传输层(TCP / UDP) TCP:可靠传输,用于控制指令、文件同步 UDP:低延迟,用于音视频画面实时传输 网络层(IP) IP地址寻址、路由选择、数据包分片与重组 网络接口层(以太网 / Wi-Fi) MAC地址、帧封装、物理信号传输 多屏互动数据封装过程 应用数据 → 加TCP/UDP头 → 加IP头 → 加帧头 → 比特流 接收端反向解包,逐层剥离,最终还原应用数据

这张图我建议你多看两眼。每次数据从你的App发出,都要经过这四层"打包"。反过来,接收端要一层层"拆包"。

2.2 传输层选型:TCP vs UDP

做多屏互动,第一个要做的决定就是:用TCP还是UDP?

我见过不少新手,上来就用TCP,觉得可靠。结果画面延迟高得离谱。也见过有人全用UDP,结果丢包丢到画面花屏。

对比维度 TCP UDP
连接方式 面向连接(三次握手) 无连接
可靠性 保证送达,自动重传 不保证送达,可能丢包
数据顺序 保证有序 不保证有序
传输延迟 较高(重传机制) 低(无重传)
适用场景 控制指令、文件同步 音视频画面、实时数据

实战经验:我在做多屏同步时,采用"双通道"策略——控制信令走TCP,画面数据走UDP。这样既保证了指令的可靠性,又保证了画面的实时性。

2.3 Socket编程基础——让设备"开口说话"

Socket,说白了就是网络通信的"门"。你要跟另一台设备通信,就得先打开这扇门。

我习惯把Socket通信比作打电话:

  • 服务端:先装好电话(bind),然后等着(listen),有人打进来就接(accept)
  • 客户端:直接拨号(connect),接通后说话(send/recv)
  • 挂断:说完就挂(close)

来看一个最简的TCP服务端代码:

// TCP服务端 - 多屏互动控制信令接收
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 1. 创建Socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    // 2. 绑定端口(我习惯用 8080 做控制端口)
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    bind(server_fd, (struct sockaddr *)&address, sizeof(address));

    // 3. 监听,最大等待队列设为3
    listen(server_fd, 3);

    printf("多屏控制服务已启动,等待设备连接...\n");

    // 4. 接受客户端连接
    client_fd = accept(server_fd, (struct sockaddr *)&address,
                       (socklen_t*)&addrlen);

    // 5. 接收数据
    read(client_fd, buffer, 1024);
    printf("收到指令: %s\n", buffer);

    // 6. 关闭连接
    close(client_fd);
    close(server_fd);
    return 0;
}

小技巧:调试时可以用 telnet 192.168.1.100 8080 模拟客户端发数据,不用每次都写客户端代码。

2.4 局域网通信原理——设备怎么"找到"彼此?

多屏互动通常都在同一个局域网里。设备之间怎么发现对方?

主要有三种方式:

  1. 手动指定IP:最简单,但不够灵活。适合固定场景。
  2. 广播/UDP组播:设备启动时发个广播包,告诉全网"我在这里"。其他设备收到后,就知道它的IP和端口了。
  3. mDNS/DNS-SD:苹果的Bonjour用的就是这个。设备注册一个名字,比如"客厅电视.local",其他设备直接通过名字访问。

我个人最推荐第二种——UDP广播发现。原因很简单:实现起来不复杂,而且兼容性好。

曾经踩过的坑:有一次我在做多屏发现功能,广播包发出去,部分设备收不到。查了半天,发现是路由器的"广播隔离"功能开了。嗯,企业级路由器默认会隔离广播域,记得关掉或者改用组播。

2.5 局域网通信的"坑"与对策

做多屏互动,局域网环境看着简单,实际坑不少。我列几个常见的:

问题 现象 对策
Wi-Fi延迟抖动 画面忽快忽慢 使用UDP + 抖动缓冲(jitter buffer)
多设备同时发送 数据碰撞、丢包 引入简单的"令牌"机制,轮流发送
设备IP变化 连接突然断开 心跳检测 + 自动重连
防火墙拦截 Socket连接失败 使用常见端口(如8080、9090)或提示用户放行

我的经验:做多屏互动,一定要在代码里加"心跳包"。每1秒发一个很小的UDP包,告诉对方"我还活着"。连续3次没收到,就判定设备离线,触发重连逻辑。这个机制救了我好几次。

2.6 本章小结

这一章我们聊了TCP/IP协议栈的四层结构,TCP和UDP怎么选,Socket编程的基本套路,以及局域网设备发现和通信的常见问题。

说白了,多屏互动的网络基础就三件事:选对协议、写好Socket、处理好局域网的特殊性。把这些搞明白了,后面写代码心里就有底了。