简介:一套基于OpenBTS 2.8的GSMS应急通讯系统代码包,面向需自建临时移动通信网络的开发者、应急通信团队及网络技术爱好者,适用于灾害救援、偏远地区信号覆盖和大型活动通信保障等场景。压缩包共2029个文件,大小仅4.45MB,其中包含1531个PHP脚本,另有JS/CSS、HTML前端文件、C源码、日志及多种配置数据文件,可支撑Web管理端、业务逻辑、接口交互与底层调试,目录结构便于按需定位和修改。已有858人学习/浏览,具备较好的参考价值。代码中整合了PHP Web应用、OpenBTS配置脚本、数据库文件和xxtea加密工具,有助于理解OpenBTS 2.8的信道管理、协议栈互操作以及与Web系统的对接流程;结合USRP硬件后可部署一套可用的应急GSM网络,整体结构清晰,是学习软件定义基站与应急通信系统的实用素材。 搞应急通讯这件事,我前前后后折腾了大半年,最后沉淀下来的就是这套基于OpenBTS 2.8的GSMS代码。说白了,它是给OpenBTS套了一层“应急指挥外壳”,让一台普通电脑加一个软件无线电外设,能在几分钟内变成一个能用的GSM基站,让周围的存量手机互相打电话、发短信,完全不依赖公网。做这个方向的同行应该都懂,真正要解决的是“公网断了怎么和外界通信”的问题,而不是去造一台新手机。这篇文章我尽量把项目里最有价值的东西拆开讲,从为什么选OpenBTS 2.8、整条链路怎么搭,到参数怎么配、现场踩过哪些坑,都给记录一遍,希望对做应急通信、实验基站或者想研究GSM协议栈的朋友有实际帮助。
1. 应急通讯项目为什么锚定OpenBTS 2.8
1.1 应急通讯到底要解决什么
应急通讯场景里,最麻烦的不是设备不够先进,而是“怎么让现场的人手上的设备立刻能用”。自然灾害、基础设施故障、偏远地区作业,最常见的共同点是:公众移动网络中断,但现场人员手边几乎全是普通手机。带卫星电话成本高、数量少,对讲机又只能和同频段对讲机互通,调度指挥效率很低。
所以一个很自然的思路是:在本地快速搭建一个“微型移动网络”,让普通手机像平时一样搜网、注册、拨号。这个场景下GSM反而是最合适的技术。原因很直接:手机存量最大、GSM信号覆盖技术成熟、协议栈规模比LTE/5G小得多。LTE不是不能做,但要做核心网(MME、SGW、PGW)加基站,整套配置和资源占用远超应急场景能接受的范围。GSM加上OpenBTS这套开源实现,一台x86小主机加一个USRP设备就能跑起来,这是应急通讯真正常见的“最小可用系统”。
1.2 OpenBTS 2.8是“最小可用”的甜点位
OpenBTS版本迭代到现在已经有不少分支了。很多人问为什么我不直接上OpenBTS 5.0或者新架构。我的回答很直接:应急场景求稳求快,OpenBTS 2.8反而是最合适的甜点位。
原因有三个。第一,2.8的内部架构把GSM的L2/L3层、鉴权数据库、SIP语音交换拆得比较清晰:transceiver负责物理层收发,OpenBTS核心进程负责GSM协议栈和业务控制,sipauthserve管用户鉴权,语音交给YATE做SIP交换。链路简单,出问题好排查。第二,2.8用YATE作为呼叫控制核心,天然支持SIP协议,这就意味着它可以非常方便地和VoIP网关、PBX甚至另一套远端OpenBTS对接,做多节点互联很方便。第三,网上关于2.8的资料存量足够多,遇到问题你能搜到别人的解法,这点在应急开发里非常宝贵。新版本架构更重,依赖更多,出了问题查起来费劲,不适合做紧急部署的底座。
2. 系统组成与GSMS代码结构
2.1 软硬件链路怎么搭
整套系统硬件其实很简单,核心就三个部分:一台能跑Linux的主机(我用过Intel NUC和树莓派4,性能都够用)、一个USRP B200或者B210软件无线电外设、一根对应频段的天线。选B200/B210而不是老款USRP1,主要是宽频、无需外置子板,USB 3.0供电和传输都方便,现场部署少带很多东西。
软件侧需要四个核心服务:transceiver(物理层)、OpenBTS核心进程(GSM L2/L3协议栈)、sipauthserve(注册和鉴权数据库)、YATE(SIP语音交换)。我的GSMS代码库本质上是把这一套服务的部署、启动、参数注入、状态检查全部脚本化,并且加上了应急场景需要的批量用户导入、短信广播、拨测报告等功能。代码目录结构大概是这样的:
bin/:封装后的start、stop、status、reset脚本。etc/:统一环境变量和OpenBTS配置模板,一次改参数,所有服务同步使用。scripts/:批量导入IMSI、批量发短信、自动拨测脚本。web/:一个可选的最简单的Python状态页,展示基站运行状态和当前注册用户数。
这样组织的好处是现场操作的人不需要懂OpenBTS内部细节,照着命令敲就行。
2.2 GSM-SIP呼叫链路的核心逻辑
理解OpenBTS,最关键的是搞清楚一条呼叫链路是怎么从手机走到SIP的。手机侧走的是标准GSM协议栈。发起呼叫时,手机在RACH信道上发Channel Request,基站侧分配SDCCH信道,然后进行CM Service Request、呼叫建立等L3信令交互。OpenBTS核心进程把这些GSM信令翻译成SIP信令,发给YATE。YATE再根据被叫号码进行路由。如果被叫也是当前基站下的手机,就直接内部接续;如果要出网,就交给外部SIP网关。
这中间最核心的工作是“号码和IMSI的映射管理”。GSM网里每个用户以IMSI识别,但手机之间打电话是以MSISDN(也就是电话号码)互相拨号的。OpenBTS里sipauthserve的数据库存的正是IMSI和MSISDN的绑定关系。我的GSMS脚本里也做了一个很实用的功能:批量导入一个CSV,里面一列IMSI一列短号,导入后现场人员直接拨短号就能互通,不需要记SIP URI。
2.3 GSMS代码库的三层设计
我给GSMS定了一个很朴素的目标:让一个对OpenBTS不熟的志愿者,也能在培训十分钟后把基站拉起来并完成拨测。所以代码库分了三层。
第一层是“裸配置层”,也就是OpenBTS原生参数,我全部放在etc/gsms.env里集中管理,不撒得到处都是。第二层是“服务管理层”,就是bin目录下的start/stop/status脚本,严格按顺序拉起服务,并在启动后做端口和进程探测。第三层是“业务脚本层”,面向应急业务使用,比如广播短信、批量开户、通话压力测试。这三层各干各的,底层OpenBTS版本即使有小变化,上层脚本也基本不用改。
3. 关键参数配置:先把网络“立起来”
3.1 无线射频参数
在一个新现场快速配置基站,最核心的无线参数就几个:频段、绝对射频信道号(ARFCN)、基站色码(BSIC)、发射功率。我通常会在gsms.env里把这些参数集中成一组。
| 参数项 | 示例值 | 说明 |
|---|---|---|
| GSM.Radio.Band | 900 | 优先选900MHz,传播损耗低,覆盖半径更大 |
| GSM.Radio.C0 | 50 | 对应上行中心频率约900MHz,必须按当地频率规划选 |
| GSM.Identity.BSIC | 12 | 基站色码,用于手机区分相邻基站 |
| GSM.Radio.TxPower | 10~20 | 单位是dBm,应急带外功放时建议从小功率开始调 |
| GSM.Radio.MCC/MNC | 901/01 | 临时应急网标识,尽量不与现实运营商冲突 |
这里有一点特别坑,就是ARFCN不能随便选。GSM900频段中,下行频率大致是上行频率加上45MHz。ARFCN=50的时候,上行中心频点就是890 + 0.2 * 50 = 900MHz,下行对应945MHz。不同国家、不同运营商的频段划分不一样,现场如果直接用默认配置,极有可能打到一个正在使用的运营商频点上。虽然做的是应急发信,也要严格遵守当地无线电管理规定,部署前一定要用扫频仪或者SDR先看一下哪些频点是空闲的,再写进配置。
3.2 开放注册与鉴权策略
常规运营商的网络要对用户做严格鉴权,但应急通讯场景下,核心诉求是“让现场的所有手机都能快速入网”。因为现场人员用的SIM卡来自不同运营商,甚至可能有人没带卡。这种情况下,我会把鉴权关掉,同时打开开放注册。
具体操作上,有两个关键参数。一个是Control.LUR.OpenRegistration,设置为true后,任意IMSI发起位置更新请求都会允许注册。另一个是GSM.Ciphering.Algorithms,设为EA0表示不加密。GSMS的subscriber脚本里,我还会预置一个“应急号码段”,比如预先写入一批短号,网络上线后这些号码直接可用。这样做是有意为之:如果要求先录白名单再开机,救援人员到场还得等配置,黄花菜都凉了。开放注册的风险在于无法做到接入控制,但应急网络的使命是救人,短暂开放换取快速接入,事后按日志审计即可。
3.3 SIP语音路由参数
语音能不能通,最终看YATE的路由配置。OpenBTS把呼叫交给YATE后,YATE需要知道“被叫号码往哪儿送”。最简单的做法是:短号互打时,YATE直接把呼叫转到OpenBTS内部注册的对端号码。如果现场有PSTN网关或者卫星VoIP链路,可以加一条前缀路由,比如拨“0”开头走外线。
我自己的配置习惯是在YATE的配置里建立两个路由段。第一段匹配纯短号,比如^[0-9]{4}$,送去OpenBTS注册用户找被叫;第二段匹配^0[0-9]+$,转发给上级SIP中继。路由测试至关重要,GSMS里有一个call_test.sh,会模拟两部终端互拨,并抓取YATE的SIP日志确认INVITE请求是否到达、200 OK是否返回。在这个环节翻过车的人都知道,百分之七八十的“电话打不通”问题都出在SIP路由配置上,而不是GSM射频上。
4. 从零部署到第一通电话
4.1 时钟校准是第一优先级
很多人第一次架OpenBTS,最容易忽略的就是时钟同步。GSM对频率误差有严格容限,B200默认使用USB时钟,漂移会随着运行时间逐渐变大。最开始我也图省事,没接GPSDO就开站,结果手机能搜到网络,信号满格,但一打电话就“扑通扑通”断断续续,延迟还特别大。后来排查半天定位到是时钟没锁。
所以我的经验是:正式部署前先做两件事。第一,确认GPSDO或者外部10MHz参考时钟已经锁定;第二,用UHD自带的工具确认设备能被系统正常识别。我的gsms-start脚本里第一步不是启动服务,而是检测时钟状态,没锁定就明确报错。现场环境嘈杂,靠人眼去看GPS锁定灯不现实,脚本能自动化判断会省很多事。
4.2 初始化数据库和启动服务
OpenBTS 2.8的注册用户数据默认存在sipauthserve对应的一组数据库文件中。GSMS里我提供了一个初始化脚本,作用是重建数据库表结构、导入应急号码段。批量开户的CSV格式非常灵活,IMSI、短号、姓名可以一次性导入。启动服务的顺序也很讲究:先transceiver、再OpenBTS核心、然后是sipauthserve、最后YATE。顺序反了会导致OpenBTS起来了但找不到鉴权服务,或者YATE还没监听端口导致注册消息发不出去。
我这里放一段GSMS里简化后的启动脚本片段,实际现场用大概就是这个思路:
# gsms-start 简化版 source /opt/gsms/etc/gsms.env uhd_find_devices || die "USRP设备未找到" check_gpsdo_locked || die "参考时钟未锁定" systemctl start openbts-transceiver systemctl start openbts-core systemctl start sipauthserve systemctl start yate sleep 5 gsms-status启动后,可以用手机做一次手动选网。手机会扫描到当前附近的GSM网络,选对应MCC/MNC的那个网络注册。注册成功后,用另一台手机拨一个短号,验证双向语音。
4.3 短信广播的实现思路
应急通讯里短信广播很常用,比如通知疏散路线、集合点、物资发放信息。GSMS里我封装了一个sms_broadcast.py脚本,逻辑很简单:读取当前已注册用户列表,然后向OpenBTS的内部消息端口逐条提交短信发送请求。要注意的是,发送频率必须限定,大量短信同时下发给GSM网络会造成寻呼拥塞,手机在空闲态收短信响应不过来,反而变成“广播不可达”。我用下来的经验是每100毫秒发一条比较稳妥,如果短信超过70个字符,还要做PDU拆分处理,否则部分手机会显示乱码。
下面是一个简单的伪代码示意:
# sms_broadcast.py 核心逻辑示意 for subscriber in registered_users: submit_sms(imsi=subscriber.imsi, content="应急通知:请前往A区集合点") sleep(0.1)短信收没收到,GSM侧可以从内部通道查回执状态。实际操作中,我更建议在基建测试阶段就发一条测试短信检查SMSC地址是否被广播出去。如果手机能注册但收不到短信,十有八九是系统消息里没配上短信中心号码。
5. 应急现场的典型故障与排查清单
跑应急基站和实验室跑通完全是两回事。实验室里你可以慢慢看日志,现场则需要在几分钟内定位问题。我把这半年多的实战问题整理成了一张排查表,遇到问题可以直接对着查。
| 故障现象 | 可能原因 | 解决办法 |
|---|---|---|
| 手机搜不到网络 | 时钟未锁定、天线没接好、发射功率过低 | 检查GPSDO锁定状态,确认天线接头,逐步提升TxPower |
| 信号满格但注册失败 | LUR开放注册未开、MCC/MNC冲突 | 确认Control.LUR.OpenRegistration为true,换空闲MCC/MNC |
| 能注册但呼叫不通 | YATE路由缺失、SIP信令没转发 | 查看YATE日志,确认被叫号码路由规则是否匹配 |
| 通话断续、杂音大 | 时钟漂移、TxPower过高导致功放饱和 | 确认时钟参考,把发射功率降到线性区 |
| 短信收不到 | SMSC地址没广播 | 正确配置短信中心号码并重启核心服务 |
| 运行几小时后全部手机掉线 | transceiver长时间时钟漂移累积 | 加外部时钟参考,配置定时巡检自动重启机制 |
这里我想特别讲一个“好不容易接通又掉线”的案例。一次外场测试中,基站运行不到两小时,所有手机都开始无法发起呼叫,重启OpenBTS后恢复,但半小时后又掉线。查了很久发现问题是transceiver的时钟源没有锁死,温度升高后晶振漂移叠加,系统失步。后来给USRP接了外部10MHz参考时钟,问题彻底消失。应急场景时间长,设备长时间运行非常普遍,这种情况必须在部署阶段就规避掉。
还有一个小提示:手机搜索网络的时候,尽量手动选网而不是自动。部分手机在自动模式下会一直尝试选择“归属网络”,而现场应急网不是任何人的归属网络,自动选网可能反复失败。手动选网一步到位,培训时一定要告诉现场操作员。
6. 一些实在的实践体会
最后再说点跑完整套系统之后的个人感受。OpenBTS 2.8这个版本虽然是老代码,但它在应急通讯场景里的价值一点不过时。GSMS这套代码的核心不是发明了什么新协议,而是把所有能提前封装的事情都封装了,让现场部署从“调参比赛”变成“执行命令”。我建议所有想复现这套系统的朋友,第一步不要急着玩花样,先老老实实把官方示例的配置在实验室跑通,然后用脚本固化你的参数,再慢慢加入自己的业务逻辑。
做应急通讯,最大的敌人不是技术难度,而是现场的不确定性。一套自动检测、快速复位、日志完整的工具链,比什么都重要。后续如果能再加上多基站之间SIP trunk互联、上级指挥中心VoIP无缝接入,这套系统会更有生命力。踩过这么多坑之后,我最深刻的体会是:应急系统永远要把“最快恢复通信”作为第一设计原则,简单可靠才是工程上的最好答案。
本文还有配套的精品资源,点击获取