|
摘 要 介紹在VISCAL C++ 6.0 環(huán)境下,使用Winsock控件進(jìn)行網(wǎng)絡(luò)通訊的一種方法。Winsock控件的使用簡單,可以方便地應(yīng)用在使用VC++進(jìn)行編程的網(wǎng)絡(luò)通訊程序中。
關(guān)鍵詞 Winsock控件 局域網(wǎng) VC6.0
中圖分類號(hào): 文獻(xiàn)標(biāo)識(shí)碼: 文章編號(hào):
引言
隨著計(jì)算機(jī)技術(shù)的發(fā)展和網(wǎng)絡(luò)的不斷普及,網(wǎng)絡(luò)通訊程序的應(yīng)用越來越普遍,各種軟件開發(fā)平臺(tái)也為網(wǎng)絡(luò)通訊程序的開發(fā)提供了不同形式的類和控件。在利用Visual C++ 進(jìn)行開發(fā)時(shí),可以使用Csocket類;在利用Visucal Basic 進(jìn)行開發(fā)時(shí),可以使用Winsock 控件。有關(guān)Csocket類在VC中的使用和Winsock 控件在VB中使用,已經(jīng)有許多文章、資料進(jìn)行的介紹,這里不再贅述。同時(shí)也應(yīng)注意到,利用VC的CSocket類需要對(duì)網(wǎng)絡(luò)通訊的機(jī)制和參數(shù)有較深的了解,需要較深的計(jì)算機(jī)知識(shí)。雖然CSocket對(duì)Winsock進(jìn)行了封裝,但是它的函數(shù)調(diào)用仍然比較復(fù)雜,使用起來不容易。與此相反,在利用VB編程時(shí),各種控件的使用比較簡單,不需要許多的參數(shù)。利用VB中的Winsock 控件進(jìn)行開發(fā)比較容易,但VB本身的功能不如VC強(qiáng)大,在進(jìn)行開發(fā)時(shí)有時(shí)會(huì)受到一定程度的限制。在VC中利用Winsock控件的使用難度則介于上述二者之間,只需對(duì)少許一些參數(shù)做簡單設(shè)置即可。如果在用VC編制程序時(shí)需要進(jìn)行網(wǎng)絡(luò)通訊而又不想花費(fèi)過多的時(shí)間,在VC程序中插入Winsock控件是一種合適的方法。利用Winsock控件可以編制一個(gè)簡單的通訊程序,用于局域網(wǎng)之間的微機(jī)通訊。
一、Winsock控件的使用方法
1.1通訊協(xié)議的選擇
Winsock控件提供了訪問 TCP 和 UDP 網(wǎng)絡(luò)服務(wù)的方便途徑。采用TCP協(xié)議可以提供雙向的、可靠的、有序的和無重復(fù)投遞的數(shù)據(jù)流。TCP允許創(chuàng)建和維護(hù)與遠(yuǎn)程計(jì)算機(jī)的連接,連接兩臺(tái)計(jì)算機(jī)就可彼此進(jìn)行數(shù)據(jù)傳輸。用戶數(shù)據(jù)文報(bào)協(xié)議 (UDP) 是一個(gè)無連接協(xié)議。采用UDP協(xié)議,支持雙向的數(shù)據(jù)流,但不保證有序、可靠或無重復(fù)的投遞。但計(jì)算機(jī)并不建立連接。
在使用中,采用TCP協(xié)議的編程模型應(yīng)用最為廣泛,因?yàn)槊嫦蜻B接協(xié)議提供了一系列的數(shù)據(jù)糾錯(cuò)功能,可以保證在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)及時(shí)、無誤地到達(dá)對(duì)方,Internet上的多數(shù)服務(wù)(WWW、FTP、Telnet、SMTP)就是靠此協(xié)議運(yùn)轉(zhuǎn)的。采用UDP協(xié)議由于不用建立連接,傳輸比連接協(xié)議快,無數(shù)據(jù)糾錯(cuò)功能,不保證數(shù)據(jù)的可靠傳遞。在這里本文只介紹使用TCP/IP協(xié)議進(jìn)行編程的方法。
1.2使用方法和主要函數(shù)
Winsock控件的使用方法和步驟如下圖所示。
1.2.1 VARIANT類型變量的使用
Winsock控件使用的一個(gè)特殊的數(shù)據(jù)類型為VARIANT結(jié)構(gòu),其中vt的值類型說明了它所存儲(chǔ)的數(shù)據(jù),vt的幾個(gè)主要的值類型及值域?yàn)椋?span lang=EN-US>
類型 值域 說明
vt=VT_BSTR bstrVal 字符串類型
vt=VT_I2 Ival 整數(shù)類型
vt=VT_ERROR scode 錯(cuò)誤代碼
在使用之前,應(yīng)對(duì)VARIANT變量的類型和值域進(jìn)行賦值。一般的使用方法為:
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程序使用的主要函數(shù)
Bind()函數(shù)指定用于 TCP 連接的 LocalPort 和 LocalIP。
Listen()函數(shù)設(shè)置偵聽模式。該方法僅適用于 TCP 連接。
Accept()在處理 ConnectionRequest 事件時(shí)用這個(gè)方法接受新連接。
SendData()用于數(shù)據(jù)的發(fā)送。
Close()關(guān)閉與對(duì)方的連接。
1.2.3Client程序使用的主要函數(shù)
Connect()要求連接到遠(yuǎn)程計(jì)算機(jī)。
GetData()得到遠(yuǎn)程計(jì)算機(jī)上的數(shù)據(jù)。
二、使用Winsock控件的局域網(wǎng)通訊程序
2.1 Server程序
利用ClassWizard建立一個(gè)ServerDemo程序,注意選擇SDI,支持ActiveX,將View類設(shè)為CFormView類, 從Project->Add File->Compont and Control, 在對(duì)話框中選Registered ActiveX,選擇Microsoft WinSock Control ,點(diǎn)擊Insert按鈕,依照缺省設(shè)置即可。這樣在工程文件中會(huì)出現(xiàn)mswinsockcontrol類編輯ServerDemo程序的主對(duì)話框,可以看到在控件面版上出現(xiàn)mswinsockcontrol類的控件。在對(duì)話框中加入控件和相應(yīng)的變量,如表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的構(gòu)造函數(shù)中加入:
localport.vt=VT_BSTR;
localip.vt=VT_BSTR;
strport="4000";
strip="128.1.0.139";//在程序中應(yīng)將“128.1.25.240”設(shè)為自己server
//的IP地址
vtCommand.vt=VT_BSTR;
m_command="Server Send";
vtData.vt=VT_BSTR;
vtType.vt=VT_ERROR;
(3)利用ClassWizar映射OnInitialUpdate()的響應(yīng):在其中加入代碼:
localport.bstrVal=strport.AllocSysString();
localip.bstrVal=strip.AllocSysString();
m_server.Bind(localport, localip);
m_server.Listen();
(4)利用ClassWizar響應(yīng)IDC_WINSOCK1的ConnectionRequest事件,在OnConnectionRequestWinsock1()中加入代碼:
if(m_connect.GetState()==0 )
m_connect.Accept(requestID);
else
AfxMessageBox("no more connects",MB_OK);
(5)利用ClassWizar映射ID_SEND的動(dòng)作:OnSend(),在其中加入代碼:
m_edit.GetWindowText(m_command);
vtCommand.bstrVal=m_command.AllocSysString();
m_connect.SendData(vtCommand);
(6)利用ClassWizar響應(yīng)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響應(yīng)ID_WINSOCK2的Close()事件,在OnCloseWinsock2()中加入代碼:
m_connect.Close();
(8)在DestroyWindow() 中加入:
m_server.Close();
m_connect.Close();
2.2 Client程序
利用ClassWizard建立一個(gè)ClientDemo程序,注意選擇SDI,支持ActiveX,將View類設(shè)為CFormView類, 從Project->Add File->Compont and Control, 在對(duì)話框中選Registered ActiveX,選擇Microsoft WinSock Control ,點(diǎn)擊Insert按鈕,依照缺省設(shè)置即可。這樣在工程文件中會(huì)出現(xiàn)mswinsockcontrol類。編輯ClientDemo程序的主對(duì)話框,可以看到在控件面版上出現(xiàn)mswinsockcontrol類的控件。在對(duì)話框中加入控件和相應(yīng)的變量,如表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的構(gòu)造函數(shù)中加入:
m_host=_T("Room312");//在程序中將“Room312”設(shè)為自己server的主機(jī)
//名
m_port=_T("4000"); //端口設(shè)為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的動(dòng)作:在OnConnect()中加入代碼:
m_socket.SetRemoteHost("Room312");//在程序中將“Room312”設(shè)為自己
//server的主機(jī)名
m_socket.SetRemotePort(4000);
vtHost.bstrVal=m_host.AllocSysString();//見CString類字符串轉(zhuǎn)化為
//系統(tǒng)字符串
vtPort.bstrVal=m_port.AllocSysString();
m_socket.Connect(vtHost,vtPort);
if(m_socket.GetState()==0) //如果m_socket已經(jīng)斷開連接,將connect
//設(shè)置為可用
m_connect.EnableWindow(true);
else
m_connect.EnableWindow(false);
(4)利用ClassWizar映射ID_SEND的動(dòng)作:在OnSend:
m_edit.GetWindowText(m_command);
vtCommand.bstrVal=m_command.AllocSysString();
m_socket.SendData(vtCommand);
(5)利用ClassWizar響應(yīng)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響應(yīng)ID_WINSOCK1的Close事件,在OnCloseWinsock1()中加入代碼:
m_socket.Close();
if(m_socket.GetState()==0)
m_connect.EnableWindow(true);
else
m_connect.EnableWindow(false);
三、程序演示及結(jié)論
將上述程序分別編輯、連接為執(zhí)行程序,生成serverdemo.exe和clientdemo.exe文件。確認(rèn)程序中主機(jī)名和IP地址無誤。如果計(jì)算機(jī)沒有連網(wǎng),可以在程序中使用本機(jī)的主機(jī)名和IP地址。首先運(yùn)行serverdemo.exe。它自動(dòng)進(jìn)入到監(jiān)聽狀態(tài)。隨后運(yùn)行clientdemo.exe,點(diǎn)擊connect按鈕。如果client與server 連接成功,connect按鈕變?yōu)榛疑ú豢捎茫_B接成功后,在編輯框中輸入文字,點(diǎn)擊send按鈕,在serverdemo程序的編輯框中可以看到clientdemo程序發(fā)送的文字。同樣,在serverdemo的編輯框中輸入文字,點(diǎn)擊send按鈕,在clientdemo程序的編輯框中可以看到serverdemo程序發(fā)送的文字。
通過上述程序可以看到,同MFC的Csocket類相比,Winsock控件的使用簡單方便。程序中并未涉及Winsock最基本的API函數(shù)以及TCP/IP的相關(guān)知識(shí),編程簡單明了,是在VC++程序中進(jìn)行網(wǎng)絡(luò)通訊的一種簡便方法。
參考文獻(xiàn)
1.Visual C++(第四版) 原著David J. Kruglinshi 潘愛民 王國印譯 機(jī)械工業(yè)出版社 1999.1
2.Visual C++ 6開發(fā)使用指南 (美)Kate Gregory 著 前導(dǎo)工作室譯 機(jī)械工業(yè)出版社 1999
|