成人AV在线无码|婷婷五月激情色,|伊人加勒比二三四区|国产一区激情都市|亚洲AV无码电影|日av韩av无码|天堂在线亚洲Av|无码一区二区影院|成人无码毛片AV|超碰在线看中文字幕

VC 的網絡編程總結

使用VC 的網絡編程總結1.套接字編程原理1.1 Client/server通信模型1.2 Windows Sockets規(guī)范1.3 套接字1.3.1 套接字定義1.3.2分類1.3.3 套接字的作

使用VC 的網絡編程總結

1.套接字編程原理

1.1 Client/server通信模型

1.2 Windows Sockets規(guī)范

1.3 套接字

1.3.1 套接字定義

1.3.2分類

1.3.3 套接字的作用

1.3.4端口與地址

1.3.5 套接口屬性

2.基本的Windows Sockets API編程

2.1常用函數

2.2 TCP實例

2.3 UDP實例

2.4 Socket 通信阻塞的解決方法

3.MFC 下的Socket 編程的類

3.1 CAsyncSocket類

3.2 CSocket類

3.3 Windows Sockets:帶存檔的套接字的工作方式

3.4 流式套接字通信的操作順序

3.5 使用 CAsyncSocket 類

3.6 從套接字類派生

3.7 套接字通知

3.8 一個使用CSocket 類的網絡通信實例

3.8.1 服務器端應用程序設計(ServerDemo)

3.8.2 客戶端應用程序設計(項目名稱ClientDemo)

4.套接字的托管實現

4.1 System::Net ::Sockets 命名空間

4.2 實例:一個新郵件檢查器

1.套接字編程原理

一個完整的網間通信進程需要由兩個進程組成,并且只能用同一種高層協(xié)議。也就是說,不可能通信的一端用TCP ,而另一端用UDP 。一個完整的網絡信需要一個五元組來標識:協(xié)議、本地地址、本地端口號、遠端地址、遠端端口號。

1.1 Client/server通信模型

在客戶/服務器模式中我們將請求服務的一方稱為客戶(client ),將提供某種服務的一方稱為服務器(server )。

一個服務程序通常在一個眾所周知的地址監(jiān)聽對服務的請求,也就是說服務進程一直處于休眠狀態(tài),直到一個客戶對這個服務的地址提出了連接請求。在這個時刻,服務程序被“驚醒”并且為客戶提供服務—對客戶的請求作出適當的反應。雖然基于連接的服務是設計客戶機/服務器應用程序時的標準,但有些服務也是可以通過無連接的接口提供的。

客戶機/服務器的請求/響應過程示意圖如下所示。

,

圖1 客戶/服務器通信模型

通過上面的分析,我們不難理解一個一個完整的網絡應用程序包括客戶端和服務器兩個部分??蛻襞c服務器進程的作用是非對稱的,因此編碼不同。服務進程一般是等待客戶請求而啟動的,只要系統(tǒng)運行,該服務進程一直存在,直到終止或強迫終止。

1.2 Windows Sockets規(guī)范

Windows Sockets 規(guī)范是90年代初Microsoft 公司聯(lián)合其他幾家大公司共同制定的一套在Windows 下的二進制兼容網絡編程接口規(guī)范。它以U.C.Berkeley 大學BSD UNIX中流行的Socket 接口為基礎,主要在其上擴充了一組針對Windows 的擴展庫函數,增加了符合Windows 消息驅動特性的網絡事件異步選擇機制,以使程序員能夠充分利用Windows 消息驅動機制進行編程。

Windows Sockets 的用途是將基礎網絡抽象出來,這樣,您不必對網絡非常了解,并且您的應用程序可在任何支持套接字的網絡上運行。它為應用程序開發(fā)者定義了一套簡單統(tǒng)一的API ,并讓各家網絡軟件供應商共同遵守。

Windows Sockets規(guī)范從90年代初的1.0版本開始,經過不斷的完善和發(fā)展,目前已經有了Windows Sockets 2版本。值得注意的是,Microsoft 的MFC 庫現在只支持Windows Sockets 1版本,不支持Windows Sockets 2版本。

MFC 提供了兩個類用以封裝Windows Sockets API 。一個是CAsyncSocket 類,它主要是提供給那些具有一定網絡編程經驗,希望同時擁有Socket API編程的靈活性和類庫編程便利性的開發(fā)者的。另一個是CSocket 類,它由CAsyncSocket 類派生,它具有更高的抽象化,致力于簡化網絡編程所需的操作。

1.3 套接字

1.3.1 套接字定義

套接字是一個通信終結點,它是Sockets 應用程序用來在網絡上發(fā)送或接收數據包的對象。套接字具有類型,與正在運行的進程相關聯(lián),并且可以有名稱。目前,套接字一般只與使用網際協(xié)議組的同一“通信域”中的其他套接字交換數據。使用套接字的應用程序間通信模型如圖2所示。

圖2 套接字通信模型

1.3.2分類

可用的套接字類型有以下兩種:

1.3.2.1流式套接字 (stream )

流式套接字提供沒有記錄邊界的數據流,即字節(jié)流。字節(jié)流能確保以正確的順序無重

,

復地被送達。

客戶機圖3 流式套接字(有連接通信) 編程

1.3.2.2 數據報套接字 (UDP )

數據報套接字支持面向記錄的數據流,但不能確保能被送達,也無法確保按照發(fā)送順序或不重復。

服務器

創(chuàng)建并初始化套接字客戶機創(chuàng)建并初始化套接字

監(jiān)聽來自客戶機的請求

向服務器發(fā)出請求

進行處理

發(fā)送結果給客戶端

接收結果

關閉連接關閉連接

圖4 數據報套接字(無連接通信) 編程

“有序”指數據包按發(fā)送的順序送達。“不重復”指一個特定的數據包只能獲取一次。這兩種套接字都是雙向的,是可以同時在兩個方向上(全雙工)進行通信的數據流。

注意 在某些網絡協(xié)議下(如 XNS ),流可以面向記錄,即作為記錄流而非字節(jié)流。但在更常用的 TCP/IP 協(xié)議下,流為字節(jié)流。Windows Sockets 提供與基礎協(xié)議無關的抽象化級別。

1.3.3 套接字的作用

套接字的作用非常大,至少在下面三種通信上下文中如此:

● 客戶端/服務器模型。

● 對等網絡方案,如聊天應用程序。

● 通過讓接收應用程序將消息解釋為函數調用來進行遠程過程調用 (RPC)。

Remote Procedures Call

1.3.4端口與地址

在網絡上,一個套接字的標識主要借助于地址和端口來描述。

套接字的地址指該套接字所在計算機的網絡地址,可以為域名或IP 地址的形式。通常,創(chuàng)建套接字時不必指明網絡地址,只有在擁有多個網絡地址的機器時,才需要顯式指定一個網絡地址。

同一機器上可以運行多個網絡應用程序,每個應用程序都有自己的套接字用以進行網絡通信,此時如果只有地址標識套接字,則當一個通信包到達機器時,將無法確定究竟是哪

,

個應用程序的套接字需要接收此信息。由此增加了端口的概念,以協(xié)助區(qū)分同一機器上不同應用程序的套接字。

端口用于標識進程,同一機器上不同的網絡應用程序各有不同的端口,這樣,通過“網絡地址 端口號”的標識方法,便唯一標識了機器上的應用程序了。

某些端口是專門為公共服務保留的(Ftp:21,http:80),除非程序是要提供這些服務,否則應盡量避免使用這些端口。一般來說,端口1024以前的端口號都是系統(tǒng)保留的或是作為公共服務的,應盡量選擇大于1024的端口號,以避免沖突。 1.3.5 套接口屬性

套接口有一系列的屬性用于標識套接口的狀態(tài)等信息,它們的屬性如表1所示。

可以通過getsockopt()函數獲取套接口的屬性,也可以通過setsockopt()函數設置套接口的屬性。

2. 基本的Windows Sockets API編程

● 需要在程序中添加下面的包含語句:#include ● 使用vc 編譯時需添加編譯鏈接依賴項ws2_32.lib庫 ● 協(xié)議尋址

在winsock 中,應用程序通過sockaddr_in 結構來指定IP 地址和服務端口信息 sockaddr_in internetAddr; int nPortID=5320;

internetAddr.sin_family=AF_INET;

internet.sin_addr.s_addr=inet_addr(“202.202.42.88”); //INADDR_ANY internet.sin_port=htons(nPortID);

ip 地址不容易記憶,還提供了許多地址和名稱解析函數如gethostbyname,gethostbyaddr 等。 2.1常用函數

1)WSAStartup 調用windows Socket DLL 函數原型 int WSAStartup(

WORD wVersionRequested, //應用程序要求的sockets 版本

,

LPWSADATA lpWSAData //指向數據結構WSDATA 的指針, //得到windows Socket的具體信息

);

WSDA TA 定義如下:

typedef struct WSAData {

WORD wVersion;

WORD wHighVersion;

#ifdef _WIN64

unsigned short iMaxSockets;

unsigned short iMaxUdpDg;

char FAR * lpV endorInfo;

char szDescription[WSADESCRIPTION_LEN 1]; char szSystemStatus[WSASYS_STATUS_LEN 1]; #else

char szDescription[WSADESCRIPTION_LEN 1]; char szSystemStatus[WSASYS_STATUS_LEN 1]; unsigned short iMaxSockets;

unsigned short iMaxUdpDg;

char FAR * lpV endorInfo;

#endif

} WSADATA, FAR * LPWSADATA;

2)WSACleanup 結束對Windows Sockets DLL的調用

函數原型:int WSACleanup(void);

3)socket 用于建立Sockets 。

函數原型:SOCKET socket(

int af, //地址族,一般是AF_INET

int type , //socket類型,SOCK_STREAM或SOCK_DGRAM int protocol //協(xié)議類型,通常取值 0

);

4)closesocket 關閉套接字

函數原型:int closesocket(

SOCKET s //要關閉的套接字

);

5)bind 將一個本地地址和一個SOCKET 描述字連接起來

函數原型:int bind(

SOCKET s, //要綁定的套接字

const struct sockaddr FAR* name, //指向SOCKADDR 結構的地址 int namelen //地址結構的sizeof

)

Tcp/ip SOCKADDR結構

struct sockaddr{

unsigned short sa_family;

char sa_data[4];

};

,

struct sockaddr_in{

short sin_family;

unsigned short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

6)listen 設定socket 為監(jiān)聽狀態(tài)

函數原型:int listen(

SOCKET s, //進行監(jiān)聽的socket

int backlog //客戶端可以連接的請求個數

);

7)accept 接受一個socket 的連接請求,同時返回一個新的socket ,新的socket 用來在服務器與客戶端之間傳遞和接收信息。

函數原型:SOCKET accept(

SOCKET s, //處于監(jiān)聽狀態(tài)的socket

struct sockaddr FAR* addr, //將要接受地址的sockaddr 指針

int FAR* addrlen //地址的長度

);

8)connect 連接客戶端的socket 到指定的網絡服務器。連接成功后,客戶端用此socket 與服務器通信。

函數原型:int connect(

SOCKET s, //將要連接的socket

const struct sockaddr FAR* name, //目標socket 地址

int namelen //地址結構sizeof

);

9)recv 用于接收已經建立連接的socket 數據信息

函數原型:int recv(

SOCKET s,

char FAR* buf, //接收數據緩沖區(qū)

int len ,//緩沖區(qū)長度

int flags //有MSG_PEEK和 MSG_OOB

);

返回值:接收到的字節(jié)數

10)send 對已經建立連接的socket 發(fā)送數據信息

函數原型:int send(

SOCKET s,

char FAR* buf, //發(fā)送數據緩沖區(qū)

int len ,//緩沖區(qū)長度

int flags //有MSG_PEEK和 MSG_OOB

);

返回值:發(fā)送的字節(jié)數

11)WSAAsyncSelect 要求socket 在有事件發(fā)生時通知使用者,本函數將套接口設置成為非阻塞方式。

函數原型:int WSAAsyncSelect(

,

SOCKET s,

HWND hWnd, //接收網絡事件的窗口句柄

unsigned int wMsg,//發(fā)送給窗口的網絡事件消息

long lEvent //網絡消息

);

12)sendto 向目標地址發(fā)送數據信息

int sendto(

SOCKET s,

const char FAR * buf,

int len,

int flags,

const struct sockaddr FAR * to,

int tolen

);

13)recvfrom 接收目標地址傳來的數據信息

int recvfrom(

IN SOCKET s,

OUT char FAR * buf,

IN int len,

IN int flags,

OUT struct sockaddr FAR * from,

IN OUT int FAR * fromlen

);

2.2 TCP 實例

服務器端需要建立兩個套接字,一個用于監(jiān)聽連接請求,另一個用來與請求連接的套接字建立連接,實際的數據傳送是通過后一個套接字。而客戶端只需要一個套接字即可。

,

,

窗體版TCP server(阻塞式)

在stdafx.h 文件中加入 #include

//啟動TCP server 按鈕事件處理

void CTcpServerDlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知處理程序代碼

if (WSAStartup(0x0101,&ws)!=0)

{

m_edit1="WSAStartup() failed!";

UpdateData(false );

return ;

}

//創(chuàng)建套接字

servsock=socket(AF_INET,SOCK_STREAM,0);

//填充服務器地址結構

servport=5555;

memset(&sa,0,sizeof (sa));

sa.sin_family=AF_INET;

sa.sin_port=htons(servport);

sa.sin_addr.s_addr=inet_addr("202.202.42.88");

//綁定套接字到服務器地址結構

err=bind(servsock,(const sockaddr *)&sa,sizeof (sa)); if (err!=0)

{

m_edit1="Bind failed!";

UpdateData(false );

//監(jiān)聽套接字

err=listen(servsock,5);

if (err!=0)

{

m_edit1="Listen failed!";

UpdateData(false ); return ; }

,

return ;

}

m_edit1.SetString("Waiting request...");

UpdateData(false );

this ->RedrawWindow ();//如不調用此句,則在阻塞Socket 方式下窗體無法正常刷新 //等待連接請求

len=sizeof (cliaddr);

clisock=accept(servsock,(struct sockaddr *)&cliaddr,&len);

m_edit1.Format("Accept

Client:s:dn",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));

}

//發(fā)送消息事件處理

void CTcpServerDlg::OnBnClickedButton2()

{

//發(fā)送歡迎詞

send(clisock,buff,strlen(buff),0);

}

//關閉連接事件處理

void CTcpServerDlg::OnBnClickedButton3()

{

// TODO: 在此添加控件通知處理程序代碼 //關閉連接 m_edit1="Connection Closed!"; UpdateData(false ); // TODO: 在此添加控件通知處理程序代碼 sprintf(buff,"Welcome you s",inet_ntoa(cliaddr.sin_addr)); UpdateData(false );

closesocket(clisock);

closesocket(servsock);

WSACleanup();

}

標簽: