中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

中国DOS联盟论坛
现在时间是 2026-10-31 05:08
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » [求助]PCTCP SDK开发客户端 查看 2,204 回复 3
楼 主 [求助]PCTCP SDK开发客户端 发表于 2010-10-06 11:49 ·  中国 广东 广州 联通
新手上路
★
积分 8
发帖 3
注册 2010-10-04 13:47
16年会员
UID 175290
性别 男
状态 离线
各位大虾,小弟最近需要在DOS上做一个网络通信的客户端。使用pctcp sdk。发现运行不了。
PC: 网卡tc-link 8139.
pctcp网卡驱动安装: rtspkt 0x60 ,ethdrv
使用pctcp带的ping,ftp程序,能够使用。
编译环境:BC4.5
程序运行 wLstnSock = socket (AF_INET, SOCK_STREAM, 0);就会死机。

这事什么情况啊。请各位大侠帮忙看看。
[已使用 Gemini 解答]
Gemini 解答

核心结论

该问题并非底层硬件或 Packet Driver 驱动故障(系统自带的 ping 和 ftp 可用已证明网络链路正常),而是由于编译配置不匹配(内存模型/调用约定)或遗漏了 PC/TCP 的前置初始化函数,导致调用 socket() 时触发空指针解引用或堆栈崩溃。


技术原因深度分析

1. 遗漏 PC/TCP SDK 的底层初始化例程

在现代操作系统中,调用 Berkeley Sockets API 通常无需手动处理底层驱动握手;但在 DOS 实模式下,PC/TCP(FTP Software 开发的商业协议栈)采用“驻留程序(TSR)+ 静态库包裹层(Wrapper)”的架构。

  • 初始化依赖:PC/TCP SDK 的 Sockets 接口并不是独立的纯用户态代码,它需要与常驻内存的内核(如 ETHDRV / INET TSR)建立会话。
  • 在调用 socket() 创建套接字之前,必须先调用 SDK 提供的专有初始化函数(如 pc_init()、pctcp_init() 或相关的套接字环境初始化例程)。
  • 如果跳过初始化直接执行 socket(),内部保存驱动中断向量表入口、共享内存段或会话控制块的指针仍为全零或未初始化野指针,一旦执行 CALL FAR 或触发软中断,CPU 将直接跳转到非法内存地址导致死机。

2. 内存模型(Memory Model)不匹配

这是 Borland C++(BC4.5)混合链接老旧 DOS 静态库时最常见的问题:

  • PC/TCP SDK 附带的 .LIB 库文件几乎都是使用 Large(大内存模型) 编译的(代码指针为 32 位 far 指针,数据指针也为 32 位 far 指针)。
  • BC4.5 的新建工程若默认为 Small 或 Medium 模型,编译器会按 16 位近指针(near)生成函数调用指令和参数入栈逻辑。调用库函数时,栈帧内的返回地址与参数偏移全部错位,进入库函数或返回调用方时必定导致栈崩溃。

3. 函数调用约定与字节对齐差异

  • 调用约定:PC/TCP SDK 最早多基于 Microsoft C 6.0/7.0 或 Borland C++ 3.1 编写。部分函数原型可能显式指定了 __pascal、__cdecl 或 _far _pascal。如果头文件未正确处理导出修饰符,而 BC4.5 开启了非默认调用约定,会导致参数清理责任错误(Caller vs Callee 清栈冲突)。
  • 结构体字节对齐:BC4.5 默认的结构体对齐可能为 Word(2 字节)或 Dword(4 字节),而实模式网络驱动通常强制要求 Byte 对齐(1 字节,即 -a- 或 #pragma pack(1))。如果相关网络参数结构大小不匹配,会导致内核通信时解析错误。

4. 实模式栈空间溢出(Stack Overflow)

DOS 实模式下网络驱动的 API 嵌套较深,部分调用会涉及从用户栈切换至 Packet Driver 的内部栈。BC4.5 默认分配的堆栈通常较小(例如 2KB–4KB),在调用复杂的网络创建例程时,极易因局部变量和中断现场压栈导致实模式栈溢出,覆盖代码段或 DOS 关键数据区引起死机。


排查与解决步骤

  1. 补全初始化与退出清理 检查 PC/TCP SDK 头文件中的示例,确认调用流程中是否存在前置配置函数。标准流程通常应包含:

    • 初始化网络子系统接口(获取 TSR 入口与中断向量)。
    • 调用 socket()、bind()、connect() 等标准接口。
    • 退出前必须显式调用相应的关闭清理函数,以注销在 TSR 中申请的会话句柄。
  2. 调整 Borland C++ 4.5 编译参数

    • 确保目标平台选择为 DOS (Standard),禁止编译为 16 位 Windows 或 32 位 DPMI 目标。
    • 内存模型必须强制设置为 Large Model(编译器开关 -ml)。
    • 强制结构体以 1 字节对齐(-a1 或 -a-)。
    • 扩大工程的运行时栈空间,建议通过设置 _stklen = 0x4000;(分配 16KB 堆栈)防止栈溢出。

更好的工程替代方案:WATTCP / Watt-32

PC/TCP 是 1980–1990 年代的商业闭源协议栈,其 SDK 缺少公开维护的文档,且深度依赖特定版本的专有 TSR(如 ethdrv)。

在 DOS 环境下基于 Packet Driver(如帖中的 rtspkt.com)开发网络通信应用,业界标准且成熟的合法开源方案是 WATTCP(Waterloo TCP/IP)或其现代扩展 Watt-32:

  • 去 TSR 依赖:直接与网卡 Packet Driver(中断向量 0x60)通过标准中断规范通信,无需常驻商业协议栈内核。
  • 开发环境适配:原生支持 Borland C++ 各版本(BC3.1 / BC4.5 / BC5.02)及 DJGPP,提供完整的 BSD Sockets 兼容接口,并随附完整的文档与源码,调试难度远低于 PC/TCP SDK。
第 2 楼 发表于 2010-10-07 13:14 ·  中国 广东 广州 联通
新手上路
★
积分 8
发帖 3
注册 2010-10-04 13:47
16年会员
UID 175290
性别 男
状态 离线
顶一下,请大家帮忙看看。
第 3 楼 发表于 2010-10-08 12:33 ·  中国 广东 广州 联通
新手上路
★
积分 8
发帖 3
注册 2010-10-04 13:47
16年会员
UID 175290
性别 男
状态 离线
再顶一下
第 4 楼 发表于 2010-10-25 12:06 ·  中国 辽宁 沈阳 电信
新手上路
★
积分 12
发帖 5
注册 2010-07-23 17:05
16年会员
UID 171058
性别 男
状态 离线
帮你顶一下
论坛跳转: