(本章节中例子都是用 VS2005 编译调试的)
相关文献:
简介(源于维基)
Berkeley套接字(也作BSD套接字应用程序接口)刚开始是4.2BSD Unix操作系统(于1983发布)的一套应用程序接口。然而,由于AT&T的专利保护着UNIX,所以只有在1989年Berkeley大学才能自由地发布自己的操作系统和网络库。
Berkeley套接字接口,一个应用程序接口(API),使用一个Internet套接字的概念,使主机间或者一台计算机上的进程间可以通讯。 它可以在很多不同的输入/输出设备和驱动之上运行,尽管这有赖于操作系统的具体实现。 接口实现用于TCP/IP协议,因此它是维持Internet的基本技术之一。 它是由加利福尼亚的伯克利大学开发,最初用于Unix系统。 如今,所有的现代操作系统都有一些源于Berkeley套接字接口的实现,它已成为连接Internet的标准接口。
套接字接口的接入有三个不同的级别,最基础的也是最有效的就是raw socket级别接入。 很少的应用程序需要在外向通讯控制的这个级别接入,所以raw socket级别是只为了用于开发计算机Internet相关技术的。 最近几年,大多数的操作系统已经实现了对它的全方位支持,包括Windows XP。
应用程序网络数据传输
套接字
网络字节顺序(套接字与地址簇中使用)
由于不同的计算机存放数据字节的顺序不同,所以通信双方必须协商出统一的存放字节顺序,这样才能发送方的数据可以被接收方准确无误的读取,否则接收方读到的是一堆不知名的数据,所以通信前双方必须协商统一的用网络字节顺序,保证通信的正常进行
基于消息的异步套接字
C/S模式
[win32 API 相关套接字函数][相关结构体及宏][基于消息的套接字编程][MFC套接字相关函数]
[套接字版本协商][创建套接字][绑定端口][点分十进制转换成无符号长整形][无符号长整形转换成点分十进制][主机字节顺序转换为网络字节顺序][TCP套接字相关函数][UDP套机制相关函数]
函数原型
int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
参数说明
返回值
函数原型
SOCKET socket ( int af, int type, int protocol );
参数说明
返回值
函数原型
int bind ( SOCKET s, const struct sockaddr FAR* name, int namelen );
参数说明
返回值 如果成功,返回0,如果失败,返回SOCKET_ERROR,错误信息可以通过WSAGetLastError函数返回
函数原型
unsigned long inet_addr (const char FAR * cp );
参数说明: cp 一个点分十进制的IP地址形式的字符串
返回值 一个对应cp点分十进制的unsigned long类型的数值
函数原型
char FAR * inet_ntoa (struct in_addr in );
参数说明 in: 一个点分十进制的unsigned long类型的数值
返回值 一个对应in点分十进制的IP地址形式的字符串
16位数值
u_short htons (u_short hostshort );
32位数值
u_long htonl (u_long hostlong );
[套接字版本结构][地址结构][TCP/IP地址结构][地址表示][MAKEWORD宏]
struct WSAData { WORD wVersion;//打算使用的Winsock版本号 WORD wHighVersion;//容纳的是现有的Winsock最高版本号,以高字节代表的是Winsock的副版本,低字节表示的是搞版本号 char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYSSTATUS_LEN+1]; //以下两个参数一般不设置它 unsigned short iMaxSockets;//同时最多可以打开多少套接字 unsigned short iMaxUdpDg;//数据报的最大长度 //同时最多可以打开套接字数目很大程度上和可用物理内存的多少有关 char FAR * lpVendorInfo; //这个参数Winsock实施方案有关的指定厂商信息预留的,任何一个Win32平台上都没有使用这个字段 };
struct sockaddr { unsigned short sa_family;//指定地址家族,对于TCP/IP协议的套接字,必须设置为AF_INET char sa_data[14];// 仅仅表示要求一块内存分配区,启到占位作用,该区域中指定与协议相关的具体地址信息,由于实际要求的只是内存区,所以对于不同的协议家族,用不同的协议家族,用不同的结构来替换sockaddr };
struct sockaddr_in{ short sin_family;///指定地址家族,对于TCP/IP协议的套接字,必须设置为AF_INET unsigned short sin_port;//指定要分配给套接字的端口 struct in_addr sin_addr;//套接字的主机的IP地址 char sin_zero[8];//一个填充占位符 };//在TCP/IP编程中用这个结构体来替换sockaddr结构体
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; }; //用于记入地址的一个结构,若将IP地址设置为INADDR_ANY,允许套接字向任何分配给本机的IP地址发送或接收数据,用INADDR_ANY可以简化编程,这样程序便可以接收发自多个接口的回应
MAKEWORD(x,y)
作用: 用于设置DWORD类型的版本号,x是高字节,y是低字节
[获得系统中安装的网络协议的相关信息][注册网络事件][创建套接字][UDP消息接收][UDP消息发送]
函数原型
int WSAEnumProtocols( LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, ILPDWORD lpdwBufferLength )
参数说明
返回值 如果函数没有错误发生,函数返回协议报告信息,如果错误返回SOCKET_ERROR和在WSAGetLastError函数中查询相关详细信息
说明 Win32平台支持多种不同的网络协议,采用Winsock2,就可以编写可直接使用任何一种协议的网络应用程序了。通过WSAEnumProtocols函数可以获得系统中安装的网络协议的相关信息
函数原型
int WSAAsyncSelect ( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );
参数说明
取值 说明
返回值 如果函数成功返回值是0,如果函数失败则返回值是SOCKET_ERROR并调用WSAGetLastError获得更多错误信息
说明 该函数为指定的套接字请求基于Windows消息的网络事件通知,并自动将该套接字设置为非阻塞模式
函数原型
SOCKET WSASocket( int af, int type, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags );
参数说明
返回值
[初始化套接字]
函数原型
BOOL AfxSocketInit(WSADATA* lpwsaData = NULL);
作用: MFC提供的创建套接字库的函数
返回值: 若函数调用成功时候返回非零值,否则返回零
注意: 应该在应用程序类重载的InitInstance函数中调用AfxSocketInit函数在MFC应用程序运行时需要的一些必要的预编译头文件stdafx.h中添加函数的头文件afxsock.h
优点: 使用这个函数的优点,它可以确保在应用程序终止前,调用WSACleapup函数以终止对套接字的使用,并且利用AfxSocketInit函数也不用在加载套接字库时,手动为工程添加到ws2_32.lib的链接库文件设置
[监听请求(服务器)][接收请求(服务器)][发送数据][接收数据][建立连接(客服端)]
函数原型
int listen ( SOCKET s, int backlog );
参数说明
函数原型
SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen );
参数说明
返回值
如果没有错误发生,函数返回一个建立好连接的SOCKET套接字,如果失败则返回INVALID_SOCKET
函数原型
int send ( SOCKET s, const char FAR * buf, int len, int flags );
参数说明
函数原型
int recv ( SOCKET s, char FAR* buf, int len, int flags );
参数说明
函数原型
int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen );
参数说明
[接收消息][发送数据][接收消息(基于消息)][发送数据(基于消息)]
函数原型
int recvfrom ( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen );
参数说明
返回值: 如果没有错误发送返回值是接收数据的字节数,如果连接关闭则返回0,否则返回SOCKET_ERROR
函数原型
int sendto ( SOCKET s, const char FAR * buf, int len, int flags, const struct sockaddr FAR * to, int tolen );
参数说明
返回值: 如果没有错误返回值是发送数据的字节数,否则返回SOCKET_ERROR
函数原型
int WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR *lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
参数说明
typedef struct __WSABUF { u_longlen; // buffer length char FAR *buf; // pointer to buffer } WSABUF, FAR * LPWSABUF;
void CALLBACK CompletionROUTINE( IN DWORDdwError, IN DWORDcbTransferred, IN LPWSAOVERLAPPEDlpOverlapped, IN DWORDdwFlags );
返回值: 若函数失败则返回SOCKET_ERROR
函数原型
int WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, const struct sockaddr FAR *lpTo, int iToLen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
参数说明
返回值: 若函数失败则返回SOCKET_ERROR
[编写基于 UDP 套接字通信][编写基于 TCP 套接字通信][编写基于消息机制的 UDP 套接字通信][通过域名获得 IP 地址]
流程图:
代码示例:
查看本机 IP
服务器端
#include <Winsock2.h> #include <iostream> #include <string> #pragma comment(lib,"ws2_32.lib") using namespace std; void main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //创建套接字 SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); //将套接字绑定到端口上 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); char recvBuffer[300];//接收字符数据 memset((void*)recvBuffer,'\0',300); cout<<"等待对方发送数据... "<<endl; //接收数据 recvfrom(sockSrv,recvBuffer,300,0,(SOCKADDR*)&addrClient,&len); cout<<"对方的地址为: "<<inet_ntoa(addrClient.sin_addr)<<endl; cout<<"接收的内容为: "<<recvBuffer<<endl; //发送数据 string sendBuffer = "this is server"; cout<<"向客户端方发送数据: "<<sendBuffer.c_str()<<endl; sendto(sockSrv,sendBuffer.c_str(),sendBuffer.length() +1,0,(SOCKADDR*)&addrClient,sizeof(SOCKADDR)); closesocket(sockSrv);//关闭服务器套接字 WSACleanup();//结束套接字库的调用 system("pause"); }
客户端
#include <Winsock2.h> #include <iostream> #include <string> //加载动态连接库ws2_32.dll,提供了网络相关API的支持 #pragma comment(lib,"ws2_32.lib") using namespace std; void main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //建立通讯 socket SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr("220.160.249.188"); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000); //发送数据 string sendBuffer = "this is client!"; cout<<"向服务器方发送数据: "<<sendBuffer.c_str()<<endl; sendto(sockClient,sendBuffer.c_str(),sendBuffer.length()+1,0,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //接收数据 char recvBuffer[300];//接收字符数据 memset((void*)recvBuffer,'\0',300); int len = sizeof(SOCKADDR); cout<<"等待对方发送数据... "<<endl; recvfrom(sockClient,recvBuffer,300,0,(SOCKADDR*)&addrSrv,&len); cout<<"主机的地址为: "<<inet_ntoa(addrSrv.sin_addr)<<endl; cout<<"接收的内容为: "<<recvBuffer<<endl; //结束通信 closesocket(sockClient);//关闭服务器套接字 WSACleanup();//结束套接字库的调用 system("pause"); }
运行结果(先运行服务器,再运行客户端.然后结果为下图所示上面为服务器下面为客户端)
流程图:
代码示例:
查看本机 IP
服务器端
#include <Winsock2.h> #include <iostream> #include <string> #pragma comment(lib,"ws2_32.lib") using namespace std; void main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //创建套接字 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); //将套接字绑定到端口上 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //将套接字设置为监听模式 listen(sockSrv,5); //等待客户请求来到,当请求来到时候,接受请求,接受连接请求,返回一个新的对应于此连接套接字 SOCKADDR_IN addrClient; int len = sizeof(SOCKADDR); //开始监听 cout<<"等待用户连接"<<endl; SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&len);//sockConn用于建立连接的套接字 cout<<"用户连接到来"<<endl; //和客户通信 //接收数据 char recvBuffer[300];//接收字符数据 memset((void*)recvBuffer,'\0',300); cout<<"等待对方发送数据... "<<endl; recv(sockConn,recvBuffer,100,0); cout<<"对方的地址为: "<<inet_ntoa(addrClient.sin_addr)<<endl; cout<<"接收的内容为: "<<recvBuffer<<endl; //发送数据 string sendBuffer = "this is server"; cout<<"向客户端方发送数据: "<<sendBuffer.c_str()<<endl; send(sockConn,sendBuffer.c_str(),sendBuffer.size(),0); //关闭本次连接的通道 closesocket(sockConn); closesocket(sockSrv);//关闭服务器套接字 WSACleanup();//结束套接字库的调用 system("pause"); }
客户端
#include <Winsock2.h> #include <iostream> #include <string> //加载动态连接库ws2_32.dll,提供了网络相关API的支持 #pragma comment(lib,"ws2_32.lib") using namespace std; void main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //建立通讯 socket SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr("220.160.249.188"); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000); //发出连接请求 cout<<"请求与服务器连接"<<endl; if(connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)) != SOCKET_ERROR) { cout<<"与服务器建立连接"<<endl; //和服务器通信 //发送数据 string sendBuffer = "this is client!"; cout<<"向服务器方发送数据: "<<sendBuffer.c_str()<<endl; send(sockClient,sendBuffer.c_str(),sendBuffer.size(),0); //接收数据 char recvBuffer[300];//接收字符数据 memset((void*)recvBuffer,'\0',300); int len = sizeof(SOCKADDR); cout<<"等待对方发送数据... "<<endl; recv(sockClient,recvBuffer,100,0); cout<<"主机的地址为: "<<inet_ntoa(addrSrv.sin_addr)<<endl; cout<<"接收的内容为: "<<recvBuffer<<endl; } //结束通信 closesocket(sockClient);//关闭服务器套接字 WSACleanup();//结束套接字库的调用 system("pause"); }
运行结果(先运行服务器,再运行客户端.然后结果为下图所示上面为服务器下面为客户端)
流程图:
程序代码(源于孙鑫第十六讲代码):
先添加一个对话框工程工程工程名为 Chat ,因为服务器和客户端这里写在一起所以就一个工程就好.
资源界面设计
相关代码
在 stdafx.h 头文件中加载动态连接库的引入库和相关头文件
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
在程序初始化的时候, 加载套接字库和进行套接字库协商,这个工作放在 Chat.cpp ,主线程的初始化工作函数 InitInstance 中.
BOOL CChatApp::InitInstance() { //套接字版本协商------------------------------------ WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return FALSE; } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup( ); return FALSE; } //---------------------------------------------------- AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CChatDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; }
接着来定义一个网络事件,和网络事件响应函数
/* 在 ChatDlg.h 中 ******************************************************/ //添加网络事件定义 #define UM_SOCK WM_USER+1 //然后在 CChatDlg 类中添加消息响应函数原型 afx_msg LRESULT OnSock(WPARAM,LPARAM); /* 在 ChatDlg.cppp 中 ***************************************************/ //在消息映射中添加消息映射 BEGIN_MESSAGE_MAP(CChatDlg, CDialog) //{{AFX_MSG_MAP(CChatDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend) //}}AFX_MSG_MAP ON_MESSAGE(UM_SOCK,OnSock) //网络事件的消息映射 END_MESSAGE_MAP() //添加消息事件响应函数定义 afx_msg LRESULT CChatDlg::OnSock(WPARAM wParam,LPARAM lParam) { switch(LOWORD(lParam)) { //接收数据 case FD_READ: WSABUF wsabuf; wsabuf.buf=new char[200]; wsabuf.len=200; DWORD dwRead; DWORD dwFlag=0; SOCKADDR_IN addrFrom; int len=sizeof(SOCKADDR); CString str; CString strTemp; HOSTENT *pHost; if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag, (SOCKADDR*)&addrFrom,&len,NULL,NULL)) { MessageBox("接收数据失败!"); return 0; } pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET); //str.Format("%s说 :%s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf); str.Format("%s说 :%s",pHost->h_name,wsabuf.buf); str+="\r\n"; GetDlgItemText(IDC_EDIT_RECV,strTemp); str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str); break; } return 0; }
定义好网络世界和网络世界响应函数后我们来进行套接字的创建和和端口绑定,以及网络事件注册,这个功能我们封装在 InitSocket 并且在对话框初始化时候我们就打算调用它.
/* 在 ChatDlg.h 中 ******************************************************/ //首先我们为 CChatDlg 类添加一个套接字成员变量,用于网络通信 SOCKET m_socket; //然后在 CChatDlg 类中添加函数原型 BOOL InitSocket(); /* 在 ChatDlg.cppp 中 ***************************************************/ //定义 InitSocket 函数 BOOL CChatDlg::InitSocket() { //套接字创建 m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0); if(INVALID_SOCKET==m_socket) { MessageBox("创建套接字失败!"); return FALSE; } //服务器端的端口绑定 SOCKADDR_IN addrSock; addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSock.sin_family=AF_INET; addrSock.sin_port=htons(6000); if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR))) { MessageBox("绑定失败!"); return FALSE; } //注册网络事件 if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ)) { MessageBox("注册网络读取事件失败!"); return FALSE; } return TRUE; }
在定义发送按钮消息事件让其能发送对应消息
void CChatDlg::OnBtnSend() { // TODO: Add your control notification handler code here DWORD dwIP; CString strSend; WSABUF wsabuf; DWORD dwSend; int len; CString strHostName; SOCKADDR_IN addrTo; HOSTENT* pHost; //客户端 //获取服务器端 IP 地址 ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); addrTo.sin_addr.S_un.S_addr=htonl(dwIP); //绑定端口和设置IP协议 addrTo.sin_family=AF_INET; addrTo.sin_port=htons(6000); //获得发送文本 GetDlgItemText(IDC_EDIT_SEND,strSend); len=strSend.GetLength(); wsabuf.buf=strSend.GetBuffer(len); wsabuf.len=len+1; SetDlgItemText(IDC_EDIT_SEND,""); //发送数据 if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0, (SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL)) { MessageBox("发送数据失败!"); return; } }
运行结果
相关函数:
代码示例:
#include <Winsock2.h> #include <iostream> #include <string> #pragma comment(lib,"ws2_32.lib") using namespace std; void main() { //加载套接字库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//该函数的功能是加载一个Winsocket库版本 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //解析域名获得 IP 地址 hostent* pHostent = gethostbyname("www.baidu.com"); sockaddr_in sa; ZeroMemory(&sa, sizeof(sa)); //获得 IP 地址 memcpy(&sa.sin_addr.s_addr,pHostent->h_addr_list[0],pHostent->h_length); //将 ID 地址转为字符串形式,输出 IP 地址 string strTemp = inet_ntoa(sa.sin_addr); cout<<strTemp<<endl; //结束套接字库的调用 WSACleanup(); system("pause"); }
运行结果:
在控制台中 ping www.baidu.com 的运行结果: