windows 網路編程學習-Winsock API

來源:互聯網
上載者:User
winsock  winsock是WIN32平台上提供的網路編程介面且與具體的網路通訊協定無關(也就是說支援多種網路通訊協定),它借鑒了Unix平台上的Berkeley(BSD)通訊端方案(Unix socket 編程和 Winsock 編程是很相似的)。雖然winsock與協議無關,但是在編程時我們還是要瞭解一下網路通訊協定的一些特徵,例如:面向訊息、連線導向與無串連、路由選擇等。面向訊息  這雷根據網路通訊協定的不同,可以將他們分為有訊息邊界和無訊息邊界保護的,通常把無訊息邊界保護的協議稱為“基於流的協議”。假設發送端發出數條不同大小的訊息如:128位元組、256位元組,而接受端將會兩次進行讀取每次讀取一個訊息的資料包,即使這些資料包已經全部搜到並存於網路堆棧中也是如此。我們熟悉的UDP協議發送的資料包,就是有訊息邊界保護的(同樣IP的資料報也是如此)。如果是在基於流的協議裡,由於訊息沒有保護邊界,系統可能將大的訊息分割或者將小的組合然後儘可能返回更多的資料。我們熟知的TCP協議就是基於流的。連線導向或無串連  一個連線導向的協議在資料交換之前會建立一個虛擬路徑,而且連線導向的協議通常還提供一定的可靠性保障服務(代價是維護串連需要開銷)。不需連線的協議只負責把資料直接投遞出去其他就不關了,比較像郵政的信件寄送,雖然缺乏可靠性但是其速度快。總所周知tcp協議是連線導向的,而UDP則是無連線協定。可以根據不同的情境和需求選擇使用哪種協議進行通訊。路由  路由器會將受到的非路由協議資料包全部丟掉(例如:NETBEUI協議)。如果我們設計的程式存在不同的網路(當然這些網路經由路由器串連著)我們就需要選擇可路由的協議,首推的當然是TCP/IP了。WSAStartup 函數  在使用winsock編程前需要先載入winSock庫,也就是調用WSAStartup函數(這是與Unix socket的最主要區別)。int WSAStartup(WORD wVersionRequested , LPWSADATA lpWSAData),該函數的第一個參數指明程式請求使用的Socket版本,其中高位位元組 指明副版本、低位位元組指明主要版本(可以利用宏MAKEWODE(2,0)獲得 wVersionRequested);作業系統利用第二個參數返回請求的Socket的版本資訊(有用的只有 wVersion和wHighVersion 這兩個而已)。當一個應用程式調用WSAStartup函數時,作業系統根 據請求的Socket版本來搜尋相應的Socket庫,然後綁定找到的Socket庫到該應用程式中。以後應用程式就可以調用所請求的Socket庫中的 其它Socket函數了,該函數執行成功後返回0。
1 wVersionRequested = MAKEWORD( 2, 2 ); 
2 err = WSAStartup( wVersionRequested, &wsaData );

我們來看看在.NET C#語言下是怎麼調用WSAStartup函數的,當然我們在使用C#是不需要顯示開啟winsock庫,.net幫我們封裝好了。用Reflector找到System.Net.Socket類(我的是.net3.5)。查看public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) 在裡面發現了這麼兩句話:

1   InitializeSockets();
2 this.m_Handle = SafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType);
3  

 其中.m_Handle是一個SafeCloseSocket類(其實祖先是 SafeHandle 類,另附:安全控制代碼和緊急終結),再看看InitializeSockets()方法發現了如下語句:

 if (UnsafeNclNativeMethods.OSSOCK.WSAStartup(0x202, out lpWSAData) != SocketError.Success)
{
throw new SocketException();
}

繼續跟蹤就可以發現:

[DllImport("ws2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
internal static extern SocketError WSAStartup([In] short wVersionRequested, out WSAData lpWSAData);

其中ws2_32.dll便是Windows Sockets應用程式介面的動態連結程式庫檔案,用DllImport的方式就可以使用這個WIN32 api了。所以當我們使用Socket類生產一個Socket執行個體時系統便會幫我們調用WSAStartup。WSACleanup  每次調用了WSAStartup都需要調用WSACleanup來釋放資源。WSAEnumProtocols函數  如果想知道系統裡安裝了哪些協議和這些協議的特性,可以調用int WSAEnumProtocols(lpdwProtocols,lpProtocolBuffer,lpdwBufferLength),通常需要兩次調用WSAEnumProtocols()函數以擷取特定的協議資訊,第一次調用時指定lpdwProtocols為 NULL,調用肯定是失敗的,但參數lpdwBufferLength包含了所有協議資訊需要的緩衝區長度。我們知道了這個準確長度就可以進行第二次調用了。WSASocket  winsock API 是建立在通訊端上的,通訊端其實就是一個控制代碼(C#層面上我們可看作是一個抽象的對象)。SOCKET WSASocket(int af,int type,int protocols,LPWSAProtocol_INFO lpprotocolInfo,GROUP g,DOWRD dwFlags) 使用這個函數我們就可以建立通訊端了

  • af:地址族描述。如果想建立UDP或TCP的通訊端,可以使用 AF_INET來指定互連網協議
  • type:新套介面的類型描述。它可以是:SOCKSTREAM、SOCKDGRAM、SOCKSEQPACKET、SOCKRAW和SOCKRDM。
  • protocol:套介面使用的特定協議,如果調用者不願指定協議則定為0,需要注意的是protocol 和 type是由一定對應關係的
  • lpProtocolInfo:一個指向PROTOCOL_INFO結構的指標,該結構定義所建立套介面的特性。如果本參數非零,則前三個參數(af, type, protocol)被忽略。
  • g:套介面組的描述字。
  • iFlags:套介面屬性描述。

還記得在.NET C#語言下是怎麼調用WSAStartup函數的嗎? 在 SafeCloseSocket 裡找到了InnerSafeCloseSocket類

internal class InnerSafeCloseSocket : SafeHandleMinusOneIsInvalid
{
// Fields
private bool m_Blockable;
private static readonly byte[] tempBuffer;

// Methods
static InnerSafeCloseSocket();
protected InnerSafeCloseSocket();
internal static SafeCloseSocket.InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal void BlockingRelease();
internal static unsafe SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(byte* pinnedBuffer);
internal static SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
protected override bool ReleaseHandle();

// Properties
public override bool IsInvalid { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get; }
}

我們看看 SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket() 方法是如何?的:

internal static SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
SafeCloseSocket.InnerSafeCloseSocket socket = UnsafeNclNativeMethods.OSSOCK.WSASocket(addressFamily, socketType, protocolType, IntPtr.Zero, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
if (socket.IsInvalid)
{
socket.SetHandleAsInvalid();
}
return socket;
}

可看到在OSSock 類裡有以下引用:

代碼

[DllImport("ws2_32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern SafeCloseSocket.InnerSafeCloseSocket WSASocket([In] AddressFamily addressFamily, [In] SocketType socketType, [In] ProtocolType protocolType, [In] IntPtr protocolInfo, [In] uint group, [In] SocketConstructorFlags flags);



 

不過令我意外的是 這個OSSOCKET 竟然是在UnsafeNclNativeMethods 下的,這個難道是不安全的嗎? 能找到的UnsafeNclNativeMethods的資料不多(哪位大牛知道希望指點指點),我對.net的 GC機制也只是知道其意思,而不知道其具體是怎麼實現的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.