Winsock开发网络通信程序的经典入门

对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手。许多概念,诸如:同步(Sync) / 异步(Async),阻塞(Block) / 非阻塞(Unblock)等,初学者往往迷惑不清,只知其所以而不知起所以然。

  同步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而异步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。

   阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用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编程机制的理解。

  为了简单起见,服务器端和客户端的应用程序均是基于MFC的标准对话框,网络通信部分基于Winsock2 API实现。

  先做服务器端应用程序。

   用MFC向导做一个基于对话框的应用程序SocketSever,注意第三步中不要选上Windwos Sockets选项。在做好工程后,创建一个SeverSock,将它设置为异步非阻塞模式,并为它注册各种网络异步事件,然后与自定义的网络异步事件联 系上,最后还要将它设置为监听模式。在自定义的网络异步事件的回调函数中,你可以得到各种网络异步事件,根据它们的类型,做不同的处理。下面将详细介绍如 何编写相关代码。

  在SocketSeverDlg.h文件的类定义之前增加如下定义:  #define  NETWORK_EVENT WM_USER+166 file: // 定义网络事件

SOCKET ServerSock; file: // 服务器端Socket
  在类定义中增加如下定义:

class  CSocketSeverDlg : CDialog
... {
 public:
  SOCKET ClientSock[CLNT_MAX_NUM]; file://存储与客户端通信的Socket的数组

  /**//*各种网络异步事件的处理函数*/
  void OnClose(SOCKET CurSock); file://对端Socket断开
  void OnSend(SOCKET CurSock); file://发送网络数据包
  void OnReceive(SOCKET CurSock); file://网络数据包到达
  void OnAccept(SOCKET CurSock); file://客户端连接请求

  BOOL InitNetwork(); file://初始化网络函数
  void OnNetEvent(WPARAM wParam, LPARAM lParam); file://异步事件回调函数
  …
} ;
  在SocketSeverDlg.cpp文件中增加消息映射,其中OnNetEvent是异步事件回调函数名:

ON_MESSAGE(NETWORK_EVENT,OnNetEvent)
  定义初始化网络函数,在SocketSeverDlg.cpp文件的OnInitDialog()中调此函数即可。

BOOL CSocketSeverDlg::InitNetwork()
... {
 WSADATA wsaData;

 //初始化TCP协议
 BOOL ret = WSAStartup(MAKEWORD(2,2), &wsaData);
 if(ret != 0)
 ...{
  MessageBox("初始化网络协议失败!");
  return FALSE;
 }

 //创建服务器端套接字
 ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if(ServerSock == INVALID_SOCKET)
 ...{
  MessageBox("创建套接字失败!");
  closesocket(ServerSock);
  WSACleanup();
  return FALSE;
 }

 //绑定到本地一个端口上
 sockaddr_in localaddr;
 localaddr.sin_family = AF_INET;
 localaddr.sin_port = htons(8888); //端口号不要与其他应用程序冲突
 localaddr.sin_addr.s_addr = 0;
 if(bind(ServerSock ,(struct sockaddr*)&localaddr,sizeof(sockaddr))= = SOCKET_ERROR)
 ...{
  MessageBox("绑定地址失败!");
  closesocket(ServerSock);
  WSACleanup();
  return FALSE;
 }

 //将SeverSock设置为异步非阻塞模式,并为它注册各种网络异步事件,其中m_hWnd 
 //为应用程序的主对话框或主窗口的句柄
 if(WSAAsyncSelect(ServerSock, m_hWnd, NETWORK_EVENT, FD_ACCEPT | FD_CLOSE | FD_READ | FD_WRITE) == SOCKET_ERROR)
 ...{
  MessageBox("注册网络异步事件失败!");
  WSACleanup();
  return FALSE;
 }
 listen(ServerSock, 5); file://设置侦听模式
 return TRUE;
}
  下面定义网络异步事件的回调函数

void  CSocketSeverDlg::OnNetEvent(WPARAM wParam, LPARAM lParam)
... {
 //调用Winsock API函数,得到网络事件类型
 int iEvent = WSAGETSELECTEVENT(lParam);

 //调用Winsock API函数,得到发生此事件的客户端套接字
 SOCKET CurSock= (SOCKET)wParam;

 switch(iEvent)
 ...{
  case FD_ACCEPT: //客户端连接请求事件
   OnAccept(CurSock);
   break;
  case FD_CLOSE: //客户端断开事件:
   OnClose(CurSock);
   break;
  case FD_READ: //网络数据包到达事件
   OnReceive(CurSock);
   break;
  case FD_WRITE: //发送网络数据事件
   OnSend(CurSock);
   break;
  default: break;
 }
}
   以下是发生在相应Socket上的各种网络异步事件的处理函数,其中OnAccept传进来的参数是服务器端创建的套接字,OnClose()、 OnReceive()和OnSend()传进来的参数均是服务器端在接受客户端连接时新创建的用与此客户端通信的Socket。

void  CSocketSeverDlg::OnAccept(SOCKET CurSock)
... {
 //接受连接请求,并保存与发起连接请求的客户端进行通信Socket
 //为新的socket注册异步事件,注意没有Accept事件
}

void  CSocketSeverDlg::OnClose(SOCET CurSock)
... {
 //结束与相应的客户端的通信,释放相应资源
}

void  CSocketSeverDlg::OnSend(SOCET CurSock)
... {
 //在给客户端发数据时做相关预处理
}

void  CSocketSeverDlg::OnReceive(SOCET CurSock)
... {
 //读出网络缓冲区中的数据包
}  
   用同样的方法建立一个客户端应用程序。初始化网络部分,不需要将套接字设置为监听模式。注册异步事件时,没有FD_ACCEPT,但增加了 FD_CONNECT事件,因此没有OnAccept()函数,但增加了OnConnect()函数。向服务器发出连接请求时,使用connect()函 数,连接成功后,会响应到OnConnect()函数中。下面是OnConnect()函数的定义,传进来的参数是客户端Socket和服务器端发回来的 连接是否成功的标志。

void  CSocketClntDlg::OnConnect(SOCKET CurSock,  int  error)
... {
 if(0 = = error)
 ...{
  if(CurSock = = ClntSock)
   MessageBox("连接服务器成功!");
 }
}
  •定义OnReceive()函数,处理网络数据到达事件;

  •定义OnSend()函数,处理发送网络数据事件;

  •定义OnClose()函数,处理服务器的关闭事件。

  以上就是用基于Windows消息机制的异步I / O模型做服务器和客户端应用程序的基本方法。另外还可以用事件模型、重叠模型或完成端口模型,读者可以参考有关书籍。

   在实现了上面的例子后,你将对Winsock编网络通信程序的机制有了一定的了解。接下来你可以进行更精彩的编程, 不仅可以在网上传输普通数据,而且还以传输语音、视频数据,你还可以自己做一个网络资源共享的服务器软件,和你的同学在实验室的局域网里可以共同分享你的 成果。 

VC网络编程-Winsock开发网络通信程序的经典入门相关推荐

  1. Winsock开发网络通信程序的经典入门

    Winsock开发网络通信程序的经典入门 对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手.许多概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Un ...

  2. 基于Winsock API的VC网络编程实战

    基于Winsock API的VC网络编程实战 随着计算机信息技术的飞速发展,互联网与人类社会的工作.生活越来越紧密相关,它已经成为人类获取.交流信息的重要途径和手段.所以当前对于开发人员来说,网络编程 ...

  3. 【网络编程】TCP 网络应用程序开发

    [网络编程]TCP 网络应用程序开发 TCP 网络应用程序开发流程 1. TCP 网络应用程序开发流程的介绍 2. TCP 客户端程序开发流程的介绍 3. TCP 服务端程序开发流程的介绍 4. 小结 ...

  4. 关于VC网络编程中用 char 发送结构体的说明

    关于VC网络编程中用 char 发送结构体的说明     在VC中要发送struct的程序,如果需要中间打包的话,首先因该将结构体转换为字节型的.然后再用 send (SOCKET s,const c ...

  5. Socket网络编程--小小网盘程序(5)

    http://www.cnblogs.com/wunaozai/p/3893469.html 各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中 ...

  6. qn模块java脚本_Qn271 对于网络编程 反射 IO 线程的一些一本入门程序 多多联系会加快 速度 WinSock-NDIS 269万源代码下载- www.pudn.com...

    文件名称: Qn271下载  收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 673 KB 上传时间: 2015-05-13 下载次数: 0 提 供 者: 褚晓旦 详细 ...

  7. VC驿站《VC++网络编程班》开课啦!

    原文链接:http://www.cctry.com/thread-240361-1-1.html 〓课程声明〓 VC驿站的各位网友大家好,非常感谢大家的支持.应广大网友要求,VC驿站特推出<VC ...

  8. LabVIEW编程LabVIEW开发 旧程序升级维护

    LabVIEW编程LabVIEW开发 旧程序升级维护 前段时间遇到一个LabVIEW软件维护的项目.系统是RT测试,和上位机有通讯,用的都是NI的控制器和板卡,只是时间比较久了,软件是用LabVIEW ...

  9. Qt网络编程-简易版UDP组播通信入门Demo(5)

    Qt网络编程-简易版UDP组播通信入门Demo(5)

最新文章

  1. hibernate hql limit的实现方式
  2. 【Janino】Janino框架初识与使用教程
  3. SpringCloud工作笔记056---mysql自增序列管理表_自增序列函数创建
  4. android studio 项目源码_这个标星 2.3k+ 的项目带你 Android 源码分析从入门到放弃...
  5. INCEPTION 编译过程报错 make[2]: * [sql/CMakeFiles/sql.dir/sql_yacc.cc.o] Error
  6. 079 pandas模块
  7. centos7配置时间同步服务器
  8. 计算机考研408真题百度云,2021计算机408考研计算机网络百度云+408历年真题
  9. 计算机辅助初中英语教学,利用多媒体优化初中英语课堂教学课题研究
  10. 董明珠表示“格力不能更好运营,我绝不交班”,现实由不得她
  11. 正交设计之正交四原则
  12. C语言---数组排序
  13. 【EXLIBRIS】#小词旮旯# 001 Lock
  14. iOS超级签名系统源码及分析
  15. pandas 报错 KeyError: 0
  16. 脱机使用计算机是什么意思,电脑脱机状态是什么意思
  17. 阿里云新Logo:生于代码
  18. 如何在不同的窗口中打开多个Excel
  19. Java 基础 利用数组来实现银行注册开户、存钱、取钱
  20. 0x00881789 处的第一机会异常(在 receive_filter.exe 中): 0xC0000005: 读取位置 0x00000000 时发生访问冲突。

热门文章

  1. Linux系统下使用java语言调用海康威视SDK连接摄像头过程记录
  2. chap2 kNN算法 2.2.2 分析数据:使用Matplotlib创建散点图
  3. Matlab 显著性检测模型评价算法之KL距离
  4. 形容人的内核是什么意思_进入内核态究竟是什么意思?
  5. JavaScript 异步
  6. Dubbo基本原理与机制
  7. Java并发包中常用类小结(一)
  8. IPO 首次公开募股(Initial Public Offerings,简称IPO)
  9. oracle轮训查询,道路客运管理信息系统
  10. JSON.parse() 中 reviver参数的理解