Windows Socket編程簡介

來源:互聯網
上載者:User

轉載地址:http://hi.baidu.com/huangfei564/blog/item/c8fc9c8e62b323fc503d9202.html

 

     

WinSock編程
使用WinSock API的編程,應該瞭解TCP/IP的基礎知識。雖然你可以直接使用WinSock API來寫網路應用程式,但是,要寫出優秀的網路應用程式,還是必須對TCP/IP協議有一些瞭解的。
1. TCP/IP協議與WinSock網路編程介面的關係
WinSock並不是一種網路通訊協定,它只是一個網路編程介面,也就是說,它不是協議,但是它可以訪問很多種網路通訊協定,你可以把他當作一些協議的封裝。現在的WinSock已經基本上實現了與協議無關。你可以使用WinSock來調用多種協議的功能。那麼,WinSock和TCP/IP協議到底是什麼關係呢?實際上,WinSock就是TCP/IP協議的一種封裝,你可以通過調用WinSock的介面函數來調用TCP/IP的各種功能.例如我想用TCP/IP協議發送資料,你就可以使用WinSock的介面函數Send()來調用TCP/IP的發送資料功能,至於具體怎麼發送資料,WinSock已經幫你封裝好了這種功能。
2、TCP/IP協議介紹
TCP/IP協議包含的範圍非常的廣,他是一種四層協議,包含了各種硬體、軟體需求的定義。 TCP/IP協議確切的說法應該是TCP/UDP/IP協議。UDP協議(User Datagram Protocol 使用者資料包通訊協定),是一種保護訊息邊界的,不保障可靠資料的傳輸。TCP協議(Transmission Control Protocol 傳輸控制通訊協定),是一種流傳輸的協議。他提供可靠的、有序的、雙向的、連線導向的傳輸。
保護訊息邊界,就是指傳輸協議把資料當作一條獨立的訊息在網上傳輸,接收端只能接收獨立的訊息。也就是說存在保護訊息邊界,接收端一次只能接收發送端發出的一個資料包。
而面向流則是指無保護訊息保護邊界的,如果發送端連續發送資料,接收端有可能在一次接收動作中,會接收兩個或者更多的資料包。
舉例來說,假如,我們連續發送三個資料包,大小分別是2k、4k、8k,這三個資料包都已經到達了接收端的網路堆棧中,如果使用UDP協議,不管我們使用多大的接收緩衝區去接收資料,我們必須有三次接收動作,才能夠把所有的資料包接收完。而使用TCP協議,我們只要把接收的緩衝區大小設定在14k以上,我們就能夠一次把所有的資料包接收下來,只需要有一次接收動作。
這就是因為UDP協議的保護訊息邊界使得每一個訊息都是獨立的。而流傳輸,卻把資料當作一串資料流,它不認為資料是一個一個的訊息。所以有很多人在使用TCP協議通訊的時候,並不清楚TCP是基於流的傳輸,當連續發送資料的時候,他們時常會認識TCP會丟包。其實不然,因為當他們使用的緩衝區足夠大時,他們有可能會一次接收到兩個甚至更多的資料包,而很多人往往會忽視這一點,只解析檢查了第一個資料包,而已經接收的其他據包卻被忽略了。
3.WinSock編程簡單流程
WinSock編程分為伺服器端和用戶端兩部分,TCP伺服器端的大體流程如下:
對於任何基於WinSock的編程首先必須要初始化WinSock DLL庫。
int WSAStarup( WORD wVersionRequested,LPWSADATA lpWsAData )。
wVersionRequested是我們要求使用的WinSock的版本。
調用這個介面函數可以初始化WinSock 。
然後必須建立一個通訊端(Socket)。
SOCKET Socket(int af,int type,int protocol);
通訊端可以說是WinSock通訊的核心。WinSock通訊的所有資料轉送,都是通過通訊端來完成的,通訊端包含了兩個資訊,一個是IP地址,一個是Port連接埠號碼,使用這兩個資訊,就可以確定網路中的任何一個通訊節點。
當調用了Socket()介面函數建立了一個通訊端後,必須把通訊端與你需要進行通訊的地址建立聯絡,可以通過綁定函數來實現這種聯絡。
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen) ;
struct sockaddr_in{
short sin_family ;
u_short sin_prot ;
struct in_addr sin_addr ;
char sin_sero[8] ;
}
就包含了需要建立串連的本地的地址,包括地址族、IP和連接埠資訊。sin_family欄位必須把它設為AF_INET,這是告訴WinSock使用的是IP地址族。sin_prot就是要用來通訊的連接埠號碼。sin_addr就是要用來通訊的IP地址資訊。
在這裡,必須還得提一下有關'大頭(big-endian)'小頭(little-endian)'。因為各種不同的電腦處理資料時的方法是不一樣的,Intel X86處理器上是用'小頭'形式來表示多位元組的編號,就是把低位元組放在前面,把高位元組放在後面,而互連網標準卻正好相反,所以,必須把主機位元組轉換成網路位元組的順序。WinSock API提供了幾個函數。
把主機位元組轉化成網路位元組的函數;
u_long htonl(u_long hostlong);
u_short htons(u_short hostshort);
把網路位元組轉化成主機位元組的函數;
u_long ntohl(u_long netlong);
u_short ntohs(u_short netshort) ;
這樣,設定IP地址和port連接埠時,就必須把主機位元組轉化成網路位元組後,才能用Bind()函數來綁定通訊端和地址。
當綁定完成之後,伺服器端必須建立一個監聽的隊列來接收用戶端的串連請求。
int listen(SOCKET s,int backlog);
這個函數可以把通訊端轉成監聽模式。
如果用戶端有了串連請求,我們還必須使用
int accept(SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
來接受用戶端的請求。
現在基本上已經完成了一個伺服器的建立,而用戶端的建立的流程則是初始化WinSock,然後建立Socket通訊端,再使用
int connect(SOCKET s,const struct sockaddr FAR* name,int namelen) ;
來串連服務端。
下面是一個最簡單的建立伺服器端和用戶端的例子:
伺服器端的建立:
WSADATA wsd;
SOCKET sListen;
SOCKET sclient;
UINT port = 800;
int iAddrSize;
struct sockaddr_in local , client;
WSAStartup( 0x11 , &wsd );
sListen = Socket ( AF_INET , SOCK_STREAM , IPPOTO_IP );
local.sin_family = AF_INET;
local.sin_addr = htonl( INADDR_ANY );
local.sin_port = htons( port );
bind( sListen , (struct sockaddr*)&local , sizeof( local ) );
listen( sListen , 5 );
sClient = accept( sListen , (struct sockaddr*)&client , &iAddrSize );
用戶端的建立:
WSADATA wsd;
SOCKET sClient;
UINT port = 800;
char szIp[] = "127.0.0.1";
int iAddrSize;
struct sockaddr_in server;
WSAStartup( 0x11 , &wsd );
sClient = Socket ( AF_INET , SOCK_STREAM , IPPOTO_IP );
server.sin_family = AF_INET;
server.sin_addr = inet_addr( szIp );
server.sin_port = htons( port );
connect( sClient , (struct sockaddr*)&server , sizeof( server ) );
當伺服器端和用戶端建立串連以後,無論是用戶端,還是伺服器端都可以使用
int send( SOCKET s,const char FAR* buf,int len,int flags);
int recv( SOCKET s,char FAR* buf,int len,int flags);
函數來接收和發送資料,因為,TCP串連是雙向的。
當要關閉通訊連結的時候,任何一方都可以調用
int shutdown(SOCKET s,int how);
來關閉通訊端的指定功能,再調用
int closeSocket(SOCKET s) ;
來關閉通訊端控制代碼,這樣一個通訊過程就算完成了。
注意:上面的代碼沒有任何檢查函數傳回值,如果你作網路編程就一定要檢查任何一個WinSock API函數的調用結果,因為很多時候函數調用並不一定成功。上面介紹的函數,傳回值類型是int的話,如果函數調用失敗的話,返回的都是SOCKET_ERROR。
4.WinSock編程的模型
上面介紹的僅僅是最簡單的WinSock通訊的方法,而實際中很多網路通訊的卻很多難以解決的意外情況。
例如,WinSock提供了兩種通訊端模式:鎖定和非鎖定。當使用鎖定通訊端的時候,使用的很多函數,例如accpet、send、recv等等,如果沒有資料需要處理,這些函數都不會返回,也就是說,你的應用程式會阻塞在那些函數的調用處。而如果使用非阻塞模式,調用這些函數,不管你有沒有資料到達,他都會返回。所以有可能我們在非阻塞模式裡,調用這些函數大部分的情況下會返回失敗,所以就需要我們來處理很多的意外出錯。
這顯然不是我們想要看到的情況。我們可以採用WinSock的通訊模型來避免這些情況的發生。
WinSock提供了五種通訊端I/O模型來解決這些問題。他們分別是select(選擇),WSAAsyncSelect(非同步選擇),WSAEventSelect (事件選擇,overlapped(重疊) , completion port(完成連接埠) 。
這裡詳細介紹一下select,WSAASyncSelect兩種模型。
Select模型是最常見的I/O模型。使用
int select( int nfds , fd_set FAR* readfds , fd_set FAR* writefds,fd_set FAR* exceptfds,const struct timeval FAR * timeout ) ;
函數來檢查你要調用的Socket通訊端是否已經有了需要處理的資料。
select包含三個Socket隊列,分別代表:
readfds ,檢查可讀性,writefds,檢查可寫性,exceptfds,例外資料。
timeout是select函數的返回時間。
例如,想要檢查一個通訊端是否有資料需要接收,我們可以把通訊端控制代碼加入可讀性檢查隊列中,然後調用select,如果,該通訊端沒有資料需要接收,select函數會把該通訊端從可讀性檢查隊列中刪除掉,所以我們只要檢查該通訊端控制代碼是否還存在於可讀性隊列中,就可以知道到底有沒有資料需要接收了。
WinSock提供了一些宏用來操作通訊端隊列fd_set。
FD_CLR( s,*set) 從隊列set刪除控制代碼s。
FD_ISSET( s, *set) 檢查控制代碼s是否存在與隊列set中。
FD_SET( s,*set )把控制代碼s添加到隊列set中。
FD_ZERO( *set ) 把set隊列初始化成空隊列。
WSAAsyncSelect(非同步選擇)模型:WSAASyncSelect模型就是把一個視窗和通訊端控制代碼建立起串連,通訊端的網路事件發生時時候,就會把某個訊息發送到視窗,然後可以在視窗的訊息響應函數中處理資料的接收和發送。
int WSAAsyncSelect( SOCKET s, HWND hWnd , unsigned int wMsg , long lEvent ) ;
這個函數可以把通訊端控制代碼和視窗建立起串連,
wMsg 是我們必須自訂的一個訊息。
lEvent就是制定的網路事件。包括FD_READ , FD_WRITE ,FD_ACCEPT,FD_CONNECT,FD_CLOSE 。幾個事件。
例如,需要接收FD_READ , FD_WRITE , FD_CLOSE 的網路事件。可以調用
WSAAsyncSelect( s , hWnd , WM_SOCKET , FD_READ | FD_WRITE | FD_CLOSE ) ;
這樣,當有FD_READ , FD_WRITE 或者 FD_CLOSE網路事件時,視窗hWnd將會收到WM_SOCKET訊息,訊息參數的lParam標誌了是什麼事件發生,MFC的CSocket類,就是使用這個模型。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.