MFC 网络编程 -- 总结
生活随笔
收集整理的這篇文章主要介紹了
MFC 网络编程 -- 总结
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原文鏈接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html
1.基于 TCP 的 socket 編程
/* 服務器端程序流程: 1.加載套接字庫 WSAStartup 2.創(chuàng)建套接字 socket 3.將我們創(chuàng)建的套接字,綁定到本機地址的某一端口上 bind 4.為套接字設置監(jiān)聽模式,準備客戶請求 listen 5.等待客戶請求到來。當請求到來,將接受連接請求,并返回一個新的對應于此次連接的套接字 accept 6.用新返回的套接字和客戶端進行通信 send / recv 7.在通信結束后,關閉套接字 closesocket客戶端程序流程: 1.加載套接字庫 WSAStartup 2.創(chuàng)建套接字 socket 3.向服務器發(fā)出請求連接 connect 4.和服務器進行通信 send / recv 5.在通信結束后,關閉套接字 closesocket */服務器端代碼:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加載套接字庫,并進行套接字的版本協(xié)商 WORD wVersionRequested; // 指定將要加載的 winsock 庫版本 WSADATA wsaData; // 用于存儲加載的 winsock 庫版本信息 int result; // 用于檢測 WSAStartup 函數(shù)運行結果 wVersionRequested = MAKEWORD(1, 1); // 設定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函數(shù) WSAStartup 調用成功返回 0 // 出錯處理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 創(chuàng)建套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // 綁定套接字 SOCKADDR_IN addrInfo; // 存儲本地主機地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主機地址 addrInfo.sin_port = htons(6000); // 端口號 addrInfo.sin_family = AF_INET; // 地址族 bind(sock, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 設置套接字監(jiān)聽模式 listen(sock, 5); SOCKADDR_IN addrInfoClient; // 存儲客戶端地址信息 int len = sizeof(SOCKADDR); while (true) { // 等待客戶請求到來,并返回用于通信的套接字 SOCKET sockConnect = accept(sock, (SOCKADDR *)&addrInfoClient, &len); // 下面通過剛建立的套接字,來進行通信 // 發(fā)送數(shù)據(jù) char sendBuf[100]; sprintf(sendBuf, "這是服務器端,主機地址:%s", inet_ntoa(addrInfo.sin_addr)); send(sockConnect, sendBuf, strlen(sendBuf), 0); // 接收數(shù)據(jù) char recvBuf[100]; recv(sockConnect, recvBuf, strlen(recvBuf), 0); // 打印接收的數(shù)據(jù) printf("%s\n", recvBuf); closesocket(sockConnect); } }客戶端代碼:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib,"Ws2_32.lib") void main() { // 加載套接字庫,并進行套接字的版本協(xié)商 WORD wVersionRequested; // 指定將要加載的 winsock 庫版本 WSADATA wsaData; // 用于存儲加載的 winsock 庫版本信息 int result; // 用于檢測 WSAStartup 函數(shù)運行結果 wVersionRequested = MAKEWORD(1, 1); // 設定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函數(shù) WSAStartup 調用成功返回 0 // 出錯處理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 創(chuàng)建套接字 SOCKET sockConnect = socket(AF_INET, SOCK_STREAM, 0); // 向服務器發(fā)出連接請求 SOCKADDR_IN addrInfoServer; // 存儲服務器端地址信息 addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrInfoServer.sin_port = htons(6000); addrInfoServer.sin_family = AF_INET; // 向服務器發(fā)出連接請求 connect(sockConnect, (SOCKADDR *)&addrInfoServer, sizeof(SOCKADDR)); // 接收數(shù)據(jù) char recvBuf[100]; recv(sockConnect, recvBuf, sizeof(recvBuf), 0); printf("%s\n", recvBuf); // 發(fā)送數(shù)據(jù) char sendBuf[100] = "這是客戶端\n"; send(sockConnect, sendBuf, sizeof(sendBuf) + 1, 0); //關閉套接字 closesocket(sockConnect); WSACleanup(); system("pause"); return; }2. 基于 UDP 無連接的 socket 編程
/*服務端程序流程: 1.加載套接字庫 WSAStartup 2.創(chuàng)建套接字 socket 3.將創(chuàng)建的套接字綁定到一個本地地址和端口上 bind 4.等待接收數(shù)據(jù)。后與客戶端實現(xiàn)實時交流 recvfrom / sendto 5.關閉套接字 closesocket客戶端程序流程: 1.加載套接字庫 WSAStartup 2.創(chuàng)建套接字 socket 3.向服務器發(fā)送數(shù)據(jù).后與服務端實現(xiàn)實時交流 recvfrom / sendto 4.關閉套接字 closesocket*/服務器端代碼:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加載套接字庫,并進行套接字的版本協(xié)商 WORD wVersionRequested; // 指定將要加載的 winsock 庫版本 WSADATA wsaData; // 用于存儲加載的 wdnsock 庫版本信息 int result; // 用于檢測 WSAStartup 函數(shù)運行結果 wVersionRequested = MAKEWORD(1, 1); // 設定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函數(shù) WSAStartup 調用成功返回 0 // 出錯處理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 創(chuàng)建用于套接字 SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 綁定套接字 SOCKADDR_IN addrInfo; // 存儲本地主機地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主機地址 addrInfo.sin_port = htons(6000); // 端口號 addrInfo.sin_family = AF_INET; // 地址族 bind(sockConnect, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 等待接收數(shù)據(jù) char recvBuf[100]; // 接收數(shù)據(jù)緩沖 char sendBuf[100]; // 發(fā)送數(shù)據(jù)緩沖 char tempBuf[200]; SOCKADDR_IN addrInfoClient; // 存儲客戶端地址信息 int len = sizeof(SOCKADDR); while (true) { recvfrom(sockConnect, recvBuf, strlen(recvBuf), 0, (SOCKADDR *)&addrInfoClient, &len); if ('q' == recvBuf[0]) { sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrInfoClient, len); printf("聊天結束"); break; } sprintf(tempBuf, "%s 說:%s", inet_ntoa(addrInfoClient.sin_addr), recvBuf); printf("%s\n", tempBuf); // 發(fā)送數(shù)據(jù) printf("我說:"); gets(sendBuf); sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrInfoClient, len); } // 關閉套接字 closesocket(sockConnect); WSACleanup(); }客戶端代碼:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加載套接字庫,并進行套接字的版本協(xié)商 WORD wVersionRequested; // 指定將要加載的 winsock 庫版本 WSADATA wsaData; // 用于存儲加載的 wdnsock 庫版本信息 int result; // 用于檢測 WSAStartup 函數(shù)運行結果 wVersionRequested = MAKEWORD(1, 1); // 設定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函數(shù) WSAStartup 調用成功返回 0 // 出錯處理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 創(chuàng)建套接字 SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 向服務器發(fā)送數(shù)據(jù) SOCKADDR_IN addrInfoServer; // 存儲服務器地址信息 addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 指定服務器地址 addrInfoServer.sin_port = htons(6000); // 端口號 addrInfoServer.sin_family = AF_INET; // 地址族 int len = sizeof(SOCKADDR); char recvBuf[100]; // 接收數(shù)據(jù)緩沖 char sendBuf[100]; // 發(fā)送數(shù)據(jù)緩沖 char tempBuf[200]; while (true) { // 發(fā)送數(shù)據(jù) printf("我說:"); gets(sendBuf); sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrInfoServer, len); // 等待并接收數(shù)據(jù) recvfrom(sockConnect,recvBuf, strlen(recvBuf), 0, (SOCKADDR*)&addrInfoServer, &len); if ('q' == recvBuf[0]) { sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrInfoServer, len); printf("聊天結束"); break; } sprintf(tempBuf, "%s 說:%s", inet_ntoa(addrInfoServer.sin_addr), recvBuf); printf("%s\n", tempBuf); } // 關閉套接字 closesocket(sockConnect); WSACleanup(); }3.其他
vc網(wǎng)絡編程常用類型解析: 1. SOCKET 類型 SOCKET 是 socket 套接字類型,在 WINSOCK2.H 中有如下定義: typedef unsigned u_int; typedef u_int SOCKET; 可知套接字實際上就是一個無符號整形,它將被 Socket 環(huán)境管理和使用。 套接字將被創(chuàng)建、設置、用來發(fā)送和接收數(shù)據(jù),最后會被關閉。 2.WORD 類型、MAKEWORD、LOBYTE、HIBYTE 宏 WORD 類型是一個 16 位的無符號整型, 在 WTYPES.H 中被定義為: typedef unsigned short WORD; 其目的是提供兩個字節(jié)的存儲, 在 Socket 中這兩個字節(jié)可以表示主版本號和副版本號。 使用 MAKEWORD 宏可以給一個 WORD 類型賦值。例如要表示主版本號 2, 副版本號 0,可以使用如下代碼: WORD wVersionRequested; wVersionRequested = MAKEWORD(2, 0); 注意低位內存存儲主版本號 2, 高位內存存儲副版本號 0,其值為 0x0002。 使用宏 LOBYTE 可以讀取 WORD 的低位字節(jié), HIBYTE 可以讀取高位字節(jié)。 3.WSADATA 類型和 LPWSADATA 類型 WSADATA 類型是一個結構,描述了 Socket 庫的一些相關信息,其結構定義如下: typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN + 1]; char szSystemStatus[WSASYS_STATUS_LEN + 1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR* lpVendorInfo; }WSADATA; typedef WSADATA FAR* LPWSADATA; 值得注意的是 wVersion 字段,存儲了 Socket 的版本類型。LPWSADATA 是 WSADATA 的指針類型。 他們通過 Socket 的初始化函數(shù) WSAStartup 讀取出來。 //// vc網(wǎng)絡編程常用函數(shù)解析: 1. WSAStartup 函數(shù) 用于初始化 Socket 環(huán)境,函數(shù)原型: int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 其返回值為整型,調用方式為 PASCAL (即標準類型,PASCAL 等于__stdcall),參數(shù)有兩個, 第一個參數(shù)為 WORD 類型,指明了 Socket 的版本號,第二個參數(shù)為 LPWSADATA,指向一個用于存儲 Socket 庫信息的WSAStartup結構。 返回值: 返回值為0,則初始化成功,若不為0則為失敗。 2.WSACleanup 函數(shù) 這是 Socket 環(huán)境的退出函數(shù),函數(shù)原型: int WSACleanup (void); 返回值: 返回值為0表示成功,SOCKET_ERROR 表示失敗。 3.socket 函數(shù) socket 套接字的創(chuàng)建函數(shù),函數(shù)原型: SOCKET socket(int af, int type, int protocol ); 第一個參數(shù)為:int af, 代表網(wǎng)絡地址族,目前只有一種取值有效,即 AF_INET, 代表 internet 地址族; 第二個參數(shù)為:int type, 代表網(wǎng)絡協(xié)議類型, SOCK_DGRAM 代表 UDP 協(xié)議, SOCK_STREAM 代表 TCP 協(xié)議。 第三個參數(shù)為:int protocol,指定網(wǎng)絡地址族特殊協(xié)議,目前無用,賦值0即可。 返回值: 返回值為 SOCKET, 若返回INVALID_SOCKET 則失敗。 4.bind 函數(shù) 用于將套接字綁定到一個已知地址上,函數(shù)原型: int bind(SOCKET s, const struct sockaddr FAR *name, int namelen); 第一個參數(shù)為:SOCKET s, 指定將被綁定的套接字。 第二個參數(shù)為:SOCKADDR_IN *name, 是一個sockaddr結構指針,該結構中包含了要綁定的地址和端口。 第三個參數(shù)為:int namelen, 確定第二個參數(shù)的結構長度。 返回值: 成功返回0,失敗返回SOCKET_ERROR。 /// 下面對其涉及的類型作一番解析: sockaddr 類型: sockaddr 類型是用來表示 Socket 地址的類型,同上面的 socketaddr_in 類型相比,sockaddr 的適用范圍更廣, 因為sockeaddr_in只適用于 TCP/IP 地址。sockaddr 的定義如下: struct sockaddr { ushort sa_family; char sa_data[14]; }; 可知sockaddr 的16個字節(jié),而sockaddr_in也有16個字節(jié),所以sockaddr_in是可以強制類型轉換為sockadddr的。 事實上也往往使用這種方法。 sockaddr_in 定義了socket發(fā)送和接收數(shù)據(jù)包的地址,其定義如下: strucr sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; 其中 in_addr 定義如下: struct in_addr { union { struct {u_char s_b1, s_b2, s_b3, s_b4} S_un_b; struct {u_short s_w1, s_w2} S_un_w; u_long S_addr; }S_un; }; 首先闡述 in_addr 的信義。 很顯然它是一個存儲 ip 地址的聯(lián)合體,有三種表達方式: 第一種用四個字節(jié)來表示IP地址的四個數(shù)字; 第二種用兩個雙字節(jié)來表示IP地址; 第三種用一個長整型來表示IP地址; 給 in_addr 賦值的一種最簡單方法是使用 inet_addr 函數(shù), 它可以把一個代表IP地址的字符串賦值 轉換為in_addr類型。如: addrServer.sin_addr = inet_addr("192.168.0.2"); 其反函數(shù)是 inet_ntoa,可以把一個 in_addr 類型轉換為一個字符串。 sockaddr_in的含義比in_addr的含義要廣泛,其各個字段的含義和取值如下: 第一字段 short sin_family,代表網(wǎng)絡地址族,如前所述,只能取值AF_INET; 第二字段 u_short sin_port, 代表IP地址端口,由程序員指定; 第三字段 struct in_addr sin_addr, 代表IP地址; 第四個字段char sin_zero[8],是為了保證sockaddr_in與SOCKADDR類型的長度相等而填充進來的字段。 5.listen 函數(shù) 該函數(shù)讓一個套接字在指定IP地址的指定端口處監(jiān)聽連接請求的到來,函數(shù)原型: int listen( SOCKET s, int backlog ); 該函數(shù)使得一個進程可以接受其他進程的請求,從而成為一個服務器進程。 在TCP服務器編程中l(wèi)isten函數(shù)把進程變?yōu)橐粋€服務器,并指定相應的套接字變?yōu)楸粍舆B接。 listen 函數(shù)一般在調用bind之后、調用accept之前調用。 返回值: 成功則返回0,失敗返回SOCKET_ERROR,可以調用函數(shù)WSAGetLastError來取得錯誤代碼。 6.accept函數(shù) 該函數(shù)從連接請求隊列中獲得連接信息,并創(chuàng)建新的套接字用于收發(fā)數(shù)據(jù),實現(xiàn)服務器與客戶端的通信。函數(shù)原型: SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); 第一個參數(shù):SOCKET s, 監(jiān)聽套接字 第二個參數(shù):struct sockaddr addr, 存儲請求連接的客戶端IP地址、端口信息 第三個參數(shù):int addrlen,第二個參數(shù)所占空間大小 返回值: 成功返回新套接字,失敗返回錯誤信息 7.connect 函數(shù) 向指定的網(wǎng)絡主機請求連接,函數(shù)原型: int connect(SOCKET s, const struct sockaddr FAR *name, int namelen); 第一個參數(shù):SOCKET s, 客戶端用于收發(fā)數(shù)據(jù)的套接字。 第二個參數(shù):struct sockaddr *name, 指定網(wǎng)絡主機IP地址和端口號。 第三個參數(shù):int namelen, 第二參數(shù)長度 返回值: 成功返回0,失敗返回-1。 8.sendto、recvfrom、send、recv函數(shù) 在 Socket 中有兩套發(fā)送和接收函數(shù)。一是sendto 和recvfrom; 二是send 和 recv。 前一套在函數(shù)參數(shù)中要指明地址(UDP協(xié)議), 而后一套需要先將套接字和一個地址綁定,然后直接發(fā)送和接收,不需綁定地址。 函數(shù)原型: int sendto( SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to, int tolen); int recvfrom(SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen); int send(SOCKET s,const char FAR *buf, int len, int flags); int recv(SOCKET s, char FAR *buf, int len, int flags); 第一個參數(shù): 套接字 第二個參數(shù): 數(shù)據(jù)指針 第三個參數(shù): 數(shù)據(jù)長度 第四個參數(shù): 收發(fā)數(shù)據(jù)方式的標識,如果不需要特殊要求可以設置為0,其他值可參考MSDN; 第五個參數(shù): 目標主機地址 第六個參數(shù): 地址的長度 返回值: 運行成功則返回收發(fā)數(shù)據(jù)的字節(jié)數(shù),失敗返回SOCKET_ERROR 9.closesocket 函數(shù) 關閉套接字,函數(shù)原型: int closesocket( SOCKET s ); 返回值: 成功返回0,失敗返回SOCKET_ERROR。轉載于:https://www.cnblogs.com/wuyuan2011woaini/p/5740975.html
總結
以上是生活随笔為你收集整理的MFC 网络编程 -- 总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 踩刹车启动发动机,启动后刹车踏板高度将?
- 下一篇: 蟑螂怎么处理