1. 程式人生 > >關於網路程式設計方面VB的WINSOCK程式設計

關於網路程式設計方面VB的WINSOCK程式設計

VB網路程式設計--WinSock控制元件及WinSockAPI

一,WinSock簡介
Socket(套接字)最初是由加利福尼亞大學Berkeley(伯克利)分校為UNIX媽作系統開發的網路通訊介面,隨著UNIX的廣泛使 用,Socket成為當前最流行的網路通訊應用程式介面之一。20世紀90年代初,由Sun Microsystems,JSB,FTP software,Microdyne和Microsoft等幾家公司共同定製了一套標準,即Windows Socket規範,簡稱WinSock。

VB編寫網路程式主要有兩種方式:1.winsock控制元件 2.winsockAPI


二,WinSock控制元件的使用
1.WinSock控制元件的主要屬性
a.Protocol屬性
通過Protocol屬性可以設定WinSock控制元件連線遠端計算機使用的協議。可選的協議是TCP和UDP對應的VB的常量分別是 sckTCPProtocol和sckUDPProtocol,Winsock控制元件預設協議是TCP。注意:雖然可以在執行時設定協議,但必須在連線未建 立或斷開連線後。

b.SocketHandle屬性
SocketHandle返回當前socket連線的控制代碼,這是隻讀屬性。

c.RemoteHostIP屬性
RemoteHostIP屬性返回遠端計算機的IP地址。在客戶端,當使用了控制元件的Connect方法後,遠端計算機的IP地址就賦給了 RemoteHostIP屬性,而在伺服器端,當ConnectRequest事件後,遠端計算機(客戶端)的IP地址就賦給了這個屬性。如果使用的是 UDP協議那麼當DataArrival事件後,傳送UDP報文的計算機的IP才賦給了這個屬性。

d.ByteReceived屬性
返回當前接收緩衝區中的位元組數

e.State屬性
返回WinSock控制元件當前的狀態

常數 值 描述
sckClosed 0 預設值,關閉。
SckOpen 1 開啟。
SckListening 2 偵聽
sckConnectionPending 3 連線掛起
sckResolvingHost 4 識別主機。
sckHostResolved 5 已識別主機
sckConnecting 6 正在連線。
sckConnected 7 已連線。
sckClosing 8 同級人員正在關閉連線。
sckError 9   錯誤


2.WinSock主要方法
a.Bind方法
用Bind方法可以把一個埠號固定為本控制元件使用,使得別的應用程式不能再使用這個埠。

b.Listen方法
Listen方法只在使用TCP協議時有用。它將應用程式置於監聽檢測狀態。

c.Connect方法
當本地計算機希望和遠端計算機建立連線時,就可以呼叫Connect方法。
Connect方法呼叫的規範為:
Connect RemoteHost,RemotePort

d.Accept方法
當伺服器接收到客戶端的連線請求後,伺服器有權決定是否接受客戶端的請求。

e.SendData方法
當連線建立後,要傳送資料就可以呼叫SendData方法,該方法只有一個引數,就是要傳送的資料。

f.GetData方法
當本地計算機接收到遠端計算機的資料時,資料存放在緩衝區中,要從緩衝區中取出資料,可以使用GetData方法。GetData方法呼叫規範如下:
GetData data,[type,][maxLen]
它從緩衝區中取得最長為maxLen的資料,並以type型別存放在data中,GetData取得資料後,就把相應的緩衝區清空。

g.PeekData方法
和GetData方法類似,但PeekData在取得資料後並不把緩衝區清空。


3.Winsock控制元件主要事件

a.ConnectRequest事件
當本地計算機接收到遠端計算機發送的連線請求時,控制元件的ConnectRequest事件將會被觸發。

b.SendProgress事件
當一端的計算機正在向另一端的計算機發送資料時,SendProgress事件將被觸發。SendProgress事件記錄了當前狀態下已傳送的位元組數和剩餘位元組數。

c.SendComplete事件
當所有資料傳送完成時,被觸發。

d.DataArrival事件
當建立連線後,接受到了新資料就會觸發這個事件。注意:如果在接受到新資料前,緩衝區中非空,就不會觸發這個事件。

e.Error事件
當在工作中發生任何錯誤都會觸發這個事件。

例子見附件



三,WinSockAPI的使用

1.WSAStartup 函式

為了在你的應用程式當中呼叫任何一個Winsock API 函式,首先第一件事情你就是必須通過WSAStartup函式完成對Winsock 服務的初始化,因此需要呼叫WSAStartup函式。

Declare Function WSAStartup Lib "ws2_32.dll" _
(ByVal wVersionRequired As Long, lpWSAData As WSAData) As Long

這個函式有兩個引數: wVersionRequired 和 lpWSAData。wVersionRequired 引數定義Windows Sockets 提供能使用的最高版本,它的高位位元組定義的是次版本號,低位位元組定義的是主版本號。下面的2個Winsock版本在VB中使用的例子:

初始化1.1版本

lngRetVal = WSAStartup(&H101, udtWinsockData)


初始化2.2版本

lngRetVal = WSAStartup(&H202, udtWinsockData)


第二個引數是WSADATA 的資料結構 ,它是接收Windows Sockets 執行時的資料。

Type WSAData
wVersion As Integer
wHighVersion As Integer
szDescription As String * WSADESCRIPTION_LEN
szSystemStatus As String * WSASYS_STATUS_LEN
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type

資料成員的描述在下表中:

Field 描述
wVersion Windows Sockets 版本資訊。
wHighVersion 通過載入庫檔案得到的最高的支援Winsock 的版本,
它通常和wVersion值相同。
szDescription Windows Sockets 執行時的詳細描述
szSystemStatus 包含了相關的狀態和配置的資訊
iMaxSockets 表示同時開啟的socket最大數,為0表示沒有限制。
iMaxUdpDg 表示同時開啟的資料報最大數,為0表示沒有限制。
lpVendorInfo 廠商指定資訊預留

在 Winsock的1.1和2.2版本中沒有lpVendorInfo的返回值。因為winsock 2支援多個傳輸協議,所以iMaxSockets 和iMaxUdpDg只能在僅支援TCP/TP的winsock1.1中使用。為了在Winsock 2中獲得這些值,你可以使用WSAEnumProtocols 函式。

如果成功或者返回一個錯誤程式碼,則函式返回 0。

錯誤程式碼 含義
WSASYSNOTREADY 指出網路沒有為傳輸準備好。
WSAVERNOTSUPPORTED 當前的WinSock實現不支援應用程式指定的Windows Sockets規範版本
WSAEINPROGRESS 一個阻塞WinSock呼叫正在進行
WSAEPROCLIM 請求的協議沒有在系統中配置或沒有支援它的實現存在。
WSAEFAULT lpWSAData 不是有效的指標



2.WSACleanup 函式

每次呼叫了WSAStartup函式,你都需要呼叫WSACleanup函式,通知系統來解除安裝庫檔案及清除已分配的資源,這個函式十分簡單,沒有任何引數:

Declare Function WSACleanup Lib "ws2_32.dll" () As Long


3.建立Socket函式

Declare Function socket Lib "ws2_32.dll" (ByVal af As Long, _
ByVal s_type As Long,
ByVal Protocol As Long) As Long

函式有3個引數定義建立何種socket,三個引數分別是:
Argument Description Enum Type
af Address family specification. AddressFamily
s_type Type specification for the new socket. SocketType
Protocol Protocol to be used with the socket SocketProtocol
that is specific to the indicated address
family.

AddressFamily:
AF_UNSPEC = 0 '/* unspecified */
AF_UNIX = 1 '/* local to host (pipes, portals) */
AF_INET = 2 '/* internetwork: UDP, TCP, etc. */
AF_IMPLINK = 3 '/* arpanet imp addresses */
AF_PUP = 4 '/* pup protocols: e.g. BSP */
AF_CHAOS = 5 '/* mit CHAOS protocols */
AF_NS = 6 '/* XEROX NS protocols */
AF_IPX = AF_NS '/* IPX protocols: IPX, SPX, etc. */
AF_ISO = 7 '/* ISO protocols */
AF_OSI = AF_ISO '/* OSI is ISO */
AF_ECMA = 8 '/* european computer manufacturers */
AF_DATAKIT = 9 '/* datakit protocols */
AF_CCITT = 10 '/* CCITT protocols, X.25 etc */
AF_SNA = 11 '/* IBM SNA */
AF_DECnet = 12 '/* DECnet */
AF_DLI = 13 '/* Direct data link interface */
AF_LAT = 14 '/* LAT */
AF_HYLINK = 15 '/* NSC Hyperchannel */
AF_APPLETALK = 16 '/* AppleTalk */
AF_NETBIOS = 17 '/* NetBios-style addresses */
AF_VOICEVIEW = 18 '/* VoiceView */
AF_FIREFOX = 19 '/* Protocols from Firefox */
AF_UNKNOWN1 = 20 '/* Somebody is using this! */
AF_BAN = 21 '/* Banyan */
AF_ATM = 22 '/* Native ATM Services */
AF_INET6 = 23 '/* Internetwork Version 6 */
AF_CLUSTER = 24 '/* Microsoft Wolfpack */
AF_12844 = 25 '/* IEEE 1284.4 WG AF */
AF_MAX = 26

Socket types:
SOCK_STREAM = 1 ' /* stream socket */
SOCK_DGRAM = 2 ' /* datagram socket */
SOCK_RAW = 3 ' /* raw-protocol interface */
SOCK_RDM = 4 ' /* reliably-delivered message */
SOCK_SEQPACKET = 5 ' /* sequenced packet stream */

Protocols:
IPPROTO_IP = 0 '/* dummy for IP */
IPPROTO_ICMP = 1 '/* control message protocol */
IPPROTO_IGMP = 2 '/* internet group management protocol */
IPPROTO_GGP = 3 '/* gateway^2 (deprecated) */
IPPROTO_TCP = 6 '/* tcp */
IPPROTO_PUP = 12 '/* pup */
IPPROTO_UDP = 17 '/* user datagram protocol */
IPPROTO_IDP = 22 '/* xns idp */
IPPROTO_ND = 77 '/* UNOFFICIAL net disk proto */
IPPROTO_RAW = 255 '/* raw IP packet */
IPPROTO_MAX = 256


該函式可以建立使用特定協議的網路套接字,例如對於UDP協議可以這樣寫:
s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)



4.關閉Socket函式

Declare Function closesocket Lib "ws2_32.dll" (ByVal s As Long) As Long

函式有一個引數為建立socket時的Handle




5.連線函式

Declare Function connect Lib "ws2_32.dll" (ByVal s As Long, _
ByRef name As sockaddr_in, _
ByVal namelen As Long) As Long

引數

s 連線的socket控制代碼。

name 建立連線的地址。

namelen 連線地址的長度。

返回值

成功時返回0。否則返回SOCKET_ERROR以及一個對應的錯誤號 Err.LastDllError。

顯 然在呼叫這個函式時我們需要知道socket控制代碼,將連線的電腦的埠號和主機名稱(或主機IP地址)。我們知道Winsock 控制元件的Connect方法依靠兩個變數:RemoteHost 和RemotePort。此方法不需要socket控制代碼,因其已經被封裝在COM物件中。你也許認為connect函式應該也接受相同的變數設定,然而, 事實並非如此。connect函式的主機地址和埠號的傳送是依靠 sockaddr_in 結構。

Public Type sockaddr_in
sin_family As Integer
sin_port As Integer
sin_addr As Long
sin_zero(1 To 8) As Byte
End Type




6.套接字幫定函式

Declare Function bind Lib "ws2_32.dll" (ByVal s As Long, _
ByRef name As sockaddr_in, _
ByRef namelen As Long) As Long



s是使用Socket函式建立好的套接字,name指向描述通訊物件的結構體的指標,namelen是該結構的長度。該結

構體中的分量包括:
IP地址:對應name.sin_addr.s_addr

埠號:對應name.sin_port
埠號用於表示同一臺計算機上不同的程序(即應用程式),其分配方法有兩種:
第一種分配方法是,程序讓系統為套接字自動分配一埠號,這隻要在呼叫bind前將埠號指定為0即可。由系統自動分配的埠號位於1024~5000之 間,而1~1023之間的任一TCP或UDP埠都是保留的,系統不允許任一程序使用保留埠,除非其有效使用者ID是零(即超級使用者)。
第二種分配方法是,程序為套接字指定一特定埠。這對於需要給套接字分配一眾所周知的埠的伺服器是很有用的。指定範圍在1024~65536之間。

地址型別:對應name.sin_family,一般都賦成AF_INET,表示是internet地址(即IP 地址)。IP地址通常使用點分表示法表示,但它事實上一個32位的長整數,這兩者之間可通過inet_addr()函式轉換。


7.套接字監聽函式

Declare Function listen Lib "ws2_32.dll" (ByVal s As Long, ByVal backlog As Long) As Long

listen函式用來設定Socket為監聽狀態,這種狀態表明Socket準備被連線了。注意,此函式一般在服務程式上使用,其中s是使用Socket函式建立好的套接字,backlog引數用於設定等待連線的客戶端數。



8.接受連線請求

Declare Function accept Lib "ws2_32.dll" (ByVal s As Long, ByRef addr As sockaddr_in, _
ByRef addrlen As Long) As Long


服務端應用程式呼叫此函式來接受客戶端Socket連線請求,accept()函式的返回值為一新的Socket,新Socket就可用來完成服務端和客戶端之間的資訊傳遞與接收,而原來Socket仍可以接受其他可戶端的連線請求。



9.接收資訊

Declare Function recv Lib "ws2_32.dll" (ByVal s As Long, _
ByRef buf As Any, _
ByVal buflen As Long, _
ByVal flags As Long) As Long


s 一個已連線的socket的識別符
buf 接受到的資料的緩衝區
len 緩衝區長度
flags 指定從哪呼叫的標識

第一個引數是socket的控制代碼-為socket函式返回值。那就是說:我們需要告訴recv函式,哪一個socket正訪問函式。

第 二個引數是:函式執行之後能裝載一些資料的緩衝區。但它不是必須要有足夠的長度接收Winsock緩衝區的所有資料,緩衝區的大小限制為8192 位元組 (8 Kbytes)。因此如果Winsock緩衝區的資料的大小大於recv函式的緩衝區,你必需多次呼叫此函式,直到獲取所有的資料。

如果應用程式定義緩衝區的長度,則recv函式必須知道緩衝區可以存放多少位元組。第三個引數就是為了這個目的。

最後一個引數是可選的,今天我們不使用。該引數有兩個選擇標誌: MSG_PEEK 和 MSG_OOB,用於改變函式的行為。

MSG_PEEK 從輸入資料中取數。資料拷入緩衝區,但不從輸入佇列中移走。函式返回當前準備接收的位元組數。
MSG_OOB 處理OOB(Out-of-band帶外)資料。在網路上有兩種型別的資料包,正常包和帶外包。帶外包可以通過檢驗一個TCP/IP包頭的一個特定標誌來決定。



10.傳送資訊

Declare Function send Lib "ws2_32.dll" (ByVal s As Long, _
ByRef buf As Any, _
ByVal buflen As Long, _
ByVal flags As Long) As Long


引數參看接收資訊




四,伺服器與客戶機互動

目前最常用的方法是:服務程式在一個眾所周知的地址(其中包括埠資訊)監聽對服務的請求,也就是說,服務程序一直處於休眠狀態,直到一個客戶對這個服務 的地址提出了連線請求。這個時刻,服務程式被喚醒並對客戶的請求作出適當的反應。注意,伺服器與客戶機之間的互動可以是面向連線的(基於流套接字),也可 以是無連線的(基於資料報套接字)
五,其他

比較:WinSock控制元件
優點:使用簡單,工作量小。
缺點:功能少僅支援TCP,UDP協議,需要WinSock控制元件(系統預設安裝不帶MSWINSCK.OCX檔案)
適合於初學者
WinSockAPI
優點:功能強大,支援多種協議,使用靈活,WinSockAPI呼叫的wsock32.dll(28K)或ws2_32.dll(69K)為Windows系統自帶函式庫不必擔心缺少檔案。
缺點:使用複雜,程式設計量大,需要一定基礎
適合於要求較高的網路程式