国产成人毛片视频|星空传媒久草视频|欧美激情草久视频|久久久久女女|久操超碰在线播放|亚洲强奸一区二区|五月天丁香社区在线|色婷婷成人丁香网|午夜欧美6666|纯肉无码91视频

VC 的網(wǎng)絡(luò)編程總結(jié)

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

使用VC 的網(wǎng)絡(luò)編程總結(jié)

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常用函數(shù)

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 類的網(wǎng)絡(luò)通信實例

3.8.1 服務(wù)器端應(yīng)用程序設(shè)計(ServerDemo)

3.8.2 客戶端應(yīng)用程序設(shè)計(項目名稱ClientDemo)

4.套接字的托管實現(xiàn)

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

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

1.套接字編程原理

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

1.1 Client/server通信模型

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

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

客戶機/服務(wù)器的請求/響應(yīng)過程示意圖如下所示。

,

圖1 客戶/服務(wù)器通信模型

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

1.2 Windows Sockets規(guī)范

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

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

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

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

1.3 套接字

1.3.1 套接字定義

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

圖2 套接字通信模型

1.3.2分類

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

1.3.2.1流式套接字 (stream )

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

,

復(fù)地被送達。

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

1.3.2.2 數(shù)據(jù)報套接字 (UDP )

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

服務(wù)器

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

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

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

進行處理

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

接收結(jié)果

關(guān)閉連接關(guān)閉連接

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

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

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

1.3.3 套接字的作用

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

● 客戶端/服務(wù)器模型。

● 對等網(wǎng)絡(luò)方案,如聊天應(yīng)用程序。

● 通過讓接收應(yīng)用程序?qū)⑾⒔忉尀楹瘮?shù)調(diào)用來進行遠程過程調(diào)用 (RPC)。

Remote Procedures Call

1.3.4端口與地址

在網(wǎng)絡(luò)上,一個套接字的標識主要借助于地址和端口來描述。

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

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

,

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

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

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

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

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

2. 基本的Windows Sockets API編程

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

在winsock 中,應(yīng)用程序通過sockaddr_in 結(jié)構(gòu)來指定IP 地址和服務(wù)端口信息 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 地址不容易記憶,還提供了許多地址和名稱解析函數(shù)如gethostbyname,gethostbyaddr 等。 2.1常用函數(shù)

1)WSAStartup 調(diào)用windows Socket DLL 函數(shù)原型 int WSAStartup(

WORD wVersionRequested, //應(yīng)用程序要求的sockets 版本

,

LPWSADATA lpWSAData //指向數(shù)據(jù)結(jié)構(gòu)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 結(jié)束對Windows Sockets DLL的調(diào)用

函數(shù)原型:int WSACleanup(void);

3)socket 用于建立Sockets 。

函數(shù)原型:SOCKET socket(

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

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

);

4)closesocket 關(guān)閉套接字

函數(shù)原型:int closesocket(

SOCKET s //要關(guān)閉的套接字

);

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

函數(shù)原型:int bind(

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

const struct sockaddr FAR* name, //指向SOCKADDR 結(jié)構(gòu)的地址 int namelen //地址結(jié)構(gòu)的sizeof

)

Tcp/ip SOCKADDR結(jié)構(gòu)

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 設(shè)定socket 為監(jiān)聽狀態(tài)

函數(shù)原型:int listen(

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

int backlog //客戶端可以連接的請求個數(shù)

);

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

函數(shù)原型:SOCKET accept(

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

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

int FAR* addrlen //地址的長度

);

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

函數(shù)原型:int connect(

SOCKET s, //將要連接的socket

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

int namelen //地址結(jié)構(gòu)sizeof

);

9)recv 用于接收已經(jīng)建立連接的socket 數(shù)據(jù)信息

函數(shù)原型:int recv(

SOCKET s,

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

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

int flags //有MSG_PEEK和 MSG_OOB

);

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

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

函數(shù)原型:int send(

SOCKET s,

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

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

int flags //有MSG_PEEK和 MSG_OOB

);

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

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

函數(shù)原型:int WSAAsyncSelect(

,

SOCKET s,

HWND hWnd, //接收網(wǎng)絡(luò)事件的窗口句柄

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

long lEvent //網(wǎng)絡(luò)消息

);

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

int sendto(

SOCKET s,

const char FAR * buf,

int len,

int flags,

const struct sockaddr FAR * to,

int tolen

);

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

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 實例

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

,

,

窗體版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);

//填充服務(wù)器地址結(jié)構(gòu)

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");

//綁定套接字到服務(wù)器地址結(jié)構(gòu)

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 ();//如不調(diào)用此句,則在阻塞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);

}

//關(guān)閉連接事件處理

void CTcpServerDlg::OnBnClickedButton3()

{

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

closesocket(clisock);

closesocket(servsock);

WSACleanup();

}

標簽: