欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    Socket编程指南及示例程序.pdf

    • 资源ID:76242764       资源大小:40.04KB        全文页数:23页
    • 资源格式: PDF        下载积分:20金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要20金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Socket编程指南及示例程序.pdf

    1前言在一些常用的编程技术中,Socket网络编程可以说是最简单的一种。而且Socket编程需要的基础知识很少,适合初学者学习网络编程。目前支持网络传输的技术、语言和工具繁多,但是大部分都是基于Socket开发的,虽说这些“高级”的网络技术屏蔽了大部分底层实现,号称能极大程度的简化开发,而事实上如果你没有一点Socket基础,要理解和应用这些技术还是很困难的,而且会让你成为“半瓢水”。深有感触的是当年我学习CORBA 的时候,由于当时各方面的基础薄弱,整整啃了半年书,最终还是一头雾水。如果现在让我带一个人学CORBA,我一定会安排好顺序:首先弄清C+语法;然后是VC 编译环境或者nmake的用法;接下来学习一些网络基础知识;然后是 Socket编程;这些大概要花费3、4 个月。有了这些基础学习CORBA 一周即可弄懂,两个月就可以基于CORBA 进行开发了。好了,说了半天其实中心思想就一个,Socket很简单,很好学!如果你会 C+或者 JAVA,又懂一点点网络基础如TCP 和 UDP 的机制,那么你看完本文就可以熟练进行Socket开发了。2Socket简介(全文摘抄)(本节内容全部抄自网络,不保证正确性,有兴趣的可以看看!)80 年代初,美国政府的高级研究工程机构(ARPA)给加利福尼亚大学Berkeley分校提供了资金,让他们在UNIX操作系统下实现TCP/IP 协议。在这个项目中,研究人员为TCP/IP网络通信开发了一个API(应用程序接口)。这个API 称为 Socket接口(套接字)。今天,SOCKET接口是 TCP/IP 网络最为通用的API,也是在 INTERNET上进行应用开发最为通用的API。90 年代初,由Microsoft联合了其他几家公司共同制定了一套WINDOWS下的网络编程接口,即 WindowsSockets规范。它是BerkeleySockets的重要扩充,主要是增加了一些异步函数,并增加了符合Windows消息驱动特性的网络事件异步选择机制。WINDOWSSOCKETS规范是一套开放的、支持多种协议的Windows下的网络编程接口。从 1991年的 1.0 版到 1995年的 2.0.8版,经过不断完善并在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的全力支持下,已成为Windows网络编程的事实上的标准。目前,在实际应用中的WINDOWSSOKCETS规范主要有1.1 版和 2.0 版。两者的最重要区别是1.1版只支持 TCP/IP协议,而 2.0版可以支持多协议。2.0版有良好的向后兼容性,任何使用1.1 版的源代码,二进制文件,应用程序都可以不加修改地在2.0 规范下使用。SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET接口的计算机通信。应用程序在网络上传输,接收的信息都通过这个SOCKET接口来实现。在应用开发中就像使用文件句柄一样,可以对SOCKET句柄进行读,写操作。3再说两句网上很多文章对于Socket的来龙去脉有如教科书一般的精准。但是涉及具体编程技术就往往被 VC 等集成开发环境所毒害了,把Windows SDK、MFC、Socket、多线程、DLL 以及编译链接等等技术搅合在一起煮成一锅夹生饭。既然要学习Socket,就应该用最简单直白的方式把Socket的几个使用要点讲出来。我认为程序员最关心的有以下几点,按照优先级排列如下:1.Socket的机制是什么?2.用 C/C+写 Socket需要什么头文件、库文件、DLL,它们可以由谁提供,安装后一般处于系统的哪个文件夹内?3.编写 Socket程序需要的编程基础是什么?4.Socket库内最重要的几个函数和数据类型是什么?5.两个最简单的例子程序;6.一个贴近应用的稍微复杂的Socket应用程序。我将一一讲述这些要点,并给出从简到繁,从朴素到花哨的所有源代码以及编译链接的命令。4Socket的机制是什么?我们可以简单的把Socket理解为一个可以连通网络上不同计算机程序之间的管道,把一堆数据从管道的A 端扔进去,则会从管道的B 端(也许同时还可以从C、D、E、F 端冒出来)。管道的端口由两个因素来唯一确认,即机器的IP 地址和程序所使用的端口号。IP 地址的含义所有人都知道,所谓端口号就是程序员指定的一个数字,许多著名的木马程序成天在网络上扫描不同的端口号就是为了获取一个可以连通的端口从而进行破坏。比较著名的端口号有 http的 80 端口和 ftp 的 21 端口(我记错了么?)。当然,建议大家自己写程序不要使用太小的端口号,它们一般被系统占用了,也不要使用一些著名的端口,一般来说使用10005000之内的端口比较好。Socket可以支持数据的发送和接收,它会定义一种称为套接字的变量,发送数据时首先创建套接字,然后使用该套接字的sendto等方法对准某个IP/端口进行数据发送;接收端也首先创建套接字,然后将该套接字绑定到一个IP/端口上,所有发向此端口的数据会被该套接字的 recv等函数读出。如同读出文件中的数据一样。5所需的头文件、库文件和DLL 对于目前使用最广泛的Windows Socket2.0版本,所需的一些文件如下(以安装了VC6为例说明其物理位置):头文件 winsock2.h,通常处于C:Program FilesMicrosoft Visual StudioVC98INCLUDE;查看该头文件可知其中又包含了windows.h和pshpack4.h头文件,因此在windows中的一些常用API 都可以使用;库文件 Ws2_32.lib,通常处于C:Program FilesMicrosoft Visual StudioVC98Lib;DLL 文件 Ws2_32.dll,通常处于C:WINDOWSsystem32,这个是可以猜到的。6编写 Socket程序需要的编程基础在开始编写Socket程序之前,需要以下编程基础:C+语法;一点点 windows SDK 的基础,了解一些 SDK 的数据类型与API 的调用方式;一点点编译、链接和执行的技术;知道cl 和 link 的最常用用法即可。7UDP 用最通俗的话讲,所谓 UDP,就是发送出去就不管的一种网络协议。因此 UDP 编程的发送端只管发送就可以了,不用检查网络连接状态。下面用例子来说明怎样编写UDP,并会详细解释每个API 和数据类型。7.1 UDP广播发送程序下面是一个用UDP 发送广播报文的例子。#include#include void main()SOCKET sock;/socket套接字char szMsg=this is a UDP test package;/被发送的字段/1.启动 SOCKET库,版本为2.0 WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested=MAKEWORD(2,0);err=WSAStartup(wVersionRequested,&wsaData);if(0!=err)/检查 Socket初始化是否成功 coutSocket2.0初始化失败,Exit!;return;/检查 Socket库的版本是否为2.0 if(LOBYTE(wsaData.wVersion)!=2|HIBYTE(wsaData.wVersion)!=0)WSACleanup();return;/2.创建 socket,sock=socket(AF_INET,/internetwork:UDP,TCP,etc SOCK_DGRAM,/SOCK_DGRAM说明是 UDP 类型0 /protocol);if(INVALID_SOCKET=sock)coutSocket 创建失败,Exit!;return;/3.设置该套接字为广播类型,bool opt=true;setsockopt(sock,SOL_SOCKET,SO_BROADCAST,reinterpret_cast(&opt),sizeof(opt);/4.设置发往的地址sockaddr_in addrto;/发往的地址memset(&addrto,0,sizeof(addrto);addrto.sin_family=AF_INET;/地址类型为internetwork addrto.sin_addr.s_addr=INADDR_BROADCAST;/设置 ip 为广播地址addrto.sin_port=htons(7861);/端口号为7861 int nlen=sizeof(addrto);unsigned int uIndex=1;while(true)Sleep(1000);/程序休眠一秒/向广播地址发送消息if(sendto(sock,szMsg,strlen(szMsg),0,(sockaddr*)&addrto,nlen)=SOCKET_ERROR)coutWSAGetLastError()endl;else coutuIndex+:an UDP package is sended.UDP_Send_Broadcast.exe 1:an UDP package is sended.2:an UDP package is sended.3:an UDP package is sended.4:an UDP package is sended.C 下面一一解释代码中出现的数据类型与API 函数。有耐心的可以仔细看看,没耐心的依葫芦画瓢也可以写程序了。7.2 SOCKET类型SOCKET是 socket套接字类型,在WINSOCK2.H中有如下定义:typedef unsigned int u_int;typedef u_int SOCKET;可知套接字实际上就是一个无符号整型,它将被 Socket环境管理和使用。套接字将被创建、设置、用来发送和接收数据,最后会被关闭。7.3 WORD类型、MAKEWORD、LOBYTE和 HIBYTE宏WORD类型是一个16 位的无符号整型,在WTYPES.H中被定义为:typedef unsigned short WORD;其目的是提供两个字节的存储,在 Socket中这两个字节可以表示主版本号和副版本号。使用 MAKEWORD宏可以给一个WORD类型赋值。例如要表示主版本号2,副版本号0,可以使用以下代码:WORD wVersionRequested;wVersionRequested=MAKEWORD(2,0);注意低位内存存储主版本号2,高位内存存储副版本号0,其值为 0 x0002。使用宏 LOBYTE可以读取 WORD的低位字节,HIBYTE可以读取高位字节。7.4 WSADATA类型和 LPWSADATA类型WSADATA类型是一个结构,描述了Socket库的一些相关信息,其结构定义如下:typedef struct WSAData WORD wVersion;WORD wHighVersion;char szDescriptionWSADESCRIPTION_LEN+1;char szSystemStatusWSASYS_STATUS_LEN+1;unsigned short iMaxSockets;unsigned short iMaxUdpDg;char FAR*lpVendorInfo;WSADATA;typedef WSADATA FAR*LPWSADATA;值得注意的就是wVersion字段,存储了 Socket的版本类型。LPWSADATA是 WSADATA的指针类型。它们不用程序员手动填写,而是通过Socket的初始化函数WSAStartup读取出来。7.5 WSAStartup函数WSAStartup函数被用来初始化Socket环境,它的定义如下:int PASCAL FAR WSAStartup(WORD wVersionRequired,LPWSADATA lpWSAData);其返回值为整型,调用方式为PASCAL(即标准类型,PASCAL等于_stdcall),参数有两个,第一个参数为WORD类型,指明了Socket的版本号,第二个参数为WSADATA类型的指针。若返回值为0,则初始化成功,若不为0 则失败。7.6 WSACleanup函数这是 Socket环境的退出函数。返回值为0 表示成功,SOCKET_ERROR表示失败。7.7 socket函数socket的创建函数,其定义为:SOCKET PASCAL FAR socket(int af,int type,int protocol);第一个参数为int af,代表网络地址族,目前只有一种取值是有效的,即AF_INET,代表internet地址族;第二个参数为int type,代表网络协议类型,SOCK_DGRAM代表 UDP 协议,SOCK_STREAM代表 TCP 协议;第三个参数为int protocol,指定网络地址族的特殊协议,目前无用,赋值0 即可。返回值为SOCKET,若返回INVALID_SOCKET则失败。7.8 setsockopt函数这个函数用来设置Socket的属性,若不能正确设置socket属性,则数据的发送和接收会失败。定义如下:int PASCAL FAR setsockopt(SOCKET s,int level,int optname,const char FAR*optval,int optlen);其返回值为int 类型,0 代表成功,SOCKET_ERROR代表有错误发生。第一个参数SOCKET s,代表要设置的套接字;第二个参数int level,代表要设置的属性所处的层次,层次包含以下取值:SOL_SOCKET代表套接字层次;IPPROTO_TCP代表 TCP 协议层次,IPPROTO_IP代表 IP 协议层次(后面两个我都没有用过);第三个参数int optname,代表设置参数的名称,SO_BROADCAST代表允许发送广播数据的属性,其它属性可参考MSDN;第四个参数const char FAR*optval,代表指向存储参数数值的指针,注意这里可能要使用 reinterpret_cast类型转换;第五个参数int optlen,代表存储参数数值变量的长度。7.9 sockaddr_in、in_addr类型,inet_addr、inet_ntoa函数sockaddr_in定义了 socket发送和接收数据包的地址,定义:struct sockaddr_in short sin_family;u_short sin_port;struct in_addr sin_addr;char sin_zero8;其中 in_addr的定义如下:struct in_addr union struct u_char s_b1,s_b2,s_b3,s_b4;S_un_b;struct u_short s_w1,s_w2;S_un_w;u_long S_addr;S_un;首先阐述in_addr的含义,很显然它是一个存储ip 地址的联合体(忘记 union含义的请看c+书),有三种表达方式:第一种用四个字节来表示IP 地址的四个数字;第二种用两个双字节来表示IP 地址;第三种用一个长整型来表示IP 地址。给 in_addr赋值的一种最简单方法是使用inet_addr函数,它可以把一个代表IP 地址的字符串赋值转换为in_addr类型,如addrto.sin_addr.s_addr=inet_addr(192.168.0.2);本例子中由于是广播地址,所以没有使用这个函数。其反函数是inet_ntoa,可以把一个in_addr类型转换为一个字符串。sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下:第一个字段short sin_family,代表网络地址族,如前所述,只能取值AF_INET;第二个字段u_short sin_port,代表 IP 地址端口,由程序员指定;第三个字段struct in_addr sin_addr,代表 IP 地址;第四个字段char sin_zero8,很搞笑,是为了保证sockaddr_in与 SOCKADDR类型的长度相等而填充进来的字段。以下代表指明了广播地址,端口号为7861的一个地址:sockaddr_in addrto;/发往的地址memset(&addrto,0,sizeof(addrto);addrto.sin_family=AF_INET;/地址类型为internetwork addrto.sin_addr.s_addr=INADDR_BROADCAST;/设置 ip 为广播地址addrto.sin_port=htons(7861);/端口号为7861 7.10sockaddr类型sockaddr类型是用来表示Socket地址的类型,同上面的sockaddr_in类型相比,sockaddr的适用范围更广,因为sockaddr_in只适用于TCP/IP 地址。Sockaddr的定义如下:struct sockaddr u_short sa_family;char sa_data14;可知 sockaddr有 16 个字节,而sockaddr_in也有 16 个字节,所以sockaddr_in是可以强制类型转换为sockaddr的。事实上也往往使用这种方法。7.11Sleep函数线程挂起函数,表示线程挂起一段时间。Sleep(1000)表示挂起一秒。定义于 WINBASE.H头文件中。WINBASE.H又被包含于WINDOWS.H中,然后 WINDOWS.H被WINSOCK2.H包含。所以在本例中使用Sleep函数不需要包含其它头文件。7.12sendto函数在 Socket中有两套发送和接收函数,一是sendto和 recvfrom;二是 send 和 recv。前一套在函数参数中要指明地址;而后一套需要先将套接字和一个地址绑定,然后直接发送和接收,不需绑定地址。sendto的定义如下:int PASCAL FAR sendto(SOCKET s,const char FAR*buf,int len,int flags,const struct sockaddr FAR*to,int tolen);第一个参数就是套接字;第二个参数是要传送的数据指针;第三个参数是要传送的数据长度(字节数);第四个参数是传送方式的标识,如果不需要特殊要求则可以设置为0,其它值请参考MSDN;第五个参数是目标地址,注意这里使用的是sockaddr的指针;第六个参数是地址的长度;返回值为整型,如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。7.13WSAGetLastError函数该函数用来在Socket相关 API 失败后读取错误码,根据这些错误码可以对照查出错误原因。7.14closesocket 关闭套接字,其参数为SOCKET类型。成功返回0,失败返回SOCKET_ERROR。7.15小结总结以上内容,写一个UDP 发送程序的步骤如下:1.用 WSAStartup函数初始化Socket环境;2.用 socket函数创建一个套接字;3.用 setsockopt函数设置套接字的属性,例如设置为广播类型;很多时候该步骤可以省略;4.创建一个 sockaddr_in,并指定其IP 地址和端口号;5.用 sendto函数向指定地址发送数据,这里的目标地址就是广播地址;注意这里不需要绑定,即使绑定了,其地址也会被sendto中的参数覆盖;若使用send函数则会出错,因为 send是面向连接的,而 UDP 是非连接的,只能使用sendto发送数据;6.用 closesocket函数关闭套接字;7.用 WSACleanup函数关闭Socket环境。那么,与之类似,一个UDP 接收程序的步骤如下,注意接收方一定要bind套接字:1.用 WSAStartup函数初始化Socket环境;2.用 socket函数创建一个套接字;3.用 setsockopt函数设置套接字的属性,例如设置为广播类型;4.创建一个 sockaddr_in,并指定其IP 地址和端口号;5.用 bind函数将套接字与接收的地址绑定起来,然后调用recvfrom函数或者recv 接收数据;注意这里一定要绑定,因为接收报文的套接字必须在网络上有一个绑定的名称才能保证正确接收数据;6.用 closesocket函数关闭套接字;7.用 WSACleanup函数关闭Socket环境。广播接收程序见源程序代码UDP_Recv_Broadcast.cpp。编译、链接、执行与UDP_Send_Broadcast类似。7.16UDP 点对点发送接收程序广播发送和接收使用并不广泛,一般来说指定发送和接收的IP 比较常用。点对点方式的UDP发送和接收与上面的例子非常类似,不同的就是需要指定一个具体的IP 地址。并且不需要调用 setsockopt设置 socket的广播属性。其具体源代码见UDP_Send_P2P.cpp和 UDP_Recv_P2P.cpp。注意在使用这两个程序时要设为自己所需的IP。8TCP TCP 与 UDP 最大的不同之处在于TCP 是一个面向连接的协议,在进行数据收发之前TCP必须进行连接,并且在收发的时候必须保持该连接。发送方的步骤如下(省略了Socket环境的初始化、关闭等内容):1.用 socket函数创建一个套接字sock;2.用 bind将 sock绑定到本地地址;3.用 listen侦听 sock 套接字;4.用 accept函数接收客户方的连接,返回客户方套接字clientSocket;5.在客户方套接字clientSocket上使用 send发送数据;6.用 closesocket函数关闭套接字sock和 clientSocket;而接收方的步骤如下:1.用 socket函数创建一个套接字sock;2.创建一个指向服务方的远程地址;3.用 connect将 sock连接到服务方,使用远程地址;4.在套接字上使用recv接收数据;5.用 closesocket函数关闭套接字sock;值得注意的是,在服务方有两个地址,一个是本地地址myaddr,另一个是目标地址addrto。本地地址myaddr用来和本地套接字sock绑定,目标地址被sock用来 accept客户方套接字 clientSocket。这样 sock 和 clientSocket连接成功,这两个地址也连接上了。在服务方使用clientSocket发送数据,则会从本地地址传送到目标地址。在客户方只有一个地址,即来源地址addrfrom。这个地址被用来connect远程的服务方套接字,connect成功则本地套接字与远程的来源地址连接了,因此可以使用该套接字接收远程数据。其实这时客户方套接字已经被隐性的绑定了本地地址,所以不需要显式调用bind函数,即使调用也不会影像结果。具体源代码见TCP_Send.cpp和 TCP_Recv.cpp。注意将源代码中的IP 地址修改为符合自己需要的IP。为了减少代码复杂性,没有使用读取本机IP 的代码,后续例子程序中含有此功能代码。8.1 bind函数bind函数用来将一个套接字绑定到一个IP 地址。一般只在服务方(即数据发送方)调用,很多函数会隐式的调用bind函数。8.2 listen函数从服务方监听客户方的连接。同一个套接字可以多次监听。8.3 connect和 accept函数connect是客户方连接服务方的函数,而 accept是服务方同意客户方连接的函数。这两个配套函数分别在各自的程序中被成功调用后就可以收发数据了。8.4 send和 recv函数send 和 recv 是用来发送和接收数据的两个重要函数。send 只能在已经连接的状态下使用,而 recv 可以面向连接和非连接的状态下使用。send的定义如下:int WSAAPI send(SOCKET s,const char FAR*buf,int len,int flags);其参数的含义和sendto中的前四个参数一样。而recv 的定义如下:int WSAAPI recv(SOCKET s,char FAR*buf,int len,int flags);其参数含义与send 中的参数含义一样。9一个局域网聊天工具的编写掌握了以上关于socket的基本用法,编写一个局域网聊天程序也就变得非常简单,如同设计一个普通的对话框程序一样。9.1 功能设计功能设计如下:1.要能够指定聊天对象的IP 和端口(端口可以内部确定);2.要能够发送消息给指定聊天对象;3.要能够接收聊天对象的消息;4.接收消息时要播放声音;5.接收消息时如果当前对话框不是最前端,要闪动图标;6.要有托盘图标,可以将对话框收入托盘;9.2 功能实现将内部端口设为3456,提供一个IP 地址控件来设置聊天对象的IP。该控件必须能够读取IP 地址并赋值给内部变量。将地址转换为in_addr类型。发送消息需要使用一个套接字。接收消息也需要使用一个套接字,由于发送消息也使用了一个套接字,为了在同一个进程中同时发送和接收消息,需要使用多线程技术,将发送消息的线程设为主线程;而接收消息的线程设为子线程,子线程只负责接收UDP 消息,在收到消息后显示到主界面中。接收消息时播放声音这个功能在子线程中完成,使用sndPlaySound函数,并提供一个wav 文件即可。闪动图标这个最白痴的功能需要使用一个Timer,在主对话框类中添加一个OnTimer函数,定时检查当前窗口状态变量是否为假,若为假就每次设置另一个图标。若当前窗口显示到最顶端,则设置为默认图标。托盘图标功能用网上下载的CtrayIcon类轻松搞定。需要提供一个自定义消息,一个弹出菜单资源。9.3 所需资源头文件:winsock2.h,Mmsystem.h 库文件:ws2_32.lib,winmm.lib dll:Ws2_32.dll,winmm.dll wav 文件:recv.wav 图标:一个主程序图标IDI_MAIN、四个变化图标IDI_ICON14;菜单:一个给托盘用的弹出菜单IDR_TRAYICON;说明,Mmsystem.h和 winmm.lib、winmm.dll是为了那个播放声音的功能。9.4 托盘功能托盘属于界面功能,是变更很少的需求,因此首先完成。1.引入 TRAYICON.H和 TRAYICON.cpp两个类;2.在 CLANTalkDlg类中加入一个CTrayIconm_trayIcon;属性;3.在 CLANTalkDlg的构造函数中初始化m_trayIcon,m_trayIcon(IDR_TRAYICON);4.添加一个自定义消息WM_MY_TRAY_NOTIFICATION,即在三个地方添加消息定义、消息响应函数、消息映射;5.在 InitDialog方法中调用托盘初始化的两个函数m_trayIcon.SetNotificationWnd(this,WM_MY_TRAY_NOTIFICATION);m_trayIcon.SetIcon(IDI_MAIN);6.重写 OnClose方法,添加弹出菜单的OnAppSuspend和 OnAppOpen以及OnAppAbout方法;7.重写对话框的OnCancel方法。9.5 动态图标动态图标也是界面相关功能,首先完成。1.添加四个HICON 变量 m_hIcon1,m_hIcon2,m_hIcon3,m_hIcon4;2.在构造函数中初始化这四个变量m_hIcon1=AfxGetApp()-LoadIcon(IDI_ICON1);3.在 InitDialog中设置调用SetTimer(1,300,NULL);设置一个 timer,id 为 1,间隔为 300 微秒;4.添加一个布尔属性m_bDynamicIcon,指示目前是否需要动态图标,并给出一个设置函数SetDynamicIcon;5.添加一个OnTimer函数,让每次 timer调用时根据m_bDynamicIcon的值修改图标;两个地方是用来设置动态图标的,一个是当程序收到消息并且程序不在桌面顶端时,这时设置为动态图标,在后面的消息接收线程中处理;二是当程序显示到桌面顶端时,设置为非动态;重载 OnActivate方法可以完成第二个时刻的要求。当窗口状态为WA_ACTIVE或者WA_CLICKACTIVE时 SetDynamicIcon(false),否则设置SetDynamicIcon(true);9.6 发送 UDP 报文功能发送 UDP 报文只需在主线程中完成,需要以下步骤:1.初始化 Socket环境,这可以在CLANTalkApp的 InitInstance中完成,同理关闭 Socket环境在 ExitInstance中完成;我们可以使用前面的方法,也可以直接调用MFC 中的 AfxSocketInit函数,这个函数可以确保在程序结束时自动关闭 Socket环境;2.创建 socket,考虑到报错信息需要弹出对话框,因此不在CLANTalkDlg的构造函数中创建,而是在 InitDialog中构建;发送报文的socket为 m_sendSock;3.设置目的地址功能,需要一个地址赋值函数setAddress(char*szAddr);可以将一个字符串地址赋值给sockaddr_in形式的地址;在CLANTalkDlg中增加一个 sockaddr_in m_addrto;属性;4.读取文本框中的文字,用sendto发送到对象地址;5.清空文本框,在记录框中添加聊天记录。这时可以使用前面的UDP 简单接收程序来辅助测试,因为此时还未完成报文接收功能。9.7 接收 UDP 报文功能接收 UDP 报文要考虑几个问题,第一个是要创建一个子线程,在子线程中接收报文;第二是接收报文和发送报文要有互斥机制,以免冲突;第三是接收到报文要播放声音;第四是接收报文且当前窗口不在桌面顶端要调用动态图标功能。按照以上需求设计步骤如下:1.创建接收套接字m_recvSock,2.利用 gethostname和 gethostbyname等函数获取本机IP,并将套接字bind到该地址;3.添加一个 CwinThread*m_pRecvThread属性,并在InitDialog中调用AfxBeginThread创建子线程;4.编写子线程运行函数void RecvProcess(LPVOID pParam),这时一个全局函数,为了方便调用CLANTalkDlg类中的各种变量与方法,将 CLANTalkDlg类的指针作为参数传入子线程函数,并将RecvProcess设置为 CLANTalkDlg类的友元。5.子线程函数中完成以下功能:利用recv 接收报文;保存聊天记录;判断当前窗口是否在前台,并修改动态图标属性;播放声音。6.用来记录聊天信息的ClistBox的 Sort 属性要去掉,否则记录会按内容排序,很不好看。在RC 编辑器中去掉这个属性即可。7.最后要注意,在主线程退出时要保证子线程退出,但此时子线程还阻塞在recv方法上,因此主线程向自己发送一条消息消除阻塞,同时改变子线程退出标志保证子线程可以退出。9.8 设置聊天对象IP 点击“确认对象”按钮时,检测IP 地址控件,如果IP 地址有效,则将IP 地址读入内部属性。这个IP 地址作为发送信息的目标地址。这个设置只能设置发送消息的对象,所有人都可以向本机发送信息,只要他的端口是正确的。9.9 编译链接和运行下载压缩包后可以打开VC 工程编译链接,若直接运行则可以点击LANTalkExeFile目录中的可执行文件,这个目标包含了运行所需要的所有dll 和资源文件。当然,如果需要可以用InstallShield做一个安装程序,不过看来是没有必要的。9.10小结这个聊天程序很简单,但是基本上具有了一个框架,可以有最简单的聊天功能。要在此基础上进行扩展几乎已经没有什么技术问题了。10使用好的Socket包可以简化开发过程本文中所有的技术尽量采用最原始的方式来使用。例如多线程使用的是AfxBeginThread,套接字使用了最原始的套接字,并在很多地方直接使用了SDK 函数,而尽量避免了MFC等代码框架,这是为了方便他人掌握技术的最基本内涵。其实在具体的编程中,当然是怎么方便怎么来,Socket和多线程以及界面等功能都有大量方便可用的代码库,复用这些代码库会比自己动手写方便很多。但是,掌握了基本原理再使用这些库,事半功倍!竟然写了14 页,真是pf 自己啊!

    注意事项

    本文(Socket编程指南及示例程序.pdf)为本站会员(索****)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开