DM&P DSock 编程指南

DSock 首页: http://www.dmp.com.cn/tech/dsock 2002/05/20

DSock是一个基于DOS系统实模式下的TCP/IP库,它通过RSIP使用。DSock提供简单的 C语言函数;利用DSock库函数,开发人员可以快速开发基于DOS系统的Internet程序, 从而节省大量开发时间。DSock库提供了丰富的例源程序代码,对于使用M6117D CPU的 DM&P产品用户,可以免费申请使用。

DSock库可以从我们的网站下载,这是一个Window自动解压缩文件,该文件解压缩后自动 创建一个DSock目录。DSock\Demo目录中有许多实例,所有实例已经顺利编译,并均打包 到DSock\Demo\EXE目录下。

Dsock库用Turbo C 2.0编译,因此推荐开发人员用Borland C++/Turbo C++编写开发程序。 如有必要,可以从网址 http://community.borland.com/article/images/21751/tcpp101.zip (2.63 MB)下载Turbo C++1.01。

本文档适用于运用DSock库,掌握TCP/IP协议,希望快速开发产品的开发人员。

索引

工程中配置DSock库

工程中一般这样配置DSock库,打开DSock库的dsock\lib目录,找到dsock.h和dsock.lib 两个文件,将它们拷贝到应用程序目录下,在工程中配置dsock.lib库,最后在源程序中包 含dsock.h头文件即可。DSock\Demo\DSock_AP是DSock库的一个启动工程实例,理解掌 握该工程是学习运用DSock的最快方法。

DSock\Lib\PKTDRV目录下存有DSock软件包驱动程序,测试程序之前,务必安装这些驱 动程序。DSock库中的文件如下:

文件名称 描述
LIB\DSOCK.H DSock库头文件,C语言
LIB\DSOCK.LIB DSock链接库,DOS系统、大型记忆体模式
LIB\DSOCK.CFG 缺省网络配置文件
LIB\LIB.HTM DSock库参考文件
LIB\PKTDRV\NE2000.COM 8019AS软件包驱动
LIB\PKTDRV\PKTDRV.BAT 装载包驱动器的DOS批处理文件

DSock库函数浏览

系统函数

初始化和关闭DSock函数如下:

函数 描述
DSock_Open() 初始化DSock函数库
DSock_Close() 关闭DSock函数库
DSock_DoBootp() 从BOOTP/DHCP服务器获取网络设置
DSock_LoadConfigFile() 通过网络配置文件获取网络配置

设置/获取网络配置DSock函数如下:

函数 描述
DSock_GetMacAddr() 获取网卡的MAC地址
DSock_GetHostIp() 获取本机IP地址
DSock_SetHostIp() 设置本机IP地址
DSock_GetNetmask() 获取本机TCP/IP的网络掩码
DSock_SetNetmask() 设置本机TCP/IP的网络掩码
DSock_GetGateway() 获取网关IP地址
DSock_AddGateway() 设置网关IP地址
DSock_GetDomainNameServer() 获取DNS的IP地址
DSock_AddDomainNameServer() 设置DNS的IP地址
DSock_Resolve() 网络域名解析为对应IP地址

帮助函数

按byte顺序将数据从主机传送到网络和获取IP地址的帮助函数如下:

函数 描述
inet_ntoa() 将DWORD类型IP地址转为包含点分式IP地址
inet_addr() 将包含点分式IP地址的字符串转为DWORD类型IP地址
ntohs() 将一个WORD类型数据转为主机Byte类型数据排列
ntohl() 将一个DWORD类型数据转为主机Byte类型数据排列
htons() 将一个WORD类型数据转为网络Byte类型数据排列
htonl() 将一个DWORD类型数据转为网络Byte类型数据排列

套接字函数

关于连接的DSock库函数如下,参考服务器& 客户端部分可以得到更多信息:

函数 描述
SocketCreate() 创建一个套接字
SocketDestory() 释放一个套接字
SocketClose() 关闭一个套接字
SocketAbort() 中止一个套接字
SocketBind() 套接字IP地址和端口绑定
SocketListen() 套接字监听
SocketAccept() 套接字接受连接请求(非阻塞模式)
SocketConnect() 与远端建立一个连接
SocketIsConnected() 检测套接字的连接状态
SocketIsTcpPortUsed() 检测TCP端口状态
SocketIsUdpPortUsed() 检测UDP端口状态
SocketFindFreeTcpPort() 搜寻一个空闲TCP端口
SocketFindFreeUdpPort() 搜寻一个空闲UDP端口
SocketFlush() 清空套接字缓冲区
SocketFlushNext() 套接字下一次读写操作到来时,清空套接字缓冲区

当套接字已经连接(UDP不需要连接),有关数据传送的DSock库函数如下:

函数 描述
SocketSend() 发送数据(阻塞模式)
SocketSend2() 发送数据(非阻塞模式)
SocketRecv() 接收数据(阻塞模式)
SocketRecv2() 接收数据(非阻塞模式)
SocketPutChar() 读入一个字符
SocketGetChar() 写入一个字符
SocketGetString() 读入一个字符串
SocketPutString() 写入一个字符串
SocketDataReady() 查询套接字已经接收数据的大小

DSock库开发

DSock利用包驱动器发送/接收所有TCP/IP包数据;启动后,DSock会检查包驱动器和CPU 的状态。所以,开发第一步,调用DSock_Open( )函数初始化DSock库,调用DSock_Close( ) 函数释放DSock库。第二步,装载网络配置文件;如果有BOOT/DHCP服务器,直接调用 DSock_DoBootp( ) 获取网络配置信息,否则,调用DSock_LoadConfigFile( ),通过装载网络配 置文件(DSOCK.CFG)获取网络配置信息。DSOCK.CFG是一个DSock库网络配置文本文件; 希望获得更多信息,请参考DSOCK.CFG相关部分。DSock库开发举例如下:


#include "dsock.h"
#include <stdio.h>

int main()
{
  /* Initialize DSock library */
  if(DSock_Open()==FALSE)
  {
    printf("Unable to initialize socket library\n");
    return 1;
  }

  /* Use BOOTP/DHCP to get setup */
  if(DSock_DoBootp()==TRUE)
  {
    printf("Load network setup from BOOTP/DHCP\n");
  }
  else /* Load setup from config file */
  {
    printf("Unable to load setup from BOOTP/DHCP server\n");
    DSock_LoadConfigFile("dsock.cfg");
    printf("Load network setup from DSOCK.CFG\n");
  }

  /* You code here */

  /* Close DSock library */
  DSock_Close();
  return 0;
}

使用DNS

如果DSOCK.CFG中增加了nameserver,或者调用过DSock_AddDomainNameServer( )函数增 加了域名服务器,则可以调用DSock_Resolve( )函数,根据网络域名解析获得对应的IP地 址。举例如下:


char szBuf[32];
DWORD dwIp = DSock_Resolve("www.dmp.com.cn");
printf("IP of www.dmp.com.cn is %s\n",inet_ntoa(dwIp));

使用TCP

传输控制协议(TCP)提供了一个可靠的、序列的、首尾相连的、基于IP上层的、面向连接的服务,它可以通过端口号实现多连接。创建TCP套接字时,可以很容易将参数“TCP_SOCKET”传递给“SocketCreate()”函数,举例如下:


SOCKET s = SocketCreate(TCP_SOCKET);

使用UDP

用户数据报协议(UDP)提供了一个非序列的、不可靠的、非连接的服务。创建UDP套接字时,可以将参数“TCP_SOCKET”传递给“SocketCreate()”函数,举例如下:


SOCKET s = SocketCreate(UDP_SOCKET);

TCP服务器/客户端模式

TCP是服务器/客户端模式下的面向连接的服务,客户端必须连接到服务器,服务器必须监 听客户端连接请求。它们之间的关系如下:

Server Client
SocketCreate() SocketCreate()
SocketBind()
SocketListen()
SocketConnect()
SocketAccept()
SocketSend()/SocketRecv() SocketRecv()/SocketSend()
SocketClose() SocketClose()
SocketDestory() SocketDestory()

DSock库中的实例TALK_TCP通过源代码展示了这种服务器-客户端模式,实例源代码如下:

服务器 客户端
s = SocketCreate(TCP_SOCKET);
if(s==INVALID_SOCKET)
{
  printf("SocketCreate() error\n");
  DSock_Close();
  return 1;
}

if(nArgCnt==1) /* Server mode */
  TalkServer(s);
else           /* Client mode */
  TalkClient(s,pszArg[1]);
if(SocketBind(s,0L,TALK_PORT)==FALSE)
{
  printf("SocketBind() error\n");
  return FALSE;
}
	
if(SocketListen(s)==FALSE)
{
  printf("SocketListen() error\n");
  return FALSE;
}
printf("Talk server mode, listening...\n");
	
	
printf("Talk client mode, connecting to server...\n");

/* Connect to server */
if(SocketConnect(s,inet_addr(szServer),
  TALK_PORT)==FALSE)
{
  printf("SocketConnect() error\n");
  return FALSE;
}
/* Wait for client */
while(TRUE)
{
  if(kbhit())
  {
    printf("Break by user\n");
    break;
  }

  if(SocketAccept(s,&dwIp))
  {
    bConnected = TRUE;
    inet_ntoa(szBuf,dwIp);
    printf("Connected with %s\n",szBuf);
    break;
  }
}
	
	
/* Is connected with client ? */
if(bConnected)
{
  printf("Start to talk...\n");
  while(TRUE)
  {
    /* Check key press */
    if(kbhit())
    {
      char c = getch();
      SocketPutChar(s,c);
      if(c==27)
      {
        printf("\nProgram terminated\n");
        break;
      }
    }
    /* Check message sent by client */
    if(SocketDataReady(s))
    {
      char c;
      SocketGetChar(s,&c);
      printf("%c",c);
      if(c==27)
      {
        printf("\nProgram terminated\n");
        break;
      }
    }
  }
}
printf("Connected to %s:%d\n",szServer,TALK_PORT);
while(TRUE)
{
  /* Check key press and send it out */
  if(kbhit())
  {
    char c = getch();
    SocketPutChar(s,c);
    if(c==27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }
  /* Check key press sent by server */
  if(SocketDataReady(s))
  {
    char c;
    SocketGetChar(s,&c);
    printf("%c",c);
    if(c==27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }
}
  SocketClose(s);
  SocketDestory(s);

UDP服务器/客户端模式

UDP无连接,它没有服务器或客户端,所以运用UDP发送/接收数据比运用TCP容易。DSock 库中的实例TALK_UDP展示了可以接收目标机键盘的输入消息,并可以向目标机发送同类 消息。实例源代码如下:

s = SocketCreate(UDP_SOCKET);
if(s==INVALID_SOCKET)
{
  printf("SocketCreate() error\n");
  DSock_Close();
  return 1;
}

if(SocketBind(s,0xFFFFFFFFL,1234)==FALSE)
{
  printf("SocketBind() error\n");
  DSock_Close();
  return 1;
}

printf("Start to talk, any press will be broadcast...\n");
while(TRUE)
{
  /* User press keyboard ? */
  if(kbhit())
  {
    char  c = getch();
    if(c == 27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }

  /* Is there any broadcast message ? */
  if(SocketDataReady(s))
  {
    char  c;
    /* Save remote IP and port */
    SocketRecvFrom(s, &dwAddr, &wPort,&c,1);
    printf("From %s:%d, send '%c' back.\n", inet_ntoa(szBuf, dwAddr), wPort, c);
    /* Send key press back to original port */
    SocketSendTo(s, dwAddr, wPort, &c, 1);
    if(c == 27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }
}

SocketClose(s);
SocketDestory(s);

UDP广播

DSock库中实例TALK_UB的源代码示例了怎样用UDP广播,并展示可以接收被广播的消 息并,以及可以将键盘消息广播出去。实例源代码如下:

s = SocketCreate(UDP_SOCKET);
if(s==INVALID_SOCKET)
{
  printf("SocketCreate() error\n");
  DSock_Close();
  return 1;
}

if(SocketBind(s,0xFFFFFFFFL,1234)==FALSE)
{
  printf("SocketBind() error\n");
  DSock_Close();
  return 1;
}

printf("Start to talk, any press will be broadcast...\n");
while(TRUE)
{
  /* User press keyboard ? */
  if(kbhit())
  {
    char c = getch();
    SocketPutChar(s,c);
    if(c==27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }
  /* Is there any broadcast message ? */
  if(SocketDataReady(s))
  {
    char c;
    SocketGetChar(s,&c);
    printf("%c",c);
    if(c==27)
    {
      printf("\nProgram terminated\n");
      break;
    }
  }
}

SocketClose(s);
SocketDestory(s);

阻塞模式&非阻塞模式

工作完成后,阻塞模式才返回;而非阻塞模式下,若有问题,立刻返回。例如,SocketAccept( ) 函数是一个非阻塞模式函数;所以,我们用一个while循环检测客户端的连接状态,在DOS 系统单任务环境下,这样可以借助该方法做更多的工作。DSock库中的实例SOCK_AP展示 了怎样用DSock接收FTP/HTTP/TELNET/SMTP连接。DSock库的非阻塞模式函数包含以下 几个:SocketAccept( ), SocketSend2( ), SocketRecv2( ).

多连接

为节省系统资源,SocketAccept( )函数返回一个套接字描述符。如果你希望接收多个连接, 必须声明多个套接字,示例代码如下:


#define MAX_SOCKET 5

SOCKET s[MAX_SOCKET];

for(i=0;i<MAX_SOCKET;i++)
{
  s[i] = SocketCreate(TCP_SOCKET);
  if(s==INVALID_SOCKET)
    return;
  if(SocketBind(s[i],0L,nPort)==FALSE)
    return;
  if(SocketListen(s[i])==FALSE)
    return;
}

while(TRUE)
{
  for(i=0;i<MAX_SOCKET;i++)
  if(SocketAccept(s[i],&dwIp))
  {
    /* Do Job Here */
    break;
  }
}

实例

DSock库有丰富的实例,参考源代码可以得到更多信息。

文件名称 描述
LIB.HTM DSock库参考文件
LIB\DSOCK.H DSock库头文件,C语言
LIB\DSOCK.LIB DSock库,DOS系统、大型记忆体模式
LIB\DSOCK.CFG 缺省网络配置文件
LIB\PKTDRV\NE2000.COM 8019AS包驱动文件
LIB\PKTDRV\PKTDRV.BAT 装载包驱动的DOS 批处理文件

实例

Example Name 描述
DEMO\BOOTP 利用BOOTP/DHCP从DHCP服务器获取网络配置
DEMO\DNS 根据网络域名解析获得对应的IP地址
DEMO\FTPD FTP服务器实例,缺省用户名是“dmp”,缺省密码是“dmp”
DEMO\HTTPD Web服务器实例
DEMO\SMTP 发送e-mail的一个程序
DEMO\SMTPD SMTP服务器实例
DEMO\TELNETD 简单的TELNET服务器实例,缺省用户名是“dmp”,缺省密码是“dmp”
DEMO\TALK_S 多TCP连接的谈话服务器实例
DEMO\TALK_TCP 运用TCP完成的谈话实例
DEMO\talk_tcp_win 用WinSock编写的Windows版本谈话(TCP)
DEMO\TALK_UB 运用广播完成的谈话实例
DEMO\talk_ub_win 用WinSock编写的Windows版本谈话(UB)
DEMO\TALK_UDP 运用UDP完成的谈话实例
DEMO\talk_udp_win 用WinSock编写的Windows版本谈话(UDP)
DEMO\SOCK_AP 支持FTP/HTTP/SMTP/TELNET的一个启动工程

DSOCK.CFG

DSOCK.CFG是一个网络配置文本文件。DSock有两种方法获取网络配置信息,第一种,如果有 BOOT/DHCP服务器,通过调用DSock_DoBootp( )函数直接获取网络配置信息;第二种,将网络 配置信息写进DSOCK.CFG文件,DSock从中读取网络配置信息,这种情况可以确保IP地址固 定。DSOCK.CFG文件描述了以下四种主状态:ip,netmask,gateway,nameserver

典型DSOCK.CFG文件配置信息示例如下:


ip=192.168.0.234
netmask=255.255.255.0
gateway=192.168.0.1
nameserver=192.168.0.1

如果没有DNS服务器,nameserver标记符这样设置:“nameserver=”。如果没有网关,gateway 标记符的设置方法和nameserver标记符相同。

包驱动器

DSock库为386 SX CPU M6117D设计,Realtek 8019AS芯片用于通信板中。缺省IRQ的设置为 5,缺省I/O地址的设置为320H,所以必须在批处理文件autoexec.bat中加入以下内容:


ne2000 0x62 5 0x320
to you autoexec.bat.

安装程序

程序测试完毕,将之装载进单板机中,对于DOS系统,启动时需要一个autoexec.bat文件引导。 另外,DSock库需要软件包驱动,所以包驱动程序也需要安装。安装所需的文件如下:

文件名称 描述
X-DOS 在DM&P 单板机上可以免费使用X-DOS
AUTOEXEC.BAT 装载包驱动器,引导你的程序
NE2000.COM 8019AS包驱动器文件
DSOCK.CFG DSock库网络配置文件
Your App 运用DSock库编写的程序

如果设备不能用X-DOS引导,可以拷贝这些文件到存储设备(Flash Disk/DOC/DOM),否则需 要首先安装X-DOS。利用"MakeROM"工具, 可以为Mity-Mite模块制作一个ROM映像,从而节省 DOC/DOM;一旦存储设备具有Mity-Mite模块,通电后就具有了Internet功能。

技术支持

如果你在使用DSock中出现任何问题,请联系我们,邮件地址:tech@dmp.com.cn please.


Jan Yin Chan Electronics Co., LTD. 保留所有权利. Email us: tech@dmp.com.cn