TimeMachine

导航

基于WINSOCK控件的VC网络通讯程序

基于WINSOCK控件的VC网络通讯程序
马进  林永君 马永光 吕丽霞
华北电力大学仿真控制技术实验室,河北保定
 
作者简介: 马进(1971- ),男,籍贯 河北任丘,华北电力大学仿真控制技术研究所工程师,工学硕士,现从事电厂负荷优化、仿真机的开发与研究工作。
 
该程序为原国家电力公司青年促进费项目“发电厂厂级负荷优化调度”中的一部分。项目编号:SP11-2001-05-66
 
摘要:介绍在VISCAL C++ 6.0 环境下,使用Winsock控件进行网络通讯的一种方法。Winsock控件的使用简单,可以方便地应用在使用VC++进行编程的网络通讯程序中。
关键字:Winsock控件  局域网  VC6.0
中图分类号:           文献标识码:          文章编号:
 
引言:
    随着计算机技术的发展和网络的不断普及,网络通讯程序的应用越来越普遍,各种软件开发平台也为网络通讯程序的开发提供了不同形式的类和控件。在利用Visual C++ 进行开发时,可以使用Csocket类;在利用Visucal Basic 进行开发时,可以使用Winsock 控件。有关Csocket类在VC中的使用和Winsock 控件在VB中使用,已经有许多文章、资料进行的介绍,这里不再赘述。同时也应注意到,利用VC的CSocket类需要对网络通讯的机制和参数有较深的了解,需要较深的计算机知识。虽然CSocket对Winsock进行了封装,但是它的函数调用仍然比较复杂,使用起来不容易。与此相反,在利用VB编程时,各种控件的使用比较简单,不需要许多的参数。利用VB中的Winsock 控件进行开发比较容易,但VB本身的功能不如VC强大,在进行开发时有时会受到一定程度的限制。在VC中利用Winsock控件的使用难度则介于上述二者之间,只需对少许一些参数做简单设置即可。如果在用VC编制程序时需要进行网络通讯而又不想花费过多的时间,在VC程序中插入Winsock控件是一种合适的方法。利用Winsock控件可以编制一个简单的通讯程序,用于局域网之间的微机通讯。
1 Winsock控件的使用方法
1.1通讯协议的选择
Winsock控件提供了访问 TCP 和 UDP 网络服务的方便途径。采用TCP协议可以提供双向的、可靠的、有序的和无重复投递的数据流。TCP允许创建和维护与远程计算机的连接,连接两台计算机就可彼此进行数据传输。用户数据文报协议 (UDP) 是一个无连接协议。采用UDP协议,支持双向的数据流,但不保证有序、可靠或无重复的投递。但计算机并不建立连接。
在使用中,采用TCP协议的编程模型应用最为广泛,因为面向连接协议提供了一系列的数据纠错功能,可以保证在网络上传输的数据及时、无误地到达对方,Internet上的多数服务(WWW、FTP、Telnet、SMTP)就是靠此协议运转的。采用UDP协议由于不用建立连接,传输比连接协议快,无数据纠错功能,不保证数据的可靠传递。在这里本文只介绍使用TCP/IP协议进行编程的方法。
1.2使用方法和主要函数
    Winsock控件的使用方法和步骤如下图所示。
      
1.2.1 VARIANT类型变量的使用
   Winsock控件使用的一个特殊的数据类型为VARIANT结构,其中vt的值类型说明了它所存储的数据,vt的几个主要的值类型及值域为:
  类型                      值域                说明
vt=VT_BSTR          bstrVal         字符串类型
vt=VT_I2                  Ival                     整数类型
vt=VT_ERROR      scode                  错误代码
在使用之前,应对VARIANT变量的类型和值域进行赋值。一般的使用方法为:
VARIANT [variant name]
[variant name].vt=[variant type]
[variant name].[variant type]=[value]
例如:
   Cstring  m_host;
   m_host="Room312";
   VARIANT  vtHost;
   vtHost.vt=VT_BSTR;
   vtHost.bstrVal=m_host.AllocSysString();
1.      2.2 Server程序使用的主要函数
    Bind()函数指定用于 TCP 连接的 LocalPort 和 LocalIP。
    Listen()函数设置侦听模式。该方法仅适用于 TCP 连接。
    Accept()在处理 ConnectionRequest 事件时用这个方法接受新连接。
    SendData()用于数据的发送。
    Close()关闭与对方的连接。
1.2.3Client程序使用的主要函数
    Connect()要求连接到远程计算机。
    GetData()得到远程计算机上的数据。
2 使用Winsock控件的局域网通讯程序
2.1 Server程序
   利用ClassWizard建立一个ServerDemo程序,注意选择SDI,支持ActiveX,将View类设为CFormView类, 从Project->Add File->Compont and Control, 在对话框中选Registered ActiveX,选择Microsoft WinSock Control ,点击Insert按钮,依照缺省设置即可。这样在工程文件中会出现mswinsockcontrol类编辑ServerDemo程序的主对话框,可以看到在控件面版上出现mswinsockcontrol类的控件。在对话框中加入控件和相应的变量,如表1所示
 
控件
控件ID
变量名
类型
Edit
IDC_EDIT1
 m_edit
CString
按钮
IDC_SEND
 
 
Winsock
IDC_WINSOCK1
 m_server
控制
Winsock
IDC_WINSOCK2
 m_connect
控制
 
(1)在ServerDemoView.h中,加入以下变量
 VARIANT localport;
 VARIANT localip;
 CString strport;
 CString strip;
 VARIANT vtCommand;
 CString m_command;
 VARIANT vtData;
 VARIANT vtType;
 VARIANT vtMaxlen;
(2)在ServerDemoView .cpp的构造函数中加入:
    localport.vt=VT_BSTR;
    localip.vt=VT_BSTR;
    strport="4000";
   strip="128.1.0.139";//在程序中应将“128.1.25.240”设为自己server  
                      //的IP地址
   vtCommand.vt=VT_BSTR;
   m_command="Server Send";
   vtData.vt=VT_BSTR;
   vtType.vt=VT_ERROR; 
(3)利用ClassWizar映射OnInitialUpdate()的响应:在其中加入代码:
   localport.bstrVal=strport.AllocSysString();
   localip.bstrVal=strip.AllocSysString();
   m_server.Bind(localport, localip);
   m_server.Listen();
(4)利用ClassWizar响应IDC_WINSOCK1的ConnectionRequest事件,在OnConnectionRequestWinsock1()中加入代码:
    if(m_connect.GetState()==0 )
       m_connect.Accept(requestID);
    else
    AfxMessageBox("no more connects",MB_OK);
(5)利用ClassWizar映射ID_SEND的动作:OnSend(),在其中加入代码:
    m_edit.GetWindowText(m_command);
    vtCommand.bstrVal=m_command.AllocSysString();
    m_connect.SendData(vtCommand);
(6)利用ClassWizar响应ID_WINSOCK2的DataArrival事件,在OnDataArrivalWinsock2()中加入代码:
    CString m_MBody;
    vtMaxlen.vt=VT_I2;
    vtMaxlen.iVal=bytesTotal;
    vtData.bstrVal=strport.AllocSysString();
    vtType.bstrVal=strport.AllocSysString();
    m_connect.GetData(&vtData,vtType,vtMaxlen);
    m_MBody=vtData.bstrVal;
    m_edit.SetWindowText( m_MBody);
(7)利用ClassWizar响应ID_WINSOCK2的Close()事件,在OnCloseWinsock2()中加入代码:
    m_connect.Close();
(8)在DestroyWindow() 中加入:
    m_server.Close();
    m_connect.Close();
22 Client程序
    利用ClassWizard建立一个ClientDemo程序,注意选择SDI,支持ActiveX,将View类设为CFormView类, 从Project->Add File->Compont and Control, 在对话框中选Registered ActiveX,选择Microsoft WinSock Control ,点击Insert按钮,依照缺省设置即可。这样在工程文件中会出现mswinsockcontrol类。编辑ClientDemo程序的主对话框,可以看到在控件面版上出现mswinsockcontrol类的控件。在对话框中加入控件和相应的变量,如表2所示
表2控件表
控件
控件ID
变量名
类型
Edit
IDC_EDIT1
 m_edit
CString
按钮
IDC_CONNECT
 m_connect
控制
按钮
IDC_SEND
 
 
Winsock
IDC_WINSOCK1
 m_socket
控制
 
(1)在ClientDemoView.h中,加入以下变量
   CString m_host;
   CString m_port;
   VARIANT vtHost;
   VARIANT vtPort;
   VARIANT vtData;
   VARIANT vtType;
   VARIANT vtMaxlen;
   VARIANT vtCommand;
   CString m_command; 
(2)在ClientDemo.cpp的构造函数中加入:
   m_host=_T("Room312");//在程序中将“Room312”设为自己server的主机
                        //名
   m_port=_T("4000");   //端口设为4000;
   m_command=_T("Client send");
   vtHost.vt=VT_BSTR;
   vtPort.vt=VT_BSTR;
   vtData.vt=VT_BSTR;
   vtType.vt=VT_ERROR;
   vtCommand.vt=VT_BSTR;
(3)利用ClassWizar映射ID_CONNECT的动作:在OnConnect()中加入代码:
   m_socket.SetRemoteHost("Room312");//在程序中将“Room312”设为自己
                                  //server的主机名
   m_socket.SetRemotePort(4000);
   vtHost.bstrVal=m_host.AllocSysString();//见CString类字符串转化为
 //系统字符串
   vtPort.bstrVal=m_port.AllocSysString();
   m_socket.Connect(vtHost,vtPort);
   if(m_socket.GetState()==0) //如果m_socket已经断开连接,将connect
                            //设置为可用
       m_connect.EnableWindow(true);
   else
      m_connect.EnableWindow(false);
(4)利用ClassWizar映射ID_SEND的动作:在OnSend:
    m_edit.GetWindowText(m_command);
    vtCommand.bstrVal=m_command.AllocSysString();
    m_socket.SendData(vtCommand);
(5)利用ClassWizar响应ID_WINSOCK1的DataArrival事件,在 OnDataArrivalWinsock1(long bytesTotal)中加入代码:
   CString m_MBody;
   vtMaxlen.vt=VT_I2;
   vtMaxlen.iVal=bytesTotal;
   vtData.bstrVal=m_host.AllocSysString();
   vtType.bstrVal=m_port.AllocSysString();
   m_socket.GetData(&vtData,vtType,vtMaxlen);
   m_MBody=vtData.bstrVal;
   m_edit.SetWindowText(m_MBody);
(6)在DestroyWindow()中加入:
    m_socket.Close();
(7)利用ClassWizar响应ID_WINSOCK1的Close事件,在OnCloseWinsock1()中加入代码:
    m_socket.Close();
    if(m_socket.GetState()==0)
      m_connect.EnableWindow(true);
else
      m_connect.EnableWindow(false);
3.程序演示及结论
将上述程序分别编辑、连接为执行程序,生成serverdemo.exe和clientdemo.exe文件。确认程序中主机名和IP地址无误。如果计算机没有连网,可以在程序中使用本机的主机名和IP地址。首先运行serverdemo.exe。它自动进入到监听状态。随后运行clientdemo.exe,点击connect按钮。如果client与server 连接成功,connect按钮变为灰色(不可用)。连接成功后,在编辑框中输入文字,点击send按钮,在serverdemo程序的编辑框中可以看到clientdemo程序发送的文字。同样,在serverdemo的编辑框中输入文字,点击send按钮,在clientdemo程序的编辑框中可以看到serverdemo程序发送的文字。
通过上述程序可以看到,同MFC的Csocket类相比,Winsock控件的使用简单方便。程序中并未涉及Winsock最基本的API函数以及TCP/IP的相关知识,编程简单明了,是在VC++程序中进行网络通讯的一种简便方法。
 
 
参考文献:
      1、Visual C++(第四版) 原著David J. Kruglinshi  潘爱民 王国印译   机械工业出版社   1999.1
      2、Visual C++ 6开发使用指南 (美)Kate Gregory 著 前导工作室译  机械工业出版社  1999
 
A Kind of LAN Communication Program Based on Winsock Control
Under VC++6.0 Environment
 
ABSTRACTT: A method for network communication with Winsock control is present under VC++6.0 environment. By inserting Winsock control in program and using its functions, the program can communicate with other programs. Most low functions of CSocket class are packed in Winsock control, it is easy to use Winsock control in network communication program. 
Key Words: Winsock Control  LAN  VC++
 
 
 
马进(1971-),男,硕士,工程师,从事火电厂优化调度、锅炉仿真模型的研究。
单位:华北电力大学仿真控制技术实验室
通讯地址:河北保定市华北电力大学93#信箱
邮编:071003
EMAIL:MAJINWJ@SINA.COM;MAJIN@NCEPU.EDU.CN
电话:0312-7522048, 13831218862
 

posted on 2005-05-16 14:54  饽饽  阅读(5818)  评论(1编辑  收藏  举报