C++中的IPv6网络程序设计
生活随笔
收集整理的這篇文章主要介紹了
C++中的IPv6网络程序设计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
IPv4?最初是由美國國防部開發的用于網際互聯(IP)協議,后來它不僅發展了TCP,而且還進一步發展了IPv4(IP?協議4.0版)。IPv4現在已經廣泛應用于Internet網絡中,同時也應用于大多數計算機系統,局域網和廣域網中。然而,隨著Internet?中的計算機數量突飛猛漲,IPv4?的局限性越發明顯:
1.IPv4地址數目面臨耗盡,日近緊張;
2.IPv4尋址并非完全分等級,這使得Internet?樞紐路由器必須維持大量的路由表,負擔過重。
3.IPv4的地址必須被靜態分配或通過配置協議(如:DHCP)進行分配。IPv6的開發目標之一就是將提供更為簡便的配置方案。
于是IPv6(6.0版本)應運而生。在Window系統中,Windows?XP?提供了IPv6的developer-release版本;Windows?2000也可在http://www.microsoft.com/ipv6?下載?IPv6協議預覽。下圖在本人計算機上成功安裝的示例圖:
圖-1?IPV6?安裝示例
?
?
一.IPv4地址及其尋址?
1.IPv4地址
IPv4地址(常稱IP地址)用一個32位數表示;通常表示位十進制格式,地址的每8位字節被表示轉為一個十進制的數值,并由句點分隔,如:192.168.0.1;IPv4地址?通常分為A、B、C、D、E?五類。
????2.IPv4尋址
在Winsock?中,通過SOCKADDR_IN?結構來指定IPv4的地址和服務斷口信息:
struct?sockaddr_in?{
short?sin_family?;//必須為AF_INET,表示使用IPv4地址簇
???????????u_short?sin_port;?//TCP/UDP?端口
struct?in_addr?sin_addr;//?IP地址(以網絡字節順序排列,?4個字節)
char?sin_zero[8];//填充項
}??
?
二.IPv6地址及其尋址
??1.IPv6地址???
????IPv6地址與IPv4地址的顯著的不同是128位,長度是IPv4地址的4倍。IPv6地址由16位字節分段表示,顯示為冒號分隔的十六進制:
???????21DA:00D3:0000:2F3A:B234:ED12:9C5A:DAC3
?????????????????????????????????????????????????IPv6地址的分配
分配
?地址前綴
?
保留地址0000?0000
為NSAP預留0000?0001
可聚合的全球單播地址001
鏈接-本地單播地址1111?1110?10
站點-本地單播地址1111?1110?11
多播地址1111?1111
?
????2.?IPv6的尋址
?Winsock中,尋址使用一下結構:
??struct??sockaddr_in6{
short?sin6_family;//?地址簇:AF_INET6
u_short?sin6_port;//端口號
u_long?sin6_flowinfo;//連接標記通信量
struct?in6_addr?sin6_addr;//16字節結構的IPv6?地址
u_long?sin6_scope_id;//地址所有的接口索引
?
}?
?
三.獨立于協議的地址及名稱解析
由此可見在尋址時,IPv4使用16字節的SOCK_ADDR_IN?結構,IPv6則使用28?字節的SOCK_ADDR_IN6?結構。為了解決這個問題,IPv6中引入了新的尋址函數。 [Page]
1.getaddrinfo(),它提供獨立于協議的名稱解析:
int?getaddrinfo(??
?????????const?char?*FAR?*nodename,
?????????const??char?FAR*?servname,
?????????const?struct?addrinfo?FAR?*hins,
?????????struct?addrinfo?FAR?*FAR?*res
);?
???
l???????第一參數:nodename,以空字節結束的主機名或文字地址
l???????第二參數:servname,包含端口或服務名(如:FTP,TELNET)的以空字節結束的字符串
l???????第三個參數:hins?是一個結構(addrinfo),包含名稱解析的執行方式選項
l???????第四個參數:res?,用于返回?addrinfo?結構的一個或多個鏈表
結構addrinfo?的定義:
struct????addrinfo{
int?ai_flags;
int?ai_family;
int?ai_socktype;
int?ai_protocol;
size_t?ai_addrlen;
char?*ai_cannoname;
struct?sockaddr?*ai_addr;
struct?addrinfo?*ai_next;
}
l???????ai_flags?選值:AI_PASSIVE:可以用來獲取能夠傳遞給bind函數的地址,此時nodename應設置為NULL,servname為欲綁定的端口;AI?_CANONNAME?表示nodename?是主機名;AI_NUMBERICHOST?表示,?nodename?是一個文字字符串地址(如:“192.168.0.1”)????
l???????ai_family?選值:AI_INET或PF_INET(IPv4地址簇);AI_INET6或PF_INET6(IPv6地址簇);AI_UNSPEC(未指定,可能是IPv4或IPv6?地址簇)
l???????ai_socktype選值:SOCK_DGRAM(UDP類型套接字);SOCK_STREAM?(TCP類??型套接字)
l???????ai_protocol?選值:IPPROTO_TCP?(TCP/IP協議)
如果函數解析成功,解析后的地址將通過res返回。如果名稱被解析為多個地址,則返回一個由ai_next?字段形成的鏈表。每個由名稱解析的地址在ai_addr中表示,長度在ai_addrlen中表示。 2.getnameinfo()函數與getaddrinfo()相對應,功能相反。
.??????int?getnameinfo(
????????????????const?struct?sockaddr?FAR?*sa,
????????????????socklen_t?salen, [Page]
????????????????char?FAR?*host,
??????????????DWORD?hostlen,
??????????????char?FAR?*serv,
??????????????DWORD?servlen,
??????????????Int?flags);?
???以上參數的含義比較明顯,不再一一說明。
??3.釋放函數:?freeaddrinfo(res);
四、兼容IPv4和IPv6的網絡程序設計
兼容IPv4和IPv6的網絡程序,顯然涉及到兩個部分:客戶機和服務器。
在Windows?網絡編程中,Winsock是一種標準的API(應用程序接口),Winsock2版本已經發展成獨立于協議的的接口,被廣泛應用于Windows平臺中。
<一>客戶機程序設計
對于客戶機來說,不管是建立TCP/UDP?連接,它都應知道服務器的主機名或IP?地址,同時將服務器地址解析為IPv4或IPv6地址都可以,一般可以考慮一下步驟:
SOCKET?s;
struct?addrinfo,hints,*res=NULL;
char?*szRemoteAddress;//主機名或IP?地址
char?*szRemotePort;//端口號
int?rc;
1.用getaddrinfo()?函數解析地址。hins結構中?使用AF_UNSPEC標志,便可以獲得地址簇類型(IPv4或IPv6)。
memset(&hintas,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
rc=getaddrinfo(szRemoteAdddress,szRemotePort,&hints,&res);
if(rc==WSANO_DATA)
{//?無法解析,出錯
}
用返回的addrinfo結構中的ai_family,ai_socketype,ai_protocol字段來創建套接字。
s=socket(res->ai_family,ai_socktype,res->protocol);
if(s==INVALID_SOCKET)
{//創建套接字失敗
}
2.使用返回的addrinfo結構中的ai_addr來調用其他函數(connect(),send()等).。
??????rc==connect(s,res->ai_addr,res->addrlen);
if(rc==SOCKET_ERROR)
{//連接失敗;
}
。。。//完成其他編程
<二>服務器程序設計
服務器程序設計,應考慮到IPv4和IPv6?都具有各自的堆棧;因此如果服務器希望能同時接受IPv4和IPv6的連接,就必須能同時創建IPv4和IPv6套接字;一般可以考慮一下步驟:
????????SOCKET?socklisten[2];//監聽Socket變量
char?*szPort=”8080”;//監聽端口
struct?addinfo?hints,*res=NULL,*ptr=NULL;
int?rc,i=0;
1.??調用getaddrinfo()函數,該結構包含AI_PASSIVE,AF_UNSPEC標志,以及所需的套接字類型、協議及所需的本地端口(用來監聽和接受數據等)。函數將返回的兩個addrinfo結構,分別可用于IPv4和IPv6監聽地址: [Page]
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
hints.ai_flags=AI_PASSIVE;
rc=getaddinfo(NULL,szPort,&hints,&res);
if(rc!=0){//失敗處理;}
ptr=res;
?????2.?用返回的addrinfo結構中的ai_family,ai_socketype,ai_protocol字段來創建套接字后;便可以使用addrinfo結構中的ai_addr?和ar_addrlen?字段調用綁定函數bind()。
while(ptr)
{
socklisten[i]=socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol);
if(socklisten[i]==INVALID_SOCKET){//創建失敗處理;}
rc=bind(socklisten[i],ptr->ai_addr,ptr->ai_addrlen);
if(rc==SOCKET_ERROR){//綁定失敗處理}
rc=listen(slisten[i],7)//開始監聽
if(rc==SOCKET_ERROR){//監聽失敗處理}
i++;
ptr=ptr->ai_next;
}
?????。。。
//完成其他編程
五、程序實例?
???在這里,給出一個基于IPV6的簡單回應(ECHO)服務器程序.?
????1.建立CIPv6?類? // IPv6.h: 頭文件,這里使用到了套接字中的“select I/O模型” #define WIN32_LEAN_AND_MEAN???
#include <winsock2.h>???
#include <ws2tcpip.h>???
#include <tpipv6.h>??? //??? IPv6 頭文件???
#include <stdlib.h>???
#include <stdio.h>???
#include <string.h>???
#pragma comment(lib, "ws2_32.lib")//套接字庫文件???
#define DEFAULT_PORT "7274" // 默認端口
#define BUFFER_SIZE?? 64?? // 數據緩沖區 class CIPv6???????
{???
public:???
?// 創建TCP 服務器???
?int CreateServer(char *Port = DEFAULT_PORT,char *Address = NULL);???
?void Usage(char *ProgName);//用戶信息提示???
?LPSTR DecodeError(int ErrorCode);//獲取錯誤信息???
?CIPv6();???
?virtual ~CIPv6();??? }; // IPv61.cpp: CIPv6類的實現 .
// IPv61.cpp: implementation of the CIPv6 class.
//
// #include "stdafx.h"
#include "IPv61.h" int CIPv6::CreateServer(char *Port, char *Address)???
{????
?char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
?int RetVal, FromLen, AmountRead;???
?SOCKADDR_STORAGE From;???
?WSADATA wsaData;???
?ADDRINFO Hints, *AddrInfo;???
?SOCKET ServSock;???
?fd_set SockSet;???
?// 啟動Winsock???
?if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
?{???
??fprintf(stderr, "WSAStartup failed with error %d: %s\n",???
???RetVal, DecodeError(RetVal));???
??WSACleanup();???
??return -1;???
?}???
?if (Port == NULL)
?{???
??Usage("Port Error");???
?}???
?memset(&Hints, 0, sizeof(Hints));???
?Hints.ai_family =AF_INET6;// Family;???
?Hints.ai_socktype =SOCK_STREAM;???
?Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;???
?RetVal = getaddrinfo(Address, Port, &Hints, &AddrInfo);???
?if (RetVal != 0)
?{???
??fprintf(stderr, "getaddrinfo failed with error %d: %s\n", RetVal, gai_strerror(RetVal));???
??WSACleanup();
??return -1;
?}
?// 創建套接字
?ServSock = socket(AddrInfo->ai_family,AddrInfo->ai_socktype, AddrInfo->ai_protocol);
?if (ServSock == INVALID_SOCKET)
?{
??fprintf(stderr, "socket() failed with error %d: %s\n",
???WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
?}
?// 綁定套接字????
?if (bind(ServSock, AddrInfo->ai_addr, AddrInfo->ai_addrlen) == SOCKET_ERROR)????
?{???
??fprintf(stderr,"bind() failed with error %d: %s\n",???
???WSAGetLastError(), DecodeError(WSAGetLastError()));???
??WSACleanup();???
??return -1;????????
?}???
?// 偵聽???
?if (listen(ServSock, 5) == SOCKET_ERROR)????
?{???
??fprintf(stderr, "listen() failed with error %d: %s\n",???
???WSAGetLastError(), DecodeError(WSAGetLastError()));???
??WSACleanup();???
??return -1;????
?}???
?printf("'Listening' on port %s, protocol %s, protocol family %s\n",???
??Port, \"TCP\",???
??"PF_INET6");??? freeaddrinfo(AddrInfo);???
?//使用select I/O 模型進行收發
?FD_ZERO(&SockSet);???
?while(1)
?{???
??FromLen = sizeof(From);???
??if (FD_ISSET(ServSock, &SockSet)) break;???
??FD_SET(ServSock, &SockSet);
??if (select(0, &SockSet, 0, 0, 0) == SOCKET_ERROR)
??{
???fprintf(stderr, "select() failed with error %d: %s\n",
????WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
??}
?}
?if (FD_ISSET(ServSock, &SockSet))
?{
??FD_CLR(ServSock, &SockSet);
?}
?//接受一個連接
?SOCKET ConnSock;
?ConnSock = accept(ServSock, (LPSOCKADDR)&From, &FromLen);
?if (ConnSock == INVALID_SOCKET)
?{
??fprintf(stderr, "accept() failed with error %d: %s\n",
???WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
?}
?if (getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
??sizeof(Hostname), NULL, 0, NI_NUMERICHOST) != 0)
??strcpy(Hostname, "<unknown>");
??printf("\nAccepted connection from %s\n", Hostname);
??while(1)
??{
???//等待接受數據
???AmountRead = recv(ConnSock, Buffer, sizeof(Buffer), 0);
???if (AmountRead == SOCKET_ERROR)
???{
????fprintf(stderr, "recv() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
?????closesocket(ConnSock);
????break;
???}
???if (AmountRead == 0) {
????printf("Client closed connection\n");
?????closesocket(ConnSock);
????break;
???} printf("Received %d bytes from client: [%.*s]\n",
????AmountRead, AmountRead, Buffer);
???//進行簡單ECHO 回應
???printf("Echoing same data back to client\n");
????RetVal = send(ConnSock, Buffer, AmountRead, 0);
???if (RetVal == SOCKET_ERROR)
???{
????fprintf(stderr, "send() failed: error %d: %s\n",
?????WSAGetLastError(), DecodeError(WSAGetLastError()));
????closesocket(ConnSock);
????break;
???}
??}
??return 0;
} void CIPv6::Usage(char *ProgName)
{
?fprintf(stderr, "\nSimple socket sample server program.\n");
??fprintf(stderr, "transport tEither TCP or UDP. (default: %s)\n",
??"TCP");
??fprintf(stderr, "port\t\tPort on which to bind. (default %s)\n",
??DEFAULT_PORT);
?fprintf(stderr, "address\tIP address on which to bind.(default: unspecified address)\n");
??WSACleanup();
?exit(1);
} LPSTR CIPv6::DecodeError(int ErrorCode)
{
?static char Message[1024];
?FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
??FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
??MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
??(LPSTR)Message, 1024, NULL);
?return Message;
} 2.應用示例
#include "stdafx.h"
#include "IPv6.h"????
int main(int argc, char* argv[])????
{
????????CIPv6 m_ipv6;????
????????m_ipv6.CreateServer(); //采用默認創建服務器,????
????????//如果你成功安裝了IPv6可以使用正常使用????
????????return 0;????
}
1.IPv4地址數目面臨耗盡,日近緊張;
2.IPv4尋址并非完全分等級,這使得Internet?樞紐路由器必須維持大量的路由表,負擔過重。
3.IPv4的地址必須被靜態分配或通過配置協議(如:DHCP)進行分配。IPv6的開發目標之一就是將提供更為簡便的配置方案。
于是IPv6(6.0版本)應運而生。在Window系統中,Windows?XP?提供了IPv6的developer-release版本;Windows?2000也可在http://www.microsoft.com/ipv6?下載?IPv6協議預覽。下圖在本人計算機上成功安裝的示例圖:
圖-1?IPV6?安裝示例
?
?
一.IPv4地址及其尋址?
1.IPv4地址
IPv4地址(常稱IP地址)用一個32位數表示;通常表示位十進制格式,地址的每8位字節被表示轉為一個十進制的數值,并由句點分隔,如:192.168.0.1;IPv4地址?通常分為A、B、C、D、E?五類。
????2.IPv4尋址
在Winsock?中,通過SOCKADDR_IN?結構來指定IPv4的地址和服務斷口信息:
struct?sockaddr_in?{
short?sin_family?;//必須為AF_INET,表示使用IPv4地址簇
???????????u_short?sin_port;?//TCP/UDP?端口
struct?in_addr?sin_addr;//?IP地址(以網絡字節順序排列,?4個字節)
char?sin_zero[8];//填充項
}??
?
二.IPv6地址及其尋址
??1.IPv6地址???
????IPv6地址與IPv4地址的顯著的不同是128位,長度是IPv4地址的4倍。IPv6地址由16位字節分段表示,顯示為冒號分隔的十六進制:
???????21DA:00D3:0000:2F3A:B234:ED12:9C5A:DAC3
?????????????????????????????????????????????????IPv6地址的分配
分配
?地址前綴
?
保留地址0000?0000
為NSAP預留0000?0001
可聚合的全球單播地址001
鏈接-本地單播地址1111?1110?10
站點-本地單播地址1111?1110?11
多播地址1111?1111
?
????2.?IPv6的尋址
?Winsock中,尋址使用一下結構:
??struct??sockaddr_in6{
short?sin6_family;//?地址簇:AF_INET6
u_short?sin6_port;//端口號
u_long?sin6_flowinfo;//連接標記通信量
struct?in6_addr?sin6_addr;//16字節結構的IPv6?地址
u_long?sin6_scope_id;//地址所有的接口索引
?
}?
?
三.獨立于協議的地址及名稱解析
由此可見在尋址時,IPv4使用16字節的SOCK_ADDR_IN?結構,IPv6則使用28?字節的SOCK_ADDR_IN6?結構。為了解決這個問題,IPv6中引入了新的尋址函數。 [Page]
1.getaddrinfo(),它提供獨立于協議的名稱解析:
int?getaddrinfo(??
?????????const?char?*FAR?*nodename,
?????????const??char?FAR*?servname,
?????????const?struct?addrinfo?FAR?*hins,
?????????struct?addrinfo?FAR?*FAR?*res
);?
???
l???????第一參數:nodename,以空字節結束的主機名或文字地址
l???????第二參數:servname,包含端口或服務名(如:FTP,TELNET)的以空字節結束的字符串
l???????第三個參數:hins?是一個結構(addrinfo),包含名稱解析的執行方式選項
l???????第四個參數:res?,用于返回?addrinfo?結構的一個或多個鏈表
結構addrinfo?的定義:
struct????addrinfo{
int?ai_flags;
int?ai_family;
int?ai_socktype;
int?ai_protocol;
size_t?ai_addrlen;
char?*ai_cannoname;
struct?sockaddr?*ai_addr;
struct?addrinfo?*ai_next;
}
l???????ai_flags?選值:AI_PASSIVE:可以用來獲取能夠傳遞給bind函數的地址,此時nodename應設置為NULL,servname為欲綁定的端口;AI?_CANONNAME?表示nodename?是主機名;AI_NUMBERICHOST?表示,?nodename?是一個文字字符串地址(如:“192.168.0.1”)????
l???????ai_family?選值:AI_INET或PF_INET(IPv4地址簇);AI_INET6或PF_INET6(IPv6地址簇);AI_UNSPEC(未指定,可能是IPv4或IPv6?地址簇)
l???????ai_socktype選值:SOCK_DGRAM(UDP類型套接字);SOCK_STREAM?(TCP類??型套接字)
l???????ai_protocol?選值:IPPROTO_TCP?(TCP/IP協議)
如果函數解析成功,解析后的地址將通過res返回。如果名稱被解析為多個地址,則返回一個由ai_next?字段形成的鏈表。每個由名稱解析的地址在ai_addr中表示,長度在ai_addrlen中表示。 2.getnameinfo()函數與getaddrinfo()相對應,功能相反。
.??????int?getnameinfo(
????????????????const?struct?sockaddr?FAR?*sa,
????????????????socklen_t?salen, [Page]
????????????????char?FAR?*host,
??????????????DWORD?hostlen,
??????????????char?FAR?*serv,
??????????????DWORD?servlen,
??????????????Int?flags);?
???以上參數的含義比較明顯,不再一一說明。
??3.釋放函數:?freeaddrinfo(res);
四、兼容IPv4和IPv6的網絡程序設計
兼容IPv4和IPv6的網絡程序,顯然涉及到兩個部分:客戶機和服務器。
在Windows?網絡編程中,Winsock是一種標準的API(應用程序接口),Winsock2版本已經發展成獨立于協議的的接口,被廣泛應用于Windows平臺中。
<一>客戶機程序設計
對于客戶機來說,不管是建立TCP/UDP?連接,它都應知道服務器的主機名或IP?地址,同時將服務器地址解析為IPv4或IPv6地址都可以,一般可以考慮一下步驟:
SOCKET?s;
struct?addrinfo,hints,*res=NULL;
char?*szRemoteAddress;//主機名或IP?地址
char?*szRemotePort;//端口號
int?rc;
1.用getaddrinfo()?函數解析地址。hins結構中?使用AF_UNSPEC標志,便可以獲得地址簇類型(IPv4或IPv6)。
memset(&hintas,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
rc=getaddrinfo(szRemoteAdddress,szRemotePort,&hints,&res);
if(rc==WSANO_DATA)
{//?無法解析,出錯
}
用返回的addrinfo結構中的ai_family,ai_socketype,ai_protocol字段來創建套接字。
s=socket(res->ai_family,ai_socktype,res->protocol);
if(s==INVALID_SOCKET)
{//創建套接字失敗
}
2.使用返回的addrinfo結構中的ai_addr來調用其他函數(connect(),send()等).。
??????rc==connect(s,res->ai_addr,res->addrlen);
if(rc==SOCKET_ERROR)
{//連接失敗;
}
。。。//完成其他編程
<二>服務器程序設計
服務器程序設計,應考慮到IPv4和IPv6?都具有各自的堆棧;因此如果服務器希望能同時接受IPv4和IPv6的連接,就必須能同時創建IPv4和IPv6套接字;一般可以考慮一下步驟:
????????SOCKET?socklisten[2];//監聽Socket變量
char?*szPort=”8080”;//監聽端口
struct?addinfo?hints,*res=NULL,*ptr=NULL;
int?rc,i=0;
1.??調用getaddrinfo()函數,該結構包含AI_PASSIVE,AF_UNSPEC標志,以及所需的套接字類型、協議及所需的本地端口(用來監聽和接受數據等)。函數將返回的兩個addrinfo結構,分別可用于IPv4和IPv6監聽地址: [Page]
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
hints.ai_flags=AI_PASSIVE;
rc=getaddinfo(NULL,szPort,&hints,&res);
if(rc!=0){//失敗處理;}
ptr=res;
?????2.?用返回的addrinfo結構中的ai_family,ai_socketype,ai_protocol字段來創建套接字后;便可以使用addrinfo結構中的ai_addr?和ar_addrlen?字段調用綁定函數bind()。
while(ptr)
{
socklisten[i]=socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol);
if(socklisten[i]==INVALID_SOCKET){//創建失敗處理;}
rc=bind(socklisten[i],ptr->ai_addr,ptr->ai_addrlen);
if(rc==SOCKET_ERROR){//綁定失敗處理}
rc=listen(slisten[i],7)//開始監聽
if(rc==SOCKET_ERROR){//監聽失敗處理}
i++;
ptr=ptr->ai_next;
}
?????。。。
//完成其他編程
五、程序實例?
???在這里,給出一個基于IPV6的簡單回應(ECHO)服務器程序.?
????1.建立CIPv6?類? // IPv6.h: 頭文件,這里使用到了套接字中的“select I/O模型” #define WIN32_LEAN_AND_MEAN???
#include <winsock2.h>???
#include <ws2tcpip.h>???
#include <tpipv6.h>??? //??? IPv6 頭文件???
#include <stdlib.h>???
#include <stdio.h>???
#include <string.h>???
#pragma comment(lib, "ws2_32.lib")//套接字庫文件???
#define DEFAULT_PORT "7274" // 默認端口
#define BUFFER_SIZE?? 64?? // 數據緩沖區 class CIPv6???????
{???
public:???
?// 創建TCP 服務器???
?int CreateServer(char *Port = DEFAULT_PORT,char *Address = NULL);???
?void Usage(char *ProgName);//用戶信息提示???
?LPSTR DecodeError(int ErrorCode);//獲取錯誤信息???
?CIPv6();???
?virtual ~CIPv6();??? }; // IPv61.cpp: CIPv6類的實現 .
// IPv61.cpp: implementation of the CIPv6 class.
//
// #include "stdafx.h"
#include "IPv61.h" int CIPv6::CreateServer(char *Port, char *Address)???
{????
?char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
?int RetVal, FromLen, AmountRead;???
?SOCKADDR_STORAGE From;???
?WSADATA wsaData;???
?ADDRINFO Hints, *AddrInfo;???
?SOCKET ServSock;???
?fd_set SockSet;???
?// 啟動Winsock???
?if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
?{???
??fprintf(stderr, "WSAStartup failed with error %d: %s\n",???
???RetVal, DecodeError(RetVal));???
??WSACleanup();???
??return -1;???
?}???
?if (Port == NULL)
?{???
??Usage("Port Error");???
?}???
?memset(&Hints, 0, sizeof(Hints));???
?Hints.ai_family =AF_INET6;// Family;???
?Hints.ai_socktype =SOCK_STREAM;???
?Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;???
?RetVal = getaddrinfo(Address, Port, &Hints, &AddrInfo);???
?if (RetVal != 0)
?{???
??fprintf(stderr, "getaddrinfo failed with error %d: %s\n", RetVal, gai_strerror(RetVal));???
??WSACleanup();
??return -1;
?}
?// 創建套接字
?ServSock = socket(AddrInfo->ai_family,AddrInfo->ai_socktype, AddrInfo->ai_protocol);
?if (ServSock == INVALID_SOCKET)
?{
??fprintf(stderr, "socket() failed with error %d: %s\n",
???WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
?}
?// 綁定套接字????
?if (bind(ServSock, AddrInfo->ai_addr, AddrInfo->ai_addrlen) == SOCKET_ERROR)????
?{???
??fprintf(stderr,"bind() failed with error %d: %s\n",???
???WSAGetLastError(), DecodeError(WSAGetLastError()));???
??WSACleanup();???
??return -1;????????
?}???
?// 偵聽???
?if (listen(ServSock, 5) == SOCKET_ERROR)????
?{???
??fprintf(stderr, "listen() failed with error %d: %s\n",???
???WSAGetLastError(), DecodeError(WSAGetLastError()));???
??WSACleanup();???
??return -1;????
?}???
?printf("'Listening' on port %s, protocol %s, protocol family %s\n",???
??Port, \"TCP\",???
??"PF_INET6");??? freeaddrinfo(AddrInfo);???
?//使用select I/O 模型進行收發
?FD_ZERO(&SockSet);???
?while(1)
?{???
??FromLen = sizeof(From);???
??if (FD_ISSET(ServSock, &SockSet)) break;???
??FD_SET(ServSock, &SockSet);
??if (select(0, &SockSet, 0, 0, 0) == SOCKET_ERROR)
??{
???fprintf(stderr, "select() failed with error %d: %s\n",
????WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
??}
?}
?if (FD_ISSET(ServSock, &SockSet))
?{
??FD_CLR(ServSock, &SockSet);
?}
?//接受一個連接
?SOCKET ConnSock;
?ConnSock = accept(ServSock, (LPSOCKADDR)&From, &FromLen);
?if (ConnSock == INVALID_SOCKET)
?{
??fprintf(stderr, "accept() failed with error %d: %s\n",
???WSAGetLastError(), DecodeError(WSAGetLastError()));
???WSACleanup();
???return -1;
?}
?if (getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
??sizeof(Hostname), NULL, 0, NI_NUMERICHOST) != 0)
??strcpy(Hostname, "<unknown>");
??printf("\nAccepted connection from %s\n", Hostname);
??while(1)
??{
???//等待接受數據
???AmountRead = recv(ConnSock, Buffer, sizeof(Buffer), 0);
???if (AmountRead == SOCKET_ERROR)
???{
????fprintf(stderr, "recv() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError()));
?????closesocket(ConnSock);
????break;
???}
???if (AmountRead == 0) {
????printf("Client closed connection\n");
?????closesocket(ConnSock);
????break;
???} printf("Received %d bytes from client: [%.*s]\n",
????AmountRead, AmountRead, Buffer);
???//進行簡單ECHO 回應
???printf("Echoing same data back to client\n");
????RetVal = send(ConnSock, Buffer, AmountRead, 0);
???if (RetVal == SOCKET_ERROR)
???{
????fprintf(stderr, "send() failed: error %d: %s\n",
?????WSAGetLastError(), DecodeError(WSAGetLastError()));
????closesocket(ConnSock);
????break;
???}
??}
??return 0;
} void CIPv6::Usage(char *ProgName)
{
?fprintf(stderr, "\nSimple socket sample server program.\n");
??fprintf(stderr, "transport tEither TCP or UDP. (default: %s)\n",
??"TCP");
??fprintf(stderr, "port\t\tPort on which to bind. (default %s)\n",
??DEFAULT_PORT);
?fprintf(stderr, "address\tIP address on which to bind.(default: unspecified address)\n");
??WSACleanup();
?exit(1);
} LPSTR CIPv6::DecodeError(int ErrorCode)
{
?static char Message[1024];
?FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
??FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
??MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
??(LPSTR)Message, 1024, NULL);
?return Message;
} 2.應用示例
#include "stdafx.h"
#include "IPv6.h"????
int main(int argc, char* argv[])????
{
????????CIPv6 m_ipv6;????
????????m_ipv6.CreateServer(); //采用默認創建服務器,????
????????//如果你成功安裝了IPv6可以使用正常使用????
????????return 0;????
}
總結
以上是生活随笔為你收集整理的C++中的IPv6网络程序设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡密码加签名是什么意思
- 下一篇: 贵金属投资常见骗局有哪些?贵金属投资的风