用Visual C++ 4.0 实现Windows 95 Socket编程

2001年08月19日 16:10:00

 

用Visual C++ 4.0 实现Windows 95 Socket编程

作者: 李 大 琪

  Windows 95 Socket 提 供 了 在 Microsoft Windows 95 中 进 行 网 络 程 序 设 计 的 一 个 接 口, 它 是 在 Unix Socket 的 基 础 上 发 展 而 来 的, 不 仅 保 留 了Unix Socket 原 有 的 风 格, 而 且 还 融 入 了 适 合 于 Windows 95 的 新 特 点, 这 使 得 用 户 可 以 利 用 Windows 95 Socket API 直 接 进 行 进 程 与 应 用 程 序 间 的 通 信。Windows 95 在Internet 支 配 域 中 的TCP/IP 协 议 定 义 了 Socket 编 写 规 程, 使 用 Socket 的 目 的 是 使 用 户 在 网 络 协 议 上 工 作 而 不 必 对 该 网 络 协 议 有 非 常 深 入 的 了 解。 此 外, 这 样 编 写 的 程 序 可 被 迅 速 移 植 到 任 何 支 持 Socket 的 网 络 系 统 中 去。

  Microsoft Windows Class Library( MFC ) 中 提 供 了 CSocket 类 用 来 实 现 网 络 通 信。 图 一 中 给 出 了CSocket 类 的 继 承 关 系。

   下 面 将 介 绍 用Visual C++ 4.0 在Windows 95 中 实 现 Socket 的 CSocket 类 相 关 成 员 函 数( 这 些 成 员 函 数 实 际 上 是 从CAsyncSocket 类 继 承 来 的 )。

  (1) BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ |FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT| FD_CLOSE,LPCTSTR lpszSocketAddress = NULL )

   该 函 数 用 来 建 立Socket。 其 中,nSocketPort 为 所 选 择 的 Socket 端 口, 一 般 要 大 于 1023, 如 果 该 参 数 为 0, 则 由 系 统 选 定 一 端 口, 默 认 值 为 0 ;nSocketType 为 套 接 字 类 型 :SOCK_STREAM 表 示 为 流 套 接 字, SOCK_DGRAM 表 示 为 数 据 报 套 接 字, 默 认 值 为 SOCK_STREAM ;lEvent 标 识 该 Socket 要 完 成 哪 种 工 作, 默 认 值 为FD_READ|FD_WRITE|FD_OOB| FD_ACCEPT|FD_CONNECT|FD_CLOSE ;lpszSockAddress 为 网 络 地 址 信 息 结 构 指 针, 包 含 网 络 地 址 , 默 认 值 为 NULL 。

  (2)BOOL Bind( UINT nSocketPort, LPCTSTR lpszSocketAddress = NULL )

   该 函 数 的 作 用 是 将Socket 端 口 与 网 络 地 址 连 接 起 来。 参 数 含 义 同 上 。

  (3)BOOL Listen( int nConnectionBacklog = 5 )

   该 函 数 的 作 用 是 等 待Socket 请 求。 其 中,nConnec-tionBacklog 表 示 等 待 队 列 的 长 度, 默 认 值 为 最 大 值 5 。

  (4)virtual BOOL Accept( CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL )

   该 函 数 的 作 用 是 取 得 队 列 上 第 一 个 连 接 请 求 并 建 立 一 个 具 有 与Socket 相 同 特 性 的 套 接 字。 其 中,rConnectedSocket 表 示 一 个 新 的 Socket 。

  (5)BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort )

   该 函 数 的 作 用 是 提 出 请 求。 其 中,lpszHostAddress 和 nHostPort 为 接 受 请 求 进 程 的 网 络 地 址 和 Socket 端 口 号 。

  (6)virtual void Close( )

   该 函 数 的 作 用 是 关 闭 该 Socket 。

   利 用 CSocket 类 直 接 进 行 数 据 通 信 有 两 种 方 式 : 一 种 是 利 用 CSocketFile 类 和 Archive 类 去 实 现, 另 一 种 是 利 用 CSocket 的 成 员 函 数 Receive、Send、ReceiveFrom、SendTo、Listen 和 Accept 等 来 实 现( 这 些 成 员 函 数 实 际 上 也 是 从CAsyncSocket 类 继 承 的)。

   两 种 方 法 的 实 现 步 骤 如 下 :

  Server : Construct-< Creat-< Bind -< Listen-< Accept-< Send-

  Cilent : Construct - < Connect-< Receive-< Close。

   下 面 我 就 用 Visual C++ 4.0 的 代 码 段 分 别 介 绍 如 何 运 用 上 述 两 种 方 法 来 实 现Socket 编 程。

  1、 利 用 CSocketFile 类 和 Archive 类 实 现

  (1)Server

  // construct a socket

  CSocket sockSrvr;

  // create the SOCKET

  sockSrvr.Create(nPort);

  // start listening

  sockSrvr.Listen( );

  //construct a new, empty socket

  CSocket sockRecv;

  // accept connection

  sockSrvr.Accept( sockRecv );

  // construct file object

  CSocketFile file(&sockRecv);

  // construct an archive

  CArchive arIn(&file, CArchive::load);

  /*or*/_CArchive arOut(&file, CArchive::store);

  // use the archive to pass data

  arIn << dwValue;

  /*or*/ arOut >> dwValue;

  (2)Client

  // construct a socket

  CSocket sockClient;

  // create the SOCKET

  sockClient.Create( );

  // seek a connection

  sockClient.Connect(strAddr, nPort);

  // construct file object

  CSocketFile file(&sockClient);

  // construct an archive

  CArchive arIn(&file, CArchive::load);

  /*or*/_CArchive arOut(&file, CArchive::store);

  // use the archive to pass data

  arOut >> dwValue;

  /*or*/ arIn << dwValue;

   上 述 为 Client/Server 模 式 的 两 个 进 程, 用 于 完 成 两 个 进 程 间 一 个 数 据 变 量 的 通 信。 其 中, nPort 是Socket 的 端 口 号,strAddr 是 该 机 器 的IP 地 址( 如 202.197.1.3 或 FTP://RedAlert.com 等), 这 两 个 变 量 在Server 和Client 中 要 一 致。 当Server 进 程 运 行 至 Listen 后 便 处 于 睡 眠 状 态 直 到 Client 进 程 执 行 Connect 时 才 被 唤 醒, 而 后 两 个 进 程 便 开 始 传 输 数 据 了。

  2、 利 用 CSocket 的 成 员 函 数 实 现

  (1)Server

  // Socket initial

  if(!AfxSocketInit()){

   MessageBox("WindowsSocket initial

   failed!","Send",MB_ICONSTOP);

   Return;

  }

  // Construct two socket

  CSocket ChatSend,server;

  // Creat a SOCKET

  if(!ChatSend.Create(nPort)) // nPort=1025

   MessageBox("SendSocket create failed!", "Send",MB_ICONSTOP);

  else{

   // Associates a local address with the socket ChatSend.Bind(nProt,strAddr);

  // strAddr="202.196.111.1"

   // Start Listening

   ChatSend.Listen();

   // Creat a new socket and accepts a connection on

   //the socket

   ChatSend.Accept(Server);

  }

  // Send a CString

  Server.SendTo(csSendText,csCounts,nPort,strAddr);

  // Close the two socket

  Server.Close();

  ChatSend.Close();

  (2)Client

  // Socket initial

  if(!AfxSocketInit()){

   MessageBox("WindowsSocket initial failed!", "Receive",MB_ICONSTOP);

   return;

  }

  // Construct a socket

  CSocket ChatRecieve;

  // Creat a SOCKET

  if(!ChatReceive.Create()){

   MessageBox("ReceiveSocket create

   failed!","Receive",MB_ICONSTOP);

   return;

  }

  else{

   // Establishes a connection to a peer socket

   ChatReceive.Connect(strAddr,nPort);

  }

  // Receive the CString

  ChatReceive.ReceiveFrom(csReceiveText,csCounts,strAddr,nPort);

  // Close the socket

  ChatReceive.Close();

   上 述 两 个 进 程 完 成 的 工 作 是 : 由Server 进 程 发 送 一 字 符 串,Client 进 程 接 收。 strAddr 和 nPort 的 含 义 与 方 法1 中 的 相 同 ;csSendText 和 csReceiveText 为 发 送 与 接 收 的 字 符 串 ;csCounts 为 字 串 长 度, 这 一 长 度 在 两 个 进 程 中 要 求 接 收 长 度 小 于 或 等 于 发 送 长 度, 否 则 会 导 致 数 据 传 输 错 误。 另 外, 在 程 序 中 要 加 入 头 文 件afxsock.h, 因 为CSocket 类 的 有 关 说 明 均 在afxsock.h 中。

   从 上 述 两 种 方 法 中 不 难 发 现, 方 法1 适 合 于 对 多 个 不 同 类 型 数 据 的 通 信, 方 法2 适 合 于 对 字 符 串 的 通 信, 具 体 选 用 何 种 方 法 则 取 决 于 具 体 应 用 的 需 求。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=3496


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网络编程,当然要用到Windows Socket(套接字)技术。Socket相关的操作由一系列API函数来完成,比如socket、bind、listen、connect、accept、send、sendto、recv、recvfrom等。调用这些API函数有一定的先后次序,有些函数的参数还比较复杂,对于开发者来说,不是很好用。于是,微软的MFC提供了两个类:CAsyncSocket和CSocket,极大地方便了Socket功能的使用。   CAsyncSocket类在较低层次上封装了Windows Socket API,并且通过内建一个(隐藏的)窗口,实现了适合Windows应用的异步机制(Windows Socket API默认情况下工作在阻塞模式,不方便直接在消息驱动的Windows程序上使用)。CSocket类从CAsyncSocket类派生,进一步简化了Socket功能的应用。不过很遗憾,正因为这两个类都内建了一个窗口,它们并不是线程安全的(thread-safe);如果要在多线程环境下应用Socket功能,建议自行封装Socket API函数。 基于TCPsocket编程的服务器端程序流程如下: 1、创建套接字 2、将套接字绑定到一个本地地址和端口号上(bind) 3、将套接字设为监听模式,准备接受客户请求(listen) 4、等待客户请求,请求到来时接受请求,建立链接,并返回 一个新的基于此次通信的套接字(accept) 5、用返回的套接字和客户端进行通信(send、recv) 6、返回,等待另一客户请求 7、关闭套接字 基于TCPsocket编程的客户端程序流程如下: 1、创建套接字 2、向服务器端发送请求(connect) 3、和服务器端进行通信(send、recv) 4、关闭套接字 基于UDP的socket编程的服务器端程序流程如下: 1、创建套接字 2、将套接字绑定到本地地址和端口号上(bind) 3、等待接收数据(recvfrom) 4、关闭套接字 基于UDP的socket编程的客户端程序流程如下: 1、创建套接字 2、和服务器端进行通信(sendto) 3、关闭套接字 异步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而同步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。   阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用recv()函数读取网络缓冲区中的数据,如果没有数据到达,将一直挂在recv()这个函数调用上,直到读到一些数据,此函数调用才返回;而非阻塞套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用recv()函数读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。在实际Windows网络通信软件开发中,异步非阻塞套接字是用的最多的。平常所说的C/S(客户端/服务器)结构的软件就是异步非阻塞模式的。   对于这些概念,初学者的理解也许只能似是而非,我将用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制。目的是让初学者不仅对Socket异步非阻塞的概念有个非常透彻的理解,而且也给他们提供一个用Socket开发网络通信应用程序的快速入门方法。操作系统是Windows 98(或NT4.0),开发工具是Visual C++6.0。   MFC提供了一个异步类CAsyncSocket,它封装了异步、非阻塞Socket的基本功能,用它做常用的网络通信软件很方便。但它屏蔽了Socket的异步、非阻塞等概念,开发人员无需了解异步、非阻塞Socket的原理和工作机制。因此,建议初学者学习编网络通信程序时,暂且不要用MFC提供的类,而先用Winsock2 API,这样有助于对异步、非阻塞Socket编程机制的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值